opentel-mcp 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +23 -5
  2. package/package.json +4 -6
  3. package/src/config.js +35 -4
package/README.md CHANGED
@@ -5,9 +5,23 @@
5
5
  > long they take, and which ones fail — via standard OTel traces.
6
6
 
7
7
  [![CI](https://github.com/Thirumalaiboobathi/opentel-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/Thirumalaiboobathi/opentel-mcp/actions/workflows/ci.yml)
8
+ [![npm version](https://img.shields.io/npm/v/opentel-mcp.svg)](https://www.npmjs.com/package/opentel-mcp)
8
9
  [![license](https://img.shields.io/npm/l/opentel-mcp.svg)](https://github.com/Thirumalaiboobathi/opentel-mcp/blob/main/LICENSE)
9
10
 
10
- **Status: pre-release. Not yet published to npm.**
11
+ ## Status
12
+
13
+ `0.x` — the [MCP semantic conventions](https://github.com/open-telemetry/semantic-conventions-genai)
14
+ this library implements are Development-stage and may change. Breaking
15
+ attribute changes will land in minor versions until `1.0`.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install opentel-mcp @opentelemetry/api
21
+ ```
22
+
23
+ `opentel-mcp` is an ES module. Your project needs `"type": "module"` in
24
+ its package.json, or you must use `.mjs` file extensions.
11
25
 
12
26
  ## Why
13
27
 
@@ -31,7 +45,7 @@ const server = new Server({ name: 'my-server', version: '1.0.0' }, {
31
45
  });
32
46
 
33
47
  instrumentMcpServer(server, {
34
- serviceName: 'my-mcp-server',
48
+ serviceName: 'my-mcp-server', // required because setupNodeSdk is true below
35
49
  setupNodeSdk: true, // dev-friendly stderr output; omit in prod
36
50
  // if you already have OTel configured
37
51
  });
@@ -49,7 +63,7 @@ import { instrumentMcpServer } from 'opentel-mcp';
49
63
  const server = new McpServer({ name: 'my-server', version: '1.0.0' });
50
64
 
51
65
  instrumentMcpServer(server, {
52
- serviceName: 'my-mcp-server',
66
+ serviceName: 'my-mcp-server', // required because setupNodeSdk is true below
53
67
  setupNodeSdk: true,
54
68
  });
55
69
 
@@ -101,12 +115,16 @@ expresses success/failure through span status, not a status attribute.
101
115
  **One-line (dev):** `setupNodeSdk: true` sets up a NodeTracerProvider
102
116
  that prints spans to stderr (safe alongside stdio-transport MCP servers —
103
117
  see ADR 003), optionally + an OTLP exporter if `exporterUrl` is provided.
104
- No separate OTel SDK setup needed — `serviceName` is still required.
118
+ No separate OTel SDK setup needed — `serviceName` is required in this
119
+ mode, since it names the resource of the provider opentel-mcp creates.
105
120
 
106
121
  **Bring-your-own-SDK (prod):** Omit `setupNodeSdk` (default false).
107
122
  opentel-mcp uses whatever tracer provider you've already registered
108
123
  via `trace.setGlobalTracerProvider()`. This means it plugs into any
109
- existing OTel setup without conflict.
124
+ existing OTel setup without conflict. In this mode the host's
125
+ TracerProvider owns the resource, so `serviceName` is not needed and has
126
+ no effect — set `service.name` on the host's Resource instead. Passing
127
+ `serviceName` anyway is harmless but logs a one-time `diag.warn`.
110
128
 
111
129
  ## Ordering constraint
112
130
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opentel-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "One-line OpenTelemetry instrumentation for Model Context Protocol (MCP) servers",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -15,13 +15,11 @@
15
15
  "engines": {
16
16
  "node": ">=20"
17
17
  },
18
- "workspaces": [
19
- "examples/hello-server",
20
- "examples/hello-mcpserver"
21
- ],
22
18
  "scripts": {
23
19
  "test": "vitest run",
24
- "test:watch": "vitest"
20
+ "test:watch": "vitest",
21
+ "prepack": "node scripts/strip-workspaces.js",
22
+ "postpack": "node scripts/restore-workspaces.js"
25
23
  },
26
24
  "keywords": [
27
25
  "mcp",
package/src/config.js CHANGED
@@ -3,9 +3,15 @@
3
3
  * Options parsing and defaults for instrumentMcpServer().
4
4
  */
5
5
 
6
+ import { diag } from '@opentelemetry/api';
7
+
6
8
  /**
7
9
  * @typedef {object} InstrumentOptions
8
- * @property {string} serviceName - Required. Identifies this server in emitted telemetry.
10
+ * @property {string} [serviceName] - Names the resource of the NodeTracerProvider this library creates.
11
+ * Required (and must be a non-empty string) when `setupNodeSdk` is true. Has no effect when `setupNodeSdk`
12
+ * is false or omitted — in that mode, resource attributes (including `service.name`) come from whatever
13
+ * TracerProvider the host application has already registered; passing `serviceName` anyway is harmless but
14
+ * logs a one-time `diag.warn`.
9
15
  * @property {string} [exporterUrl] - OTLP/HTTP traces endpoint (e.g. 'http://localhost:4318/v1/traces').
10
16
  * Only takes effect when `setupNodeSdk` is true.
11
17
  * @property {boolean} [enabled=true] - Set to false to disable instrumentation entirely; instrumentMcpServer()
@@ -18,6 +24,17 @@
18
24
  * instrumentMcpServer() from ever overriding a host application's own OpenTelemetry setup.
19
25
  */
20
26
 
27
+ // Guards the "serviceName has no effect" diagnostic below so it fires once
28
+ // per process rather than once per instrumented server.
29
+ let warnedServiceNameIgnored = false;
30
+
31
+ // Test-only: lets test/instrument.test.js get a clean slate for the
32
+ // once-per-process warning above regardless of what earlier tests in the
33
+ // same file already triggered. Not part of the public API.
34
+ export function __resetServiceNameWarnedForTests() {
35
+ warnedServiceNameIgnored = false;
36
+ }
37
+
21
38
  /**
22
39
  * Validates and applies defaults to raw instrumentMcpServer() options.
23
40
  *
@@ -26,15 +43,29 @@
26
43
  */
27
44
  export function resolveOptions(options) {
28
45
  const opts = options ?? {};
46
+ const setupNodeSdk = opts.setupNodeSdk ?? false;
47
+ const hasServiceName = typeof opts.serviceName === 'string' && opts.serviceName.trim() !== '';
48
+
49
+ if (setupNodeSdk && !hasServiceName) {
50
+ throw new Error(
51
+ 'opentel-mcp: options.serviceName is required when setupNodeSdk is true ' +
52
+ '(it names the resource of the tracer provider this library creates). ' +
53
+ "It is not needed otherwise — the host application's registered provider owns the resource.",
54
+ );
55
+ }
29
56
 
30
- if (typeof opts.serviceName !== 'string' || opts.serviceName.trim() === '') {
31
- throw new Error('opentel-mcp: options.serviceName is required and must be a non-empty string.');
57
+ if (!setupNodeSdk && hasServiceName && !warnedServiceNameIgnored) {
58
+ warnedServiceNameIgnored = true;
59
+ diag.warn(
60
+ 'opentel-mcp: serviceName was provided but setupNodeSdk is false, so it has no effect. ' +
61
+ 'Resource attributes (including service.name) come from the TracerProvider the host application registered.',
62
+ );
32
63
  }
33
64
 
34
65
  return {
35
66
  serviceName: opts.serviceName,
36
67
  exporterUrl: opts.exporterUrl,
37
68
  enabled: opts.enabled ?? true,
38
- setupNodeSdk: opts.setupNodeSdk ?? false,
69
+ setupNodeSdk,
39
70
  };
40
71
  }