[FEATURE] Inject W3C traceparent on outbound MCP HTTP/SSE requests

Resolved 💬 3 comments Opened Apr 27, 2026 by bryanhong Closed May 30, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

With OTel tracing enabled (CLAUDE_CODE_ENABLE_TELEMETRY=1,
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1, OTLP traces exporter configured),
Claude Code's MCP HTTP/SSE client does not inject W3C traceparent
headers on outbound requests to remote MCP servers. Spans emitted by
the MCP server therefore cannot be stitched into the Claude Code trace
tree — observability stops at the MCP boundary.

I run a self-hosted MCP server in k8s with inbound ASGI auto-instrumentation
plus outbound httpx instrumentation to a third-party API. Both ends
export to my collector, but I can't get one connected trace per tool
call — only two disconnected trees correlated by timestamp. End-to-end
latency attribution ("this tool call took 12s — where did the time go?")
is not possible without traceparent propagation.

I confirmed the gap by adding a debug ASGI middleware that logs the
traceparent header on every inbound request: every MCP call from Claude
Code shows traceparent=<absent>.

Proposed Solution

When OTel tracing is active in Claude Code, the MCP HTTP/SSE client
should inject W3C traceparent (and tracestate) headers on every
outbound request, carrying the trace context of the current
tool-execution span. The receiving server's W3C-aware ASGI middleware
will then extract it as the parent span automatically.

This is analogous to the existing TRACEPARENT env var propagation to
Bash subprocesses (#45483), applied to the MCP HTTP transport.

A complementary in-band path exists upstream:
modelcontextprotocol/modelcontextprotocol#246 proposes carrying trace
identifiers in the MCP _meta field. Both approaches are valid; HTTP
header injection is the simpler near-term path and unblocks users
today without protocol changes.

Alternative Solutions

  • stdio-MCP shim that reads TRACEPARENT from env and injects it as an

HTTP header: doesn't work because stdio MCP servers are long-lived;
the env is captured at startup and never updates per-call. Would
link every call in the session to the same stale parent span.

  • Bash-tool indirection (curl with traceparent header): per-call

TRACEPARENT works correctly, but loses all MCP tool schemas and UX.
Not viable.

  • Patching the bundled Claude Code JS to add the header: fragile

across updates, breaks every release.

There is no clean user-side workaround; this requires a fix in Claude
Code's MCP client (or eventual upstream protocol support).

Priority

Medium - Would be very helpful

Feature Category

MCP server integration

Use Case Example

A team operates a customer-support agent built on Claude Code that
talks to several internal MCP servers (CRM, ticketing, knowledge base).
Each MCP server is independently instrumented with OTel and exports
to the team's tracing backend.

Today they see disconnected trees:

Claude Code: tool_use:mcp__crm__lookup_customer
tool_use:mcp__ticketing__create_ticket

CRM MCP: ASGI inbound /mcp
└── DB query
└── HTTPS GET /api/customers/...

Ticketing: ASGI inbound /mcp
└── HTTPS POST /tickets

When a support interaction is slow, the on-call engineer can't tell
whether time was spent in Claude's reasoning, the MCP transport, the
internal DB, or the downstream HTTP call — they have to correlate
three disjoint traces by timestamp.

With traceparent injection they would see one tree per tool call:

Claude Code: tool_use:mcp__crm__lookup_customer
└── HTTP POST /mcp (Claude Code outbound)
└── ASGI inbound /mcp (CRM MCP)
├── DB query
└── HTTPS GET /api/customers/123

That's the canonical "where did the time go?" view, and it's the
primary value of wiring OTel through an MCP-based agent stack.

Additional Context

Related issues:

  • #31039 — [FEATURE] support TRACEPARENT context propagation for

OpenTelemetry (closed, not planned; scope was inbound env, not
outbound MCP)

  • #45483 — Bash subprocess TRACEPARENT propagation (completed)
  • #53972 — subprocess does not inherit active OTel span
  • #48862 — docs gap on TRACEPARENT/TRACESTATE parent-linking
  • modelcontextprotocol/modelcontextprotocol#246 — Include OpenTelemetry

trace identifiers in the MCP protocol (upstream, in-band via _meta)

Environment:

  • Claude Code: 2.1.119
  • macOS 15 (also reproduces from Linux)
  • MCP server: FastMCP 3.2.4 (Python), HTTP transport
  • opentelemetry-instrumentation-asgi 0.62b1
  • opentelemetry-instrumentation-httpx 0.62b1
  • Collector: self-hosted, OTLP HTTP/protobuf

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗