Repository navigation
[FEATURE]: propagate W3C trace context (traceparent/baggage) in MCP tools/call _meta per SEP-414 #46856
Description
Feature hasn't been suggested before.
- I have verified this feature I'm about to request hasn't been suggested before. Related but different: [FEATURE]: Pass the active session ID to MCP tool calls via _meta #45997 / feat(core): pass session context to MCP tools #46008 added
_meta.sessionID(thanks, this is great); [FEATURE]: propagate W3C trace context on outbound MCP HTTP/SSE requests #28295 asked fortraceparentas an HTTP header on remote MCP transports and was closed for inactivity. This request is aboutparams._metaontools/call, which is the only channel a stdio MCP server has, and follows the now-final MCP spec (SEP-414).
Describe the enhancement you want to request
What: when OpenCode invokes an MCP tool, include the W3C trace context of the active tool-call span in CallToolRequest.params._meta, using the keys the MCP spec reserves for this in SEP-414: traceparent, optionally tracestate, and baggage (unprefixed, by spec exception to the _meta prefix rule). For example:
{
"method": "tools/call",
"params": {
"name": "engram_search",
"arguments": { "...": "..." },
"_meta": {
"sessionID": "ses_…",
"traceparent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
"baggage": "session.id=ses_…,opencode.tool.call_id=call_…"
}
}
}_meta.sessionID from #46008 can stay as is; baggage just carries the same value under the spec-conventional key so servers built against the OTel GenAI MCP semantic conventions pick it up without OpenCode-specific code.
Why: OpenCode already opens an OpenTelemetry span per tool call (session/tools.ts has session.id and tool.call_id in scope at the call site; with experimental.openTelemetry those spans export). An MCP server that traces its own work today has no way to parent its spans onto that span, so the client-side and server-side halves of one tool call land in the backend as two unrelated traces. With traceparent in _meta the server span becomes a child of OpenCode's, and a trace view shows: model turn → tool call → what the server actually did (retrieval stages, cache hits, lock waits) in one waterfall. The OTel GenAI MCP semantic conventions (Development) say clients SHOULD inject propagators into params._meta and servers SHOULD use it as the parent; the Rust SDK (rmcp ≥ 3.1) already exposes RequestMetaObject::get_traceparent/get_baggage for exactly this.
Where: the same place #46008 adds _meta.sessionID (packages/core/src/mcp/client.ts), reading the current span context from the OTel API (propagation.inject into a carrier and copying the three keys) when tracing is enabled; when it is not, traceparent can simply be omitted.
Workaround today: a plugin's tool.execute.before hook can inject a reserved argument (we use args._otel = { traceparent, baggage }) and the server lifts it into _meta. It works, but it couples the server to an OpenCode-specific argument and leaks into the stored tool input; native _meta propagation makes that unnecessary.
Activity