TT-16826 OTel Metrics MCP Dimensions#7889
Conversation
|
API Changes --- prev.txt 2026-03-18 08:09:47.743226233 +0000
+++ current.txt 2026-03-18 08:09:39.873261384 +0000
@@ -8593,6 +8593,14 @@
JSONRPCRoutingState
// MCPRouting indicates the request came via MCP JSON-RPC routing
MCPRouting
+ // MCPMethod stores the JSON-RPC method name for MCP metrics dimensions.
+ MCPMethod
+ // MCPPrimitiveType stores the MCP primitive type (tool/resource/prompt) for metrics dimensions.
+ MCPPrimitiveType
+ // MCPPrimitiveName stores the MCP primitive name for metrics dimensions.
+ MCPPrimitiveName
+ // JSONRPCErrorCode stores the JSON-RPC error code for metrics dimensions.
+ JSONRPCErrorCode
)
# Package: ./dlpython
|
|
This PR introduces OpenTelemetry (OTel) metric dimensions for Multi-Cloud Protocol (MCP) traffic, enabling detailed observability into MCP-specific operations like tool calls, resource reads, and prompt invocations. Key changes include:
Files Changed AnalysisThe PR introduces 1075 lines of code across 19 files, with the bulk of the changes focused on adding the new feature and its corresponding tests.
Architecture & Impact AssessmentWhat this PR accomplishesThis PR significantly enhances the observability of Tyk's MCP proxy. It allows operators to gain deep insights into MCP traffic by creating detailed, dimensional metrics based on the specific MCP methods and primitives being invoked. This enables fine-grained monitoring, alerting, and dashboarding that was not previously possible. Key technical changes introduced
Affected system components
Component Interaction FlowsequenceDiagram
participant Client
participant TykGateway as "Tyk Gateway"
participant JSONRPCMiddleware as "JSON-RPC Middleware"
participant BaseMiddleware as "Base Middleware"
participant OTelInstruments as "OTel Instruments"
Client->>+TykGateway: POST /mcp (JSON-RPC Request)
TykGateway->>+JSONRPCMiddleware: ProcessRequest(r)
JSONRPCMiddleware->>JSONRPCMiddleware: Parse request, extract MCP data
JSONRPCMiddleware->>TykGateway: ctxSetMCPMethod(r, "tools/call")<br/>ctxSetMCPPrimitiveType(r, "tool")
Note right of JSONRPCMiddleware: Request context is now enriched
JSONRPCMiddleware-->>TykGateway: Continue middleware chain
TykGateway->>+BaseMiddleware: RecordMetrics(r)
alt if MetricInstruments.NeedsMCP() is true
BaseMiddleware->>TykGateway: Populate RequestContext with MCP data from context
BaseMiddleware->>+OTelInstruments: RecordAPIMetrics(RequestContext)
OTelInstruments->>OTelInstruments: Extract MCP dimensions from RequestContext
OTelInstruments-->>BaseMiddleware:
end
BaseMiddleware-->>TykGateway:
TykGateway-->>-Client: HTTP Response
Scope Discovery & Context ExpansionThe changes are well-contained within the gateway's request processing and metrics subsystems. The architectural pattern—enriching request context in a protocol-specific middleware for consumption by a generic downstream middleware (like metrics or logging)—is a robust and reusable pattern. This could serve as a blueprint for adding detailed observability for other protocols like GraphQL or gRPC in the future. The implementation correctly builds upon the existing custom metrics framework ( Metadata
Powered by Visor from Probelabs Last updated: 2026-03-18T08:10:34.870Z | Triggered by: pr_updated | Commit: a777121 💡 TIP: You can chat with Visor using |
Security Issues (1)
✅ Architecture Check PassedNo architecture issues found – changes LGTM. Security Issues (1)
No architecture issues found – changes LGTM. \n\nPerformance Issues (1)
Quality Issues (1)
Powered by Visor from Probelabs Last updated: 2026-03-18T08:10:30.382Z | Triggered by: pr_updated | Commit: a777121 💡 TIP: You can chat with Visor using |
🚨 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. |
|



Description
Adds MCP-specific dimensions to the OTel custom metrics system, enabling users to observe MCP proxy traffic (tool calls, resource reads,
prompt invocations) through configurable OTel metric instruments.
Tyk's MCP proxy already introspects JSON-RPC payloads at the middleware layer — this PR surfaces that data (method, primitive type, primitive
name, error code) as metric dimensions aligned with the OTel
mcp.*semanticconventions.
Context Propagation
MCPMethod,MCPPrimitiveType,MCPPrimitiveName,JSONRPCErrorCode) withctxSet/ctxGethelpers following theexisting gateway pattern
JSONRPCMiddleware.ProcessRequest()propagates MCP fields right after routing state is resolved — before access control, so rejectedrequests still carry full MCP context
writeJSONRPCError()updated to accept*http.Requestand stash the JSON-RPC error code in context. Same forwriteJSONRPCErrorResponse()in the error handler
Dimension Extractors
RequestContextand 4 metadata extractors registered:mcp_method→ JSON-RPC method name (tools/call,resources/read,initialize, etc.)mcp_primitive_type→tool,resource,prompt, or""mcp_primitive_name→ specific tool/resource/prompt namemcp_error_code→ JSON-RPC error code as string, empty when no errorNeedsMCP()flag on the registry (follows existingNeedsSession()/NeedsContext()pattern) — MCP fields only populated at the recordingsite when MCP dimensions are configured, zero overhead otherwise
New Dimensions
mcp_methodmcp.method.nametools/call,resources/read,prompts/get,initialize,ping, ...mcp_primitive_typemcp.primitive.typetool,resource,prompt,""mcp_primitive_namemcp.primitive.namemcp_error_codemcp.error.code-32700,-32600,-32601,-32602,-32603,""Additionally,
mcp.session.idis already available via existing header source ({"source": "header", "key": "Mcp-Session-Id", "label": "mcp.session.id"}) with no code changes.Configuration Example
Design Decisions
the recording site — makes data available to all downstream consumers (audit logs, traces, custom plugins), not just metrics
Related Issue
Motivation and Context
How This Has Been Tested
Unit tests
E2E Tests (
ci/tests/metrics/metrics_test.go, profile:mcp)Docker-compose stack: Go test client → Tyk Gateway →
tzolov/mcp-everything-server:v3→ OTel Collector → Prometheus8 test cases:
tools/callproducestyk_mcp_requests_total{mcp_method_name="tools/call",mcp_primitive_type="tool"}echotool call producestyk_mcp_requests_total{mcp_primitive_name="echo"}tyk_mcp_primitive_duration_seconds_count{mcp_primitive_type="tool",mcp_primitive_name="echo"}exists after toolcalls
http_server_request_duration_seconds_count{mcp_method_name="tools/call"}existsMcp-Session-Id: test-session-123header surfaces asmcp_session_id="test-session-123"labeltyk_mcp_requests_total{mcp_method_name="initialize"}with no primitive typeapi_id,mcp_method_name,mcp_primitive_type,mcp_primitive_name,response_codeScreenshots (if appropriate)
Types of changes
Checklist