[Draft] Document OpenTelemetry integration
Add comprehensive documentation for integrating OpenTelemetry with FastMCP for distributed tracing and observability.
Changes
- New integration guide at
docs/integrations/opentelemetry.mdx - Covers logging integration with LoggingHandler
- Demonstrates span creation via custom middleware
- Includes production OTLP export configuration
- Provides complete working example
- Updated related docs with OpenTelemetry references
- Registered in docs.json under new Observability section
- Added working example in
examples/opentelemetry_example.py
Closes #1998
Generated with Claude Code
@chrisguidry I had Claude generate this, I was mostly going to stick with logging for now
I thought the problem with emitting spans was going to be that we don't have a way to accept or propagate the trace id through MCP calls so the spans would all be uncorrelated
I'd be very happy to do more if we thought it was useful and sensible
we don't have a way to accept or propagate the trace id through MCP calls
Yep, that's a great call, and I think it might need to be pushed lower into the base SDK? I would make an argument that even without trace propagation, there's still some value because you'd see all of the things your MCP server called out to, even if each tool call was a separate trace. Also, as soon as the community figures out client-side trace propagation, it would all "just work" (LOL).
Didn't mean to block your efforts to get great documentation in for sure!
we don't have a way to accept or propagate the trace id through MCP calls
Yep, that's a great call, and I think it might need to be pushed lower into the base SDK? I would make an argument that even without trace propagation, there's still some value because you'd see all of the things your MCP server called out to, even if each tool call was a separate trace. Also, as soon as the community figures out client-side trace propagation, it would all "just work" (LOL).
Didn't mean to block your efforts to get great documentation in for sure!
I'm ok adding it to our client and server as experimental until the lower level sdk gets it together, would that be interesting for you?
I found this PR when trying to add otel instrumentation to a FastMCP server. I notice no mention of this package: https://github.com/traceloop/openllmetry/blob/main/packages/opentelemetry-instrumentation-mcp/opentelemetry/instrumentation/mcp/fastmcp_instrumentation.py
Would that package not be recommended? Is that something you'd add to FastMCP itself?
Update: I brought in the middleware from your PR and got it working with two OTel-compliant platforms. I also added in StarletteMiddleware on the FastMCP's Starlette app instance, for route-level tracing too. You can see my usage here: https://github.com/Azure-Samples/python-mcp-demos/pull/10/files#diff-2f9b1ef748487a1f4ade8aee44108cafa9db539ad34132e96912588d96e609de
I think it'd be great if this was added to FastMCP itself. You may want to add options to turn off sending tool arguments in the spans, for PII/size reasons.
@pamelafox im not sure using middleware makes the most sense here but im glad it worked for your use-case
/marvin let's update the PR to bake the instrumentation right in
Claude finished @strawgate's task โโ View job
Baking OpenTelemetry instrumentation into FastMCP โ
Successfully integrated OpenTelemetry instrumentation directly into FastMCP core!
Completed Tasks
- [x] Review current OpenTelemetry documentation and examples
- [x] Review FastMCP architecture and middleware system
- [x] Design integration approach (built-in vs optional)
- [x] Implement built-in OTel middleware
- [x] Add optional dependencies for opentelemetry-api
- [x] Update documentation
- [x] Update examples
- [x] Create tests for the middleware
- [x] Run development workflow (uv sync, prek, pytest)
- [x] Commit and push changes
What Was Implemented
Built-in OpenTelemetry Middleware (src/fastmcp/server/middleware/opentelemetry.py):
- Automatic span creation for all MCP operations:
- Tool calls (
tool.{name}) - Resource reads (
resource.read) - Prompt retrievals (
prompt.{name}) - List operations (
tools.list,resources.list, etc.)
- Tool calls (
- Graceful degradation: becomes no-op when OpenTelemetry not installed
- Configuration options:
enabled: explicitly enable/disable (default: True)include_arguments: control inclusion of sensitive data (default: True)max_argument_length: prevent oversized spans (default: 500)tracer_name: custom tracer naming (default: "fastmcp")
Optional Dependency:
- Added
fastmcp[opentelemetry]optional dependency - Installs
opentelemetry-api>=1.20.0andopentelemetry-sdk>=1.20.0
Updated Documentation:
- Rewrote
docs/integrations/opentelemetry.mdxto highlight built-in support - Added Quick Start section showing simple usage
- Updated all examples to use built-in middleware
- Documented configuration options and best practices
Tests:
- Comprehensive test suite with 11 tests covering:
- No-op behavior without OpenTelemetry installed
- Configuration options
- All MCP operation types
- Error handling and propagation
Usage
Users can now simply add the middleware:
from fastmcp import FastMCP
from fastmcp.server.middleware.opentelemetry import OpenTelemetryMiddleware
mcp = FastMCP("My Server")
mcp.add_middleware(OpenTelemetryMiddleware())
If OpenTelemetry isn't installed, the middleware safely becomes a no-op. To enable full instrumentation:
pip install fastmcp[opentelemetry]
All validation checks pass โ
Walkthrough
Adds OpenTelemetry observability across docs, examples, and server middleware. Inserts an "Observability" group under Integrations in docs/docs.json and adds docs/integrations/opentelemetry.mdx. Updates docs/servers/logging.mdx and docs/servers/middleware.mdx with pointers to the OpenTelemetry guide. Adds an example examples/opentelemetry_example.py demonstrating setup, exporters, and middleware wiring. Introduces OpenTelemetryMiddleware at src/fastmcp/server/middleware/opentelemetry.py with tracing hooks, optional argument capture, context propagation, and configuration options.
Pre-merge checks and finishing touches
โ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | โ Passed | The title '[Draft] Document OpenTelemetry integration' clearly summarizes the main change - adding documentation for OpenTelemetry integration with FastMCP. |
| Description check | โ Passed | The description covers all required sections: clear summary of changes, comprehensive list of modifications, issue closure, and AI generation disclosure. Follows the template structure adequately. |
| Linked Issues check | โ Passed | The PR comprehensively addresses issue #1998 by providing OpenTelemetry documentation with logging integration, span creation via middleware, production OTLP export guidance, and working examples. |
| Out of Scope Changes check | โ Passed | All changes are directly scoped to documenting OpenTelemetry integration: documentation files, example code, docs.json registration, and middleware implementation. No extraneous changes detected. |
| Docstring Coverage | โ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. |
โจ Finishing touches
- [ ] ๐ Generate docstrings
๐งช Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
- [ ] Commit unit tests in branch
claude/issue-1998-20251004-0217
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
/marvin while creating spans in middleware is great and all, we also want to push the context information into response _meta fields and then when we receive a result with _meta trace id or whatever, we can use that to set the trace id for the context. That way someone calling us over a weird protocol like SSE can still propagate context for distributed traces
Claude finished @strawgate's task โโ View job
Adding trace context propagation to OpenTelemetry middleware โ
Successfully implemented trace context propagation through MCP _meta fields for cross-protocol observability!
Completed Tasks
- [x] Review current OpenTelemetry middleware implementation
- [x] Understand MCP protocol metadata structure
- [x] Implement trace context injection into response metadata
- [x] Implement trace context extraction from request metadata
- [x] Update tests for context propagation
- [x] Update documentation
- [x] Run validation workflow (uv sync, prek, pytest)
- [x] Commit and push changes
Implementation Summary
Added trace context propagation to OpenTelemetryMiddleware using W3C Trace Context standard:
Key Features:
- New parameter:
propagate_context(default: True) enables/disables trace context propagation - Automatic extraction: Reads
traceparentandtracestatefrom request_metafields - Automatic injection: Writes current trace context to response
_metafields - Universal support: Works across all MCP operations (tools, resources, prompts, list operations)
- Standard format: Uses W3C Trace Context for interoperability with existing tools
Changes Made:
- Modified
src/fastmcp/server/middleware/opentelemetry.py:- Added context extraction and injection helper methods
- Updated all operation handlers to use parent context when available
- Added W3C TraceContextTextMapPropagator for standard format
- Added 5 new tests in
tests/server/middleware/test_opentelemetry_middleware.py - Updated
docs/integrations/opentelemetry.mdxwith configuration examples
Benefits:
- Enables distributed tracing across protocols without HTTP headers (SSE, stdio, etc.)
- Automatically links spans when clients provide trace context in requests
- Allows downstream trace propagation to other MCP servers
- Gracefully degrades when trace context isn't provided
Example Usage:
from fastmcp import FastMCP
from fastmcp.server.middleware.opentelemetry import OpenTelemetryMiddleware
mcp = FastMCP("My Server")
mcp.add_middleware(OpenTelemetryMiddleware(propagate_context=True))
All validation checks pass โ