Tracing MCP Tool Calls with OpenTelemetry
Instrument Model Context Protocol (MCP) tool executions and agent workflows with OpenTelemetry distributed tracing for end-to-end observability.
Published on • September 11, 2026
AI Assistant

When an autonomous agent executes a multi-step task, a single user prompt may trigger a complex sequence of model inferences, internal agent handoffs, and external MCP tool invocations. When a tool call hangs or returns an error, debugging without distributed tracing becomes nearly impossible.
By instrumenting your MCP servers and agent runtimes with OpenTelemetry (OTel), you gain end-to-end visibility into every tool call, latency breakdown, and parameter payload across your entire agent infrastructure.
Observability Architecture for MCP Tool Calls
OpenTelemetry distributed tracing propagates trace context across service boundaries using standardized W3C trace context headers:
[Agent System Trace]
|-- [LLM Generation Span]
|-- [MCP Tool Call Span: "search_database"] (W3C Trace Parent Header)
|-- [DB Query Span: SELECT * FROM users]
|-- [Data Transformation Span]
When the agent sends an MCP tool request, the active trace ID and span ID are injected into request metadata, allowing the MCP server to record child spans under the same root trace.
Instrumenting Python MCP Servers with OpenTelemetry
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
from opentelemetry.trace import Status, StatusCode
from mcp.server.fastmcp import FastMCP, Context
# Initialize OpenTelemetry Tracer
provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter()) # Replace with OTLP Exporter in production
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("mcp.server.tracer", "1.0.0")
mcp = FastMCP("Traced Enterprise MCP Server")
@mcp.tool()
async def search_knowledge_base(query: str, ctx: Context) -> str:
"""Traced MCP Tool Handler"""
# Create child span for tool execution
with tracer.start_as_current_span("mcp.tool.search_knowledge_base") as span:
# Record semantic attributes according to OTel GenAI conventions
span.set_attribute("gen_ai.tool.name", "search_knowledge_base")
span.set_attribute("gen_ai.tool.query", query)
try:
# Simulate underlying knowledge base search
results = f"Search results for: {query}"
span.set_attribute("gen_ai.tool.status", "success")
span.set_status(Status(StatusCode.OK))
return results
except Exception as e:
span.record_exception(e)
span.set_status(Status(StatusCode.ERROR, str(e)))
raise e
Essential OTel Span Attributes for MCP Tools
When tracing agent and MCP interactions, include standard OpenTelemetry GenAI semantic conventions:
gen_ai.system: Model/Platform provider (gemini,openai,anthropic).gen_ai.tool.name: Exact string identifier of the invoked MCP tool.gen_ai.tool.call_id: Unique call ID assigned by the agent engine.gen_ai.tool.duration_ms: Duration of tool execution in milliseconds.error.type: Exception class name if the tool execution failed.
Analyzing Tracing Telemetry
Exporting OTel traces to platforms like Jaeger, Datadog, Honeycomb, or Grafana Tempo allows engineering teams to:
- Identify slow or hanging MCP tools causing agent latency spikes.
- Map dependency graphs showing which agents invoke specific MCP servers.
- Trace error propagation when a tool failure causes an agent reflection loop.
For standard specifications, API references, and language SDKs, consult the official OpenTelemetry Documentation.