mcp-trace

module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 26, 2026 License: MIT

README

mcp-trace

Transparent Go proxy for MCP servers that emits OpenTelemetry spans for every JSON-RPC tool call.

MCP Client  →  mcp-trace :8001  →  MCP Server :8000
                     ↓
              OTEL Collector :4317
              (Jaeger / Tempo / Honeycomb)

Quick start

# Run against a local MCP server, export spans to Jaeger
mcp-trace --target http://localhost:8000/sse --port 8001 --otel-endpoint localhost:4317

Point your MCP client at :8001 instead of :8000. Zero client changes required.

With Docker Compose (Jaeger all-in-one)
docker compose -f docker/compose.jaeger.yml up -d
mcp-trace --target http://localhost:8000/sse
# Open http://localhost:16686 — traces appear after the first tool call.

Installation

Pre-built binary

Download from GitHub Releases.

Build from source
go install github.com/anhermon/mcp-trace/cmd/mcp-trace@latest
Docker

No image is published. Build one locally:

task docker:build
docker run --rm mcp-trace:dev \
  --target http://host.docker.internal:8000/sse \
  --otel-endpoint host.docker.internal:4317

Configuration

All flags can be set via a .mcp-trace.yaml file (see .mcp-trace.yaml.example).

Flag Default Description
--target (required) Upstream MCP server SSE URL
--port 8001 Local port to listen on
--otel-endpoint localhost:4317 OTLP gRPC endpoint
--otel-http false Use HTTP OTLP exporter instead of gRPC
--otel-http-endpoint http://localhost:4318 OTLP HTTP endpoint
--otel-insecure true Disable TLS for OTLP
--service-name mcp-trace OTel service.name resource attribute
--trace-all false Trace all JSON-RPC methods (not just tools/call)
--include-lifecycle false Include initialize/ping/notifications/*
--log-level info debug | info | warn | error
--config Path to config file

Environment variables

Every CLI flag can also be set via an environment variable using the MCP_TRACE_ prefix. Nested OTel keys use _ as a separator (._).

Environment variable Equivalent flag Example
MCP_TRACE_TARGET --target http://localhost:8000/sse
MCP_TRACE_PORT --port 8001
MCP_TRACE_OTEL_ENDPOINT --otel-endpoint localhost:4317
MCP_TRACE_OTEL_HTTP --otel-http true
MCP_TRACE_OTEL_HTTP_ENDPOINT --otel-http-endpoint http://localhost:4318
MCP_TRACE_OTEL_INSECURE --otel-insecure true
MCP_TRACE_OTEL_SERVICE_NAME --service-name my-mcp-server
MCP_TRACE_TRACE_ALL --trace-all true
MCP_TRACE_INCLUDE_LIFECYCLE --include-lifecycle true
MCP_TRACE_LOG_LEVEL --log-level debug

The service-name variable is MCP_TRACE_OTEL_SERVICE_NAME, not MCP_TRACE_SERVICE_NAME — the underlying config key is otel.service_name.

Environment variables override config-file values. CLI flags take the highest precedence.

Docker example — run mcp-trace entirely via environment, no flags needed:

docker run --rm \
  -e MCP_TRACE_TARGET=http://host.docker.internal:8000/sse \
  -e MCP_TRACE_OTEL_ENDPOINT=host.docker.internal:4317 \
  -e MCP_TRACE_OTEL_SERVICE_NAME=my-service \
  mcp-trace:dev

Span schema

Every traced call produces a span with these attributes:

Attribute Present on Description
mcp.method all spans JSON-RPC method
mcp.request.id all spans JSON-RPC request id
mcp.server.target all spans Upstream URL
mcp.duration_ms all spans Wall-clock duration in ms
mcp.status all spans ok or error
mcp.tool.name tools/call only Tool name
mcp.tool.duration_ms tools/call only Wall-clock duration in ms
mcp.tool.status tools/call only ok or error
error error spans true if errored
error.message error spans Error message

Spans are emitted with SpanKind = client. If the caller sends a traceparent header, the span is created as a child of that trace; either way mcp-trace injects traceparent into the request it forwards upstream, so the MCP server can continue the same trace.

Span names follow the pattern:

  • mcp tools/call read_file (tool calls)
  • mcp tools/list (other methods, with --trace-all)

As a Claude Code plugin

{
  "mcpServers": {
    "my-server-traced": {
      "command": "mcp-trace",
      "args": [
        "--target", "http://localhost:8000/sse",
        "--port", "8001",
        "--otel-endpoint", "localhost:4317"
      ]
    }
  }
}

Development

task build    # build binary to bin/mcp-trace
task test     # run all tests
task ci       # full pipeline: vet + test + lint + build
task release  # cross-compile all platforms to dist/
Pre-commit hooks

Install hooks that run task ci before every commit and task check before every push:

task hooks:install

Remove hooks:

task hooks:uninstall

Hooks are stored in scripts/hooks/ and copied into .git/hooks/. Bypass in emergencies with --no-verify (use sparingly).

Roadmap

  • v1.0 — SSE proxy with OTLP spans (this release)
  • v2.0 — stdio transport support (mcp-trace --stdio -- <command>)
  • v2.x — Metrics (counters, histograms), sampling

License

MIT

Directories

Path Synopsis
cmd
mcp-trace command
internal
proxy
Package proxy implements the transparent MCP SSE proxy with OTel span emission.
Package proxy implements the transparent MCP SSE proxy with OTel span emission.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL