[TT-17356] Join the MCP agent's trace from params._meta and propagate upstream#8276
Conversation
🎯 Recommended Merge TargetsBased on JIRA ticket TT-17356: MCP trace-context bridge, join the agent's trace via params._meta (read/write) Fix Version: Tyk 5.13.1Required:
Fix Version: Tyk 5.14.0
Required:
📋 Workflow
|
|
This PR introduces end-to-end distributed tracing for MCP (Model-as-a-Coprocessor) APIs. It resolves an issue where Tyk would start a new, disconnected trace for MCP requests because MCP-native agents send the W3C trace context in the JSON-RPC body ( This change allows Tyk to read the trace context from configurable sources (defaulting to the HTTP header, then the request body), join the agent's existing trace, and propagate the context upstream to the MCP server. This ensures that gateway spans, access logs, and analytics are correctly correlated with the entire request journey. Files Changed AnalysisThe changes are well-structured across 14 files, with a significant portion of the ~1100 new lines dedicated to comprehensive testing.
Architecture & Impact Assessment
Request Flow VisualizationsequenceDiagram
participant Agent
participant Tyk Gateway
participant Upstream MCP Server
Agent->>+Tyk Gateway: POST /mcp (traceparent in JSON body)
Tyk Gateway->>Tyk Gateway: JSONRPCMiddleware: Reads body, finds traceparent in params._meta
Tyk Gateway->>Tyk Gateway: otel.JoinMCPTraceContext(): Installs agent's trace context into request
Tyk Gateway->>Tyk Gateway: otelmcp.WriteMetaTraceContext(): Injects current trace context into outbound body
Tyk Gateway->>+Upstream MCP Server: POST / (traceparent in JSON body)
Upstream MCP Server-->>-Tyk Gateway: Response
Tyk Gateway-->>-Agent: Response
Scope Discovery & Context Expansion
Metadata
Powered by Visor from Probelabs Last updated: 2026-06-09T09:51:18.550Z | Triggered by: pr_updated | Commit: 8184f6f 💡 TIP: You can chat with Visor using |
✅ Security Check PassedNo security issues found – changes LGTM. ✅ Architecture Check PassedNo architecture issues found – changes LGTM. ✅ Security Check PassedNo security issues found – changes LGTM. \n\n✅ Architecture Check PassedNo architecture issues found – changes LGTM. \n\nPerformance Issues (1)
✅ Quality Check PassedNo quality issues found – changes LGTM. Powered by Visor from Probelabs Last updated: 2026-06-09T09:51:09.497Z | Triggered by: pr_updated | Commit: 8184f6f 💡 TIP: You can chat with Visor using |
…es/tyk into TT-17356-mcp-trace-context
tbuchaillot
left a comment
There was a problem hiding this comment.
Please have a look at the config comment and add some tracing test case for this
| // MCPTraceContext configures where Tyk reads an MCP request's W3C trace | ||
| // context from (ordered, first-match-wins). Omitted ⇒ the canonical | ||
| // [{header}, {body, path: params._meta}] default. | ||
| MCPTraceContext MCPTraceContextConfig `json:"mcp_trace_context"` |
There was a problem hiding this comment.
This should be part of traceConfig structure. In 5.13 we introduced this division in configuration for metrics and traces so new tracing related config configs should live inside opentelemetry.traces instead of root level opentelemetry
| @@ -0,0 +1,183 @@ | |||
| package mcp | |||
There was a problem hiding this comment.
nitpick - shouldn't this live in otel package or otel/mcp since it's purely related to opentelemetry?
| // extractTraceContext returns ctx with tc installed as the active (remote) span | ||
| // context via the W3C propagator — the same propagator Tyk uses for inbound | ||
| // header extraction, so the joined trace is byte-identical to a header-carried one. | ||
| func extractTraceContext(ctx context.Context, tc mcp.TraceContext) context.Context { |
There was a problem hiding this comment.
I'm wondering if this functions shouldn't be part of https://github.com/TykTechnologies/opentelemetry/tree/main/trace package so we avoid importing/using go.opentelemetry.io/otel directly here
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
🚨 Jira Linter FailedCommit: The Jira linter failed to validate your PR. Please check the error details below: 🔍 Click to view error detailsNext Steps
This comment will be automatically deleted once the linter passes. |
|



MCP-native agents carry the W3C trace context inside the JSON-RPC body (params._meta, SEP-414), not the traceparent header. Tyk only read the header, so for those requests it started a fresh, disconnected trace — its spans, access logs, and analytics couldn't be correlated to the agent's journey.
This makes Tyk a first-class participant in an MCP request's trace:
Read/join the trace context from configurable sources; when the header carried none, install it so every span/log/audit later in the request inherits the agent's trace_id. Reconcile (never fork) when both channels are present.

Write the current trace context into the outbound body so the MCP server joins too — the body-channel parallel of the traceparent header Tyk already injects for ordinary upstreams. Runs automatically when tracing is on (no per-API flag).
Span labels: mcp.method.name, mcp.{tool,resource,prompt}.name (keyed by primitive type), mcp.trace_source.
Config: opentelemetry.mcp_trace_context.read_sources (ordered, first-match-wins; default [{header}, {body, params._meta}]). Applies to all MCP primitive types; no-op when tracing is off or the body is non-MCP/malformed. Covered by unit tests (internal/mcp, internal/otel) and gateway integration tests.
Description
Related Issue
Motivation and Context
How This Has Been Tested
Screenshots (if appropriate)
Types of changes
Checklist
Ticket Details
TT-17356
Generated at: 2026-06-04 12:35:36