How It Works
FastMCP uses the OpenTelemetry API for instrumentation. This means:- On by default - Instrumentation is active out of the box, no opt-in required
- No overhead when unused - Without an SDK, all operations are no-ops
- Bring your own SDK - You control collection, export, and sampling
- Works with any OTEL backend - Jaeger, Zipkin, Datadog, New Relic, etc.
Telemetry Modes
FASTMCP_TELEMETRY_MODE (or fastmcp.settings.telemetry_mode) controls how much of the instrumentation is active:
Use
off to disable FastMCP’s instrumentation entirely. No spans are created even if an SDK is configured, and FastMCP leaves the surrounding OpenTelemetry context exactly as it found it.
Use propagation_only when another instrumentation layer already owns the MCP span hierarchy — see Interoperability below.
Enabling Telemetry
The easiest way to export traces is usingopentelemetry-instrument, which configures the SDK automatically:
OpenTelemetry Python Documentation
Learn more about the OpenTelemetry Python SDK, auto-instrumentation, and available exporters.
Tracing
FastMCP creates spans for all MCP operations, providing end-to-end visibility into request handling.Server Spans
The server creates spans for each operation using MCP semantic conventions:
For mounted servers, an additional
delegate {name} span shows the delegation to the child server.
Client Spans
The FastMCP client creates spans for outgoing requests with the same naming pattern (tools/call {name}, resources/read, prompts/get {name}, and tasks/{operation}).
Span Hierarchy
Spans form a hierarchy showing the request flow. For mounted servers:Background tasks
Background task traces have two parts:- Task submission and management requests use normal client-to-server context propagation.
tasks/get,tasks/update, andtasks/cancelserver spans are descendants of the corresponding FastMCP client spans. - Deferred execution runs in a Docket worker. Docket records its
CONSUMERspan as a new trace root with a span link to the submission context, rather than making it a child of the submission span. Custom spans created inside the task are children of that worker span.
ParentBased:
ParentBased delegates. If the name-based sampler is nested inside ParentBased, it is not consulted for child spans whose parent was already sampled.
Interoperability
FastMCP assumes it owns the MCP span hierarchy. When something else already owns it — an MCP-aware OpenTelemetry instrumentation library, or a service mesh that understands the protocol — FastMCP’s spans duplicate what that layer already emits, and the same request shows up twice in your traces. Settingpropagation_only resolves the duplication in FastMCP’s favor of the other layer:
off matters here. Both emit no FastMCP spans, but off is fully transparent, while propagation_only still extracts the trace context arriving in _meta and attaches it for the duration of the request. Spans created downstream — by your tool handlers, or by the instrumentation layer that owns the hierarchy — are parented to the calling trace rather than starting a new one. Outbound requests still carry traceparent and tracestate in _meta.
Suppressing spans for a single block
Library authors embedding FastMCP inside their own instrumented stack often want to own the hierarchy for one specific operation rather than process-wide.suppress_fastmcp_telemetry() applies propagation_only semantics to a block:
telemetry_mode is already off. A request to skip FastMCP’s spans cannot re-enable the context propagation that off deliberately omits.
Programmatic Configuration
For more control, configure the SDK in your Python code before importing FastMCP:Local Development
For quick local trace visualization, otel-desktop-viewer is a lightweight single-binary tool:Custom Spans
You can add your own spans using the FastMCP tracer:Where custom spans help most
Custom spans are most useful around work that is expensive or hard to debug:- External calls such as databases, vector stores, HTTP APIs, or queue operations
- Multi-step tool logic where one stage dominates latency
- Prompt or resource generation that fans out to other systems
- LLM calls a tool makes to a model provider
Recommended naming and attributes
- Use
{tool_name}.{operation}or{resource_name}.{operation}for child spans such assearch.fetch,search.rank, ordocs.render - Add attributes that explain workload shape, such as counts, sizes, cache hits, or IDs
- Do not record secrets, prompts with sensitive user data, or raw tokens as span attributes
- Let exceptions propagate unless you have a specific recovery path; FastMCP’s server spans already mark failures and record exceptions
Instrumenting tools, prompts, and resources
LLM calls inside tools
A tool that calls an LLM directly should keep the model work nested under the tool span, so traces show application logic and model latency together. For providers with their own OTEL integrations, prefer enabling that instrumentation rather than manually creating a span around every model call. For example, if you use Google GenAI,logfire.instrument_google_genai() will emit child spans with token and request metadata under the active FastMCP tool span.
Exporter choices
- For local debugging,
ConsoleSpanExporterorotel-desktop-viewergives quick feedback with minimal setup - For shared environments, use OTLP exporters to backends like Logfire, Jaeger, Tempo, Datadog, or New Relic
- If traces are too noisy, tune sampling in your OpenTelemetry SDK instead of removing FastMCP instrumentation
Error Handling
When errors occur, spans are automatically marked with error status and the exception is recorded:Attributes Reference
MCP Semantic Conventions
FastMCP implements the OpenTelemetry MCP semantic conventions:Auth Attributes
Standard identity attributes:FastMCP Custom Attributes
All custom attributes use thefastmcp. prefix for features unique to FastMCP:
Provider-specific attributes for delegation context:

