Summary
The telemetry docs show how to enable tracing and what FastMCP emits automatically, but don't guide users on how to instrument their own tool/prompt/resource implementations. Users building production MCP servers need guidance on:
Proposed content
Adding spans inside tools
from fastmcp import FastMCP
from fastmcp.telemetry import get_tracer
mcp = FastMCP("my-server")
@mcp.tool
async def search(query: str) -> str:
tracer = get_tracer()
with tracer.start_as_current_span("search.fetch") as span:
span.set_attribute("search.query_length", len(query))
results = await fetch_results(query)
span.set_attribute("search.result_count", len(results))
with tracer.start_as_current_span("search.rank") as span:
ranked = rank_results(results)
return format_results(ranked)
Recommended patterns
- Span naming: Use
{tool_name}.{operation} for child spans (e.g., search.fetch, search.rank)
- What to trace: External calls (APIs, databases), expensive computations, anything >100ms
- What NOT to trace: Every function call, simple transformations, fast in-memory operations
- Attributes: Add domain-specific attributes that help debugging (counts, sizes, IDs) — not PII or secrets
- Error recording: Let exceptions propagate — FastMCP's
server_span records them automatically. Don't double-record.
Instrumenting sampling calls
For servers that use ctx.sample() for LLM calls, recommend using logfire.instrument_google_genai() or equivalent to get per-LLM-call spans with token counts nested inside the tool span.
Connecting to backends
- Logfire:
logfire.configure() — FastMCP spans flow automatically
- Jaeger/OTLP:
opentelemetry-instrument CLI or programmatic SDK setup
- Console (debugging):
ConsoleSpanExporter for raw span output
Summary
The telemetry docs show how to enable tracing and what FastMCP emits automatically, but don't guide users on how to instrument their own tool/prompt/resource implementations. Users building production MCP servers need guidance on:
Proposed content
Adding spans inside tools
Recommended patterns
{tool_name}.{operation}for child spans (e.g.,search.fetch,search.rank)server_spanrecords them automatically. Don't double-record.Instrumenting sampling calls
For servers that use
ctx.sample()for LLM calls, recommend usinglogfire.instrument_google_genai()or equivalent to get per-LLM-call spans with token counts nested inside the tool span.Connecting to backends
logfire.configure()— FastMCP spans flow automaticallyopentelemetry-instrumentCLI or programmatic SDK setupConsoleSpanExporterfor raw span output