You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
For the TypeScript SDK, I would start with instrumentation hooks rather than a vendor opinion.
Accept a tracer/meter provider or a small lifecycle subscriber, then emit boundaries for client request, server request, tools/call, resources/read, prompts, and notifications. Each event/span needs session id, request id, method, tool/resource name when present, and trace context from MCP metadata.
That gives OpenTelemetry users first-class spans, while users with their own audit layer can consume the same lifecycle without pulling an exporter into the SDK core.
I needed this for a tool server that sends blockchain transactions (its spans should be children of the agent's tool call span), so I tested trace context over _meta with stdio on 1.32.1 and 2.3.1. In case it helps whoever picks this up:
Inject on the client and extract on the server is all it takes. With v2: propagation.inject(context.active(), meta) into each callTool's _meta, and in the handler context.with(propagation.extract(context.active(), ctx.mcpReq._meta ?? {}), fn). With that, the server's spans join the agent's trace; without it, they start their own.
Two stdio details that cost me spans: StdioClientTransport passes only getDefaultEnvironment() plus env to the server, so OTEL_* settings have to go into env explicitly; and close() waits 2 s before SIGTERM, so the server has to flush its exporter when stdin ends or the last spans are lost.
Activity
Fix OTel context propagation: parent tool spans to HTTP root span
Necmttn commentedon Jun 21, 2026
For the TypeScript SDK, I would start with instrumentation hooks rather than a vendor opinion.
Accept a tracer/meter provider or a small lifecycle subscriber, then emit boundaries for client request, server request, tools/call, resources/read, prompts, and notifications. Each event/span needs session id, request id, method, tool/resource name when present, and trace context from MCP metadata.
That gives OpenTelemetry users first-class spans, while users with their own audit layer can consume the same lifecycle without pulling an exporter into the SDK core.
Generated with ax.
selimaytac commentedon Oct 18, 2026
I needed this for a tool server that sends blockchain transactions (its spans should be children of the agent's tool call span), so I tested trace context over
_metawith stdio on 1.32.1 and 2.3.1. In case it helps whoever picks this up:propagation.inject(context.active(), meta)into eachcallTool's_meta, and in the handlercontext.with(propagation.extract(context.active(), ctx.mcpReq._meta ?? {}), fn). With that, the server's spans join the agent's trace; without it, they start their own.StdioClientTransportpasses onlygetDefaultEnvironment()plusenvto the server, soOTEL_*settings have to go intoenvexplicitly; andclose()waits 2 s before SIGTERM, so the server has to flush its exporter when stdin ends or the last spans are lost.The test that runs this end to end (agent and stdio server as separate processes, with and without propagation): https://github.com/selimaytac/hashspan/blob/9da1b25/integrations/test/mcp.int.test.ts
feat(otel): add @modelcontextprotocol/otel on top of the instrumentat…
feat: built-in OpenTelemetry, no option and no separate package