This release is a pre-release and may not be stable for production use.
mcp-telemetry
Zero-config observability for MCP servers. OTel GenAI conventions. Redaction on by default.
MCP hit 97 million monthly SDK downloads — and the production playbook is still being written. OWASP's MCP Top 10 puts "Lack of Audit and Telemetry" at the top of the risk list. This repo is that gap, filled in three lines.
Install
pip install mcp-telemetry # core — zero dependencies
pip install 'mcp-telemetry[otlp]' # + OTLP/HTTP export (httpx)
Use — no changes to your server logic
import mcp_telemetry as mt
mt.auto() # patches the official `mcp` SDK, writes JSONL
@mt.wrap_tool_call("issues.fetch", server="gh")
def fetch_issue(issue_id, token=""):
...
Every call emits an OTel GenAI gen_ai.client.tool_call span with:
- input fingerprint — SHA-256 hash, never the raw payload
- secret scrubbing —
token,secret,api_key-style keys →[REDACTED] - latency, status, error type, server name
Manual spans and traces work too:
with mt.session(): # one trace for the whole agent turn
with mt.span("chat.step"):
...
Distributed traces cross servers
Propagation is built in. A traceparent header on an inbound MCP request starts a
continuation, not a new trace — the span stamps parent_span_id and the trace id
carries through:
from mcp_telemetry.propagator import parse_traceparent
store.start(parse_traceparent(my_header).trace_id)
Pair with mcp-hub: set the gateway's
telemetryUrl to this server and every hub-hosted call streams in as a span
whose trace continues whatever traceparent the client sent — one trace down
to the upstream and back. See examples/responder.py
for a stdlib-only server that records the far side.
Watch the firehose
mcp-trace # last 25 spans, ANSI table
mcp-trace --tail # follow the JSONL feed
mcp-trace --json | jq . # pipe raw records anywhere
mcp-trace --replay store.jsonl --console # offline replay → OTLP-shaped output
mcp-trace --serve 8901 # live dashboard + JSON + SSE + /ingest
--serve opens a dark single-file dashboard on http://127.0.0.1:8901
(autopolling stats, top-tools latency table, realtime spans over SSE) while
keeping the raw /traces and /stats JSON endpoints. POST /ingest appends
straight into the feed — this is where mcp-hub
points its telemetryUrl, so client → hub → upstream spans land in the
same dashboard. Add --max-bytes N to keep the feed bounded (3 generations).
Exporters
| Exporter | Where | Deps |
|---|---|---|
JsonlExporter |
mcp-telemetry.jsonl |
none |
TextExporter |
live stderr panel | none |
OtlpExporter |
Jaeger/Grafana/Datadog via OTLP/HTTP | [otlp] |
Spans follow OTel GenAI semantic conventions (gen_ai.client.tool_call,
gen_ai.agent.invoke) so traces land in your existing stack without a transform layer.
Extended surface
- Sampling —
parent_based,ratio,rate_limited(mcp_telemetry.sampler) - Metrics —
Registry+ histogram buckets,metrics_from_store(mcp_telemetry.metrics) - OTel provider — builds OTLP-shaped telemetry,
OtelProvider.export_built(mcp_telemetry.otel_provider) - fastmcp — opt-in shim:
mt.make_server(),patch_fastmcp(mcp_telemetry.fastmcp) - Offline replay — re-deliver any recorded JSONL through the exporter stack
Overhead
examples/bench.py: ~78µs median, ~85µs p95 per instrumented call (Python 3.14).
There's no free lunch, but at that cost you can trace every tool call in a hot agent loop.
Design
monkey.py— monkeypatches the officialmcpSDK'scall_tool; idempotent, no-ops cleanly when the SDK is absentredact.py— fingerprinting + secret scrubbing, deterministic hashesstore.py/api.py— trace lifecycle + the three-line public surfacepropagator.py— W3Ctraceparent/tracestatecontinuation between servicesreplay.py/cli.py— offline re-export +mcp-tracerenderer/tail/replay- Core import graph is stdlib-only;
httpxlives behind[otlp]
MIT. Ship it.
Metadata
Release files for mcp-telemetry 0.3.0b1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcp_telemetry-0.3.0b1.tar.gz | 31.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_telemetry-0.3.0b1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 62.0 kB
Release files / mcp_telemetry-0.3.0b1.tar.gz
| Download URL | mcp_telemetry-0.3.0b1.tar.gz |
|---|---|
| Size | 31.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b61338d3bcf65fb09e387892d390082a7035922a33950a5e4ae18e096588dab1
|
|
BLAKE2b-256 checksum How to use checksums |
4cb412c875a83e4164f74004df3ed1c0348ac1813e7555924cf5ca6d4b6b3a90
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / mcp_telemetry-0.3.0b1-py3-none-any.whl
| Download URL | mcp_telemetry-0.3.0b1-py3-none-any.whl |
|---|---|
| Size | 31.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
49217dc7b1928312a7af48a2c3eefce281a2656c2f720a8473d218c729fed9da
|
|
BLAKE2b-256 checksum How to use checksums |
94121d6fec4ab50c91db2e5e34f27194a568f23df6cf254207cbcf6e8d60a5c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|