fastmcp icon indicating copy to clipboard operation
fastmcp copied to clipboard

[Draft] Document OpenTelemetry integration

Open strawgate opened this issue 2 months ago โ€ข 3 comments

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

strawgate avatar Oct 04 '25 02:10 strawgate

@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

strawgate avatar Oct 12 '25 20:10 strawgate

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!

chrisguidry avatar Oct 15 '25 15:10 chrisguidry

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?

strawgate avatar Oct 15 '25 15:10 strawgate

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?

pamelafox avatar Dec 02 '25 00:12 pamelafox

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 avatar Dec 03 '25 21:12 pamelafox

@pamelafox im not sure using middleware makes the most sense here but im glad it worked for your use-case

strawgate avatar Dec 03 '25 22:12 strawgate

/marvin let's update the PR to bake the instrumentation right in

strawgate avatar Dec 03 '25 22:12 strawgate

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.)
  • 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.0 and opentelemetry-sdk>=1.20.0

Updated Documentation:

  • Rewrote docs/integrations/opentelemetry.mdx to 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 โœ“

--- | Branch: claude/issue-1998-20251004-0217

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.

โค๏ธ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot] avatar Dec 03 '25 22:12 coderabbitai[bot]

/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

strawgate avatar Dec 03 '25 23:12 strawgate

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 traceparent and tracestate from request _meta fields
  • Automatic injection: Writes current trace context to response _meta fields
  • 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.mdx with 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 โœ“

--- | Branch: claude/issue-1998-20251004-0217