Skip to content

feat: add OpenTelemetry tracing#26

Open
mattpodwysocki wants to merge 3 commits intomainfrom
feat/otel-tracing
Open

feat: add OpenTelemetry tracing#26
mattpodwysocki wants to merge 3 commits intomainfrom
feat/otel-tracing

Conversation

@mattpodwysocki
Copy link
Copy Markdown
Contributor

Summary

Adds OpenTelemetry tracing to mcp-docs-server, consistent with the implementation in mcp-server and mcp-devkit-server.

  • src/utils/tracing.ts (new) — initializeTracing(), shutdownTracing(), getTracer(), and withToolSpan(). Suppresses OTEL diagnostic output at module load time to protect MCP stdio.
  • BaseTool.run() — wraps every tool execution in a tool.<name> span via withToolSpan(); sets tool.error=true attribute when a tool returns isError: true.
  • src/index.ts — calls initializeTracing() on startup, shutdownTracing() on graceful exit.
  • src/utils/index.ts — exports tracing utilities from @mapbox/mcp-docs-server/utils.

Tracing is a no-op by default. It activates only when OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_CONSOLE_ENABLED=true is set. Uses OTEL 2.x (resourceFromAttributes instead of the removed Resource class).

Test plan

  • npm run build passes
  • npm test — 58 tests pass (tracing is no-op in test env via VITEST guard)
  • CI green

🤖 Generated with Claude Code

mattpodwysocki and others added 3 commits April 1, 2026 14:16
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add src/utils/tracing.ts with initializeTracing(), shutdownTracing(),
  getTracer(), and withToolSpan() — consistent with mcp-server and mcp-devkit-server
- BaseTool.run() wraps every execution in a tool.<name> span via withToolSpan();
  sets tool.error=true attribute on tool-level errors
- index.ts initializes tracing on startup and shuts it down on graceful exit
- OTEL is a no-op unless OTEL_EXPORTER_OTLP_ENDPOINT or
  OTEL_EXPORTER_CONSOLE_ENABLED=true is set; diagnostics suppressed on stdio
- Export tracing utilities from @mapbox/mcp-docs-server/utils barrel
- Add OTEL 2.x dependencies: api@^1.9.1, resources@^2.6.1,
  sdk-trace-base@^2.6.1, sdk-node@^0.214.0, instrumentation@^0.214.0,
  exporter-trace-otlp-http@^0.214.0, auto-instrumentations-node@^0.72.0,
  semantic-conventions@^1.40.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mattpodwysocki mattpodwysocki requested a review from a team as a code owner April 14, 2026 03:02
Copy link
Copy Markdown
Member

@zmofei zmofei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Clean implementation, consistent with sibling repos. One minor issue:

src/tools/BaseTool.ts — missing tool.error attribute in catch block

The try path sets span.setAttribute('tool.error', true) when result.isError, but the catch path (which also returns isError: true) doesn't set it. Since the inner catch returns rather than re-throws, withToolSpan sees a successful completion and marks the span SpanStatusCode.OK.

Validation failures and unexpected exceptions will produce spans that look successful — no tool.error attribute, status OK.

Suggested fix:

} catch (error) {
  span.setAttribute('tool.error', true);
  return {
    isError: true,
    content: [{ type: 'text', text: (error as Error).message }]
  };
}

Not blocking — can be a follow-up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants