MCP Telemetry and Distributed Tracing
Instrumenting Model Context Protocol servers with OpenTelemetry: Distributed context propagation, W3C traceparent headers, latency profiling, and Prometheus SLOs.
Generate & Validate Multi-Client MCP Config
One-click export with environment variables & path locators for Claude Desktop, Cursor, Windsurf, and OpenAI Codex CLI.
MCP Telemetry and Distributed Tracing
In complex multi-agent architectures, an agent prompt often triggers a cascading chain of tool executions across multiple remote Model Context Protocol (MCP) servers before generating a final response. When an agent invocation stalls for 18 seconds or produces a corrupted output, diagnosing where the bottleneck occurred—in the language model inference phase, network transport latency, database query execution, or an unhandled JSON-RPC error—becomes virtually impossible without end-to-end distributed tracing.
Because the Model Context Protocol communicates over JSON-RPC 2.0 (via standard input and output stdio, Server-Sent Events SSE, or Streamable HTTP), standard HTTP-only Application Performance Monitoring (APM) agents fail to capture internal tool lifecycles, schema parsing overhead, and parameter serialization costs.
Full-fidelity observability requires embedding OpenTelemetry (OTel) instrumentation directly into the MCP transport loop, injecting W3C trace contexts through JSON-RPC metadata envelopes, and exporting tool latencies to Prometheus and Jaeger collectors.
1. End-to-End Tracing Architecture
A complete MCP trace spans the client orchestration framework (such as Claude Desktop, Cursor, or OpenAI Codex CLI), traverses an API Gateway or Ingress, enters the target MCP Server, and terminates at backend dependencies (PostgreSQL, Pinecone, Redis).
Critical Trace Spans in MCP
- ▸
mcp.client.request: Captures the duration from the host deciding to invoke a tool until the response is parsed back into model context. - ▸
mcp.gateway.route: Measures authentication validation, rate limit verification, and connection pool routing. - ▸
mcp.server.tool_execute: Measures the exact execution time of the tool underlying handler function. - ▸
mcp.server.serialize: Captures the CPU overhead of converting large dataset results into token-dense markdown or JSON strings.
2. Environment Matrix and Dependencies
Before deploying OpenTelemetry instrumentation across your MCP fleet, verify that your runtime satisfies the following component requirements:
| Component | Minimum Version | Purpose |
|---|---|---|
| Node.js | >= 20.0.0 | Runtime environment for TypeScript MCP and OTel SDKs |
| @opentelemetry/sdk-node | >= 0.52.0 | Core OpenTelemetry instrumentation supervisor |
| @opentelemetry/exporter-trace-otlp-grpc | >= 0.52.0 | High-throughput gRPC trace exporter to OpenTelemetry Collector |
| @modelcontextprotocol/sdk | >= 1.2.0 | Official Model Context Protocol TypeScript framework |
| prom-client | >= 15.1.0 | Prometheus metric exporter for tool invocation counters and gauges |
Export the standard OpenTelemetry environment variables in your deployment environment:
export OTEL_SERVICE_NAME="mcp-production-server"
export OTEL_EXPORTER_OTLP_ENDPOINT="https://otel-collector.internal:4317"
export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
export OTEL_TRACES_SAMPLER="parentbased_traceidratio"
export OTEL_TRACES_SAMPLER_ARG="0.25"3. Multi-Host Configuration Snippets
Developers and site reliability engineers need to run instrumented MCP servers across local IDE hosts and desktop tools. The following configurations pass OpenTelemetry collector endpoints directly into the child process environment.
Claude Desktop Configuration
Configure your server in claude_desktop_config.json:
{
"mcpServers": {
"telemetry-db-server": {
"command": "node",
"args": ["/opt/mcp-servers/telemetry/dist/index.js"],
"env": {
"OTEL_SERVICE_NAME": "mcp-desktop-service",
"OTEL_EXPORTER_OTLP_ENDPOINT": "",
"DATABASE_URL": "postgresql://app:secret@/analytics"
}
}
}
}Cursor IDE Configuration
Place this configuration inside .cursor/mcp.json:
{
"mcpServers": {
"telemetry-db-server": {
"command": "node",
"args": ["./dist/index.js"],
"env": {
"OTEL_SERVICE_NAME": "cursor-mcp-service",
"OTEL_EXPORTER_OTLP_ENDPOINT": ""
}
}
}
}OpenAI Codex CLI Configuration
In ~/.codex/config.toml, configure the telemetry-enabled server:
[mcp_servers.telemetry_db_server]
command = "node"
args = ["/opt/mcp-servers/telemetry/dist/index.js"]
[mcp_servers.telemetry_db_server.env]
OTEL_SERVICE_NAME = "codex-mcp-service"
OTEL_EXPORTER_OTLP_ENDPOINT = ""4. W3C Trace Context Propagation over JSON-RPC 2.0
Standard HTTP headers (traceparent, tracestate) do not persist when MCP servers operate over standard input and output (stdio) or multiplexed SSE streams.
To maintain unbroken distributed traces across any transport, inject W3C trace contexts into the JSON-RPC _meta parameter object:
Outgoing tools/call with W3C Context Injection
{
"jsonrpc": "2.0",
"id": "trace-job-7712",
"method": "tools/call",
"params": {
"name": "enterprise_db_query",
"arguments": {
"sql": "SELECT account_id, billing_tier FROM accounts WHERE status = 'active' LIMIT 10;"
},
"_meta": {
"traceparent": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
"tracestate": "rojo=1,congo=2",
"tenant_id": "org_enterprise_99",
"agent_model": "claude-3-7-sonnet"
}
}
}Result Payload with Child Span Propagation
The MCP server extracts the parent context, binds downstream database and API spans as children of 00f067aa0ba902b7, and returns execution metrics in the response metadata:
{
"jsonrpc": "2.0",
"id": "trace-job-7712",
"result": {
"content": [
{
"type": "text",
"text": "[{\"account_id\": \"acc_01\", \"billing_tier\": \"enterprise\"}]"
}
],
"_meta": {
"execution_time_ms": 38.4,
"span_id": "9a38f72c0199e4b1",
"estimated_tokens": 42
}
}
}5. Production OpenTelemetry Instrumentation (TypeScript)
Below is an OpenTelemetry SDK integration for an MCP server. It intercepts JSON-RPC calls, parses _meta.traceparent, instruments tool execution, and exports traces via OTLP/gRPC to Jaeger, Grafana Tempo, or Datadog:
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
import {
trace,
context,
propagation,
SpanStatusCode,
ROOT_CONTEXT
} from '@opentelemetry/api';
const exporter = new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || ''
});
const sdk = new NodeSDK({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: process.env.OTEL_SERVICE_NAME || 'mcp-database-service',
[SemanticResourceAttributes.SERVICE_VERSION]: '1.2.0',
[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV || 'production'
}),
traceExporter: exporter
});
sdk.start();
const tracer = trace.getTracer('mcp-instrumentation', '1.0.0');
export async function executeMonitoredTool(
toolName: string,
args: Record<string, any>,
meta: Record<string, any> = {},
handler: (args: any) => Promise<any>
): Promise<any> {
let parentContext = ROOT_CONTEXT;
if (meta?.traceparent) {
parentContext = propagation.extract(ROOT_CONTEXT, {
traceparent: meta.traceparent,
tracestate: meta.tracestate
});
}
return context.with(parentContext, async () => {
const span = tracer.startSpan(`mcp.tool_call:${toolName}`, {
attributes: {
'mcp.tool.name': toolName,
'mcp.tenant.id': meta?.tenant_id || 'anonymous',
'mcp.agent.model': meta?.agent_model || 'unknown',
'rpc.system': 'mcp-jsonrpc'
}
});
const startTime = performance.now();
try {
const result = await handler(args);
const duration = performance.now() - startTime;
span.setAttribute('mcp.execution_duration_ms', duration);
span.setStatus({ code: SpanStatusCode.OK });
return {
result,
meta: {
traceparent: span.spanContext().traceId,
execution_time_ms: duration
}
};
} catch (error: any) {
span.recordException(error);
span.setStatus({
code: SpanStatusCode.ERROR,
message: error.message || 'Tool execution failure'
});
throw error;
} finally {
span.end();
}
});
}6. Key Performance Indicators and Prometheus Metrics
Enterprise SRE teams must track four critical Service Level Indicators (SLIs) across all MCP clusters:
| Metric Name | Type | Description | Alert Threshold |
|---|---|---|---|
mcp_tool_execution_duration_seconds | Histogram | Latency distribution of tool execution | p99 > 3.0s |
mcp_tool_invocation_total | Counter | Total invocations segmented by tool and status | 5xx error rate > 1% |
mcp_response_token_size_bytes | Histogram | Payload size returned back to LLM context | Max > 64KB |
mcp_active_sse_connections | Gauge | Concurrent persistent client agent streams | Capacity > 85% |
Prometheus Alerting Rules (mcp-alerts.yaml)
groups:
- name: MCP_Observability_Alerts
rules:
- alert: MCPToolHighLatencyP99
expr: histogram_quantile(0.99, sum(rate(mcp_tool_execution_duration_seconds_bucket[5m])) by (le, tool_name)) > 3.0
for: 2m
labels:
severity: warning
team: ai-platform
annotations:
summary: "MCP tool {{ $labels.tool_name }} p99 latency exceeds 3 seconds"
description: "High tool latency directly blocks host LLM agent generation and exhausts connection pools."
- alert: MCPHighToolFailureRate
expr: (sum(rate(mcp_tool_invocation_total{status="error"}[5m])) / sum(rate(mcp_tool_invocation_total[5m]))) * 100 > 2.0
for: 1m
labels:
severity: critical
team: ai-platform
annotations:
summary: "MCP tool execution error rate > 2% across cluster"
description: "Agents encountering repeated tool failures risk hallucination cascades and runaway retries."7. Common Errors and Production Troubleshooting
When deploying telemetry across high-throughput MCP clusters, watch out for the following issues:
Error: Context Severing Across Asynchronous Spans
- ▸Symptom: Child spans for database queries or API fetches appear as independent root traces in Jaeger or Grafana Tempo instead of children of the MCP tool span.
- ▸Root Cause: Node.js
async/awaitcontext loss when libraries do not propagateAsyncLocalStorageor when handlers execute across uninstrumented event emitters. - ▸Resolution: Always wrap asynchronous handler calls inside
context.with(parentContext, ...)as demonstrated in the middleware implementation above.
Error: Collector Connection Refused (ECONNREFUSED )
- ▸Symptom: Server startup blocks or throws uncaught background promise rejections attempting to reach OTLP collectors.
- ▸Root Cause: The local OpenTelemetry collector agent is not running, or network policies block egress to port 4317 (gRPC) or 4318 (HTTP).
- ▸Resolution: Configure fallback exporters or add a timeout wrapper. If running in development without a local collector, disable trace exporting by setting
OTEL_SDK_DISABLED=true.
Terminal and Host Fixes
- ▸macOS / Linux: Ensure your local OpenTelemetry Collector Docker container shares the host network or is reachable via
host.docker.internal:4317. - ▸Windows: When defining endpoints in PowerShell, ensure environment variable strings do not omit protocol prefixes (
).
8. External Citations and Security Guardrails
Before onboarding enterprise production tools, verify security compliance and consult official specifications:
- ▸PII and Secret Redaction: Never write raw authentication bearer tokens or database passwords to OTel span attributes. Use OpenTelemetry attribute processors to redact fields matching regex patterns for API keys and authorization headers.
- ▸Official Standards and Repositories:
MCP Developer Newsletter (In Planning)
We are preparing an occasional technical dispatch covering new servers, benchmarks, and protocol updates. Sign up early to receive issues when we launch.
Zero marketing spam. 1-click unsubscribe anytime.
Build your full agent toolstack in the Visual Generator
Combine verified MCP servers with databases, search APIs, and memory graphs in a single configuration file.
Did this setup guide work with your AI host?
Help test this configuration across Claude, Cursor, and Codex CLI. Be the first to report:
Written by Rad Tome
Lead AI Systems Architect & Maintainer, MCP Codex
Specializing in Model Context Protocol (MCP) integrations, autonomous AI agent orchestration, and distributed developer toolchains. Researches and benchmarks production MCP client-server architectures across OpenAI Codex, Claude, and Cursor.
Related Guides
The MCP Security Checklist: 50 Vulnerabilities to Audit Before Shipping
Comprehensive security audit checklist for MCP servers. 50 specific vulnerabilities across injection, authentication, authorization, transport, supply chain, and operational security. Includes exploitation examples, detection methods, and remediation code.
EnterpriseBenchmarking MCP: Latency, Transport Overheads & Cost Model
Empirical latency baselines comparing MCP stdio vs SSE transports, cold start overheads, memory footprints, and AWS cost modeling with runnable test scripts.
EnterpriseMCP Server Monetization: Production Models
Architect paid MCP servers using Stripe Billing, token metering, and HTTP 402 machine payments. Covers real auth flows, mppx code, and unit economics.