Skip to content

Latest commit

 

History

History
70 lines (59 loc) · 3.71 KB

File metadata and controls

70 lines (59 loc) · 3.71 KB

Architecture — mcp-telemetry

Zero-config observability for MCP servers. Instrument at import, ship OTel GenAI-compliant spans, replay offline. Core package is stdlib-only against the grain of the ecosystem — httpx is an optional extra.

        mcp SDK server ──patch──▶ monkey.wrap_tool_call
                              │
        fastmcp server ─patch─▶ fastmcp.patch_fastmcp
                              │
        manual / agent code ──▶ api.session() + api.span()
                              │
                              ▼
                       store (TraceStore, in-memory + JSONL)
                              │  on_record
                              ▼
        exporters fanout: JsonlExporter · TextExporter · OtlpExporter(httpx)
                              │
                              ▼
        replay offline: mcp-trace --replay store.jsonl --console → OTLP-shaped

Modules

File Job
store.py TraceStore — start/record/close traces; default store w/ JSONL append.
api.py Public surface: auto, instrument, session, span.
monkey.py Monkeypatch for the official mcp SDK — wrap_tool_call, patch_mcp_sdk, idempotent.
redact.py SHA-256 input fingerprints + secret-key scrubbing (token[REDACTED]).
exporters.py Exporter protocol, JSONL / Text(panel) / OTLP(HTTP) + Fanout.
model.py Span dataclass — includes parent_span_id for continued traces.
propagator.py W3C traceparent / tracestategenerate_traceparent, parse_traceparent.
sampler.py parent_based, ratio, rate_limited sampling policies.
metrics.py Registry, Histogram w/ explicit buckets, metrics_from_store.
otel_provider.py OtelProvider — builds OTLP-shaped span bundles (export_built), telemetry objects.
replay.py Offline re-delivery of a recorded JSONL store through the exporter stack.
fastmcp.py Opt-in shim for fastmcppatch_fastmcp, make_server.
cli.py mcp-trace — table, --tail, --json, --clear, --replay [--console] [--max N].

Key invariants

  1. Hidden from your codemt.auto() patches, scrubs, and exports; the only visible change is spans you never wrote a line for.
  2. Never store secrets — inputs are fingerprinted, sensitive keys scrubbed, all before anything touches disk.
  3. Zero-config default — no SDK, no env vars, no account: install and auto().
  4. Continued traces cross servers — a traceparent header on an inbound MCP request starts store.start(parent.trace_id) and stamps parent_span_id on the span; the sibling repo mcp-hub relays that header on every upstream hop. One trace, end to end, replayable offline.

Data flows

Instrumented tool call: mcp SDK / fastmcp / manual span → store.start → span(fingerprint, redaction, parent_span_id) → store.record → exporters fanout (JSONL + panel + OTLP)

Replay: mcp-trace --replay FILE [--console] [--max N] → rehydrate traces → OtelProvider.export_built → console / exporter

Conventions

  • Stdlib-first: the core import graph uses zero third-party imports.
  • Everything pure where possible; side effects live in store, exporters.
  • Spans model OTel GenAI semantic conventions (gen_ai.client.tool_call, gen_ai.agent.invoke) so no transform is needed in your observability stack.