Skip to content

Latest commit

 

History

21 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MCP Trace

CI CodeQL Release License: MIT

Security-first Model Context Protocol observability for stdio and Streamable HTTP. Put one transparent proxy between an MCP client and a fixed upstream server to trace, measure, record, inspect, and safely replay JSON-RPC and SSE traffic.

Status: early preview (0.x). The protocol boundary, recording schema, and CLI may evolve before 1.0. Current limits are documented rather than hidden.

A real MCP Trace demo showing a successful tool call, sanitized recording summary, and bounded Prometheus metric

Start in 30 seconds

The public v0.1.1 container is the shortest released path on linux/amd64:

docker run --rm --network host \
  ghcr.io/ryux1/mcp-trace:v0.1.1 proxy \
  --upstream http://127.0.0.1:3001/mcp

The npm package is not published yet. To run the newer 0.2.0 code on main, use Node.js 20.19 or newer and the deterministic source demo:

corepack enable
pnpm install --frozen-lockfile
pnpm demo

The deterministic demo starts a mock MCP server and MCP Trace on ephemeral localhost ports, sends a real tools/call, verifies that the demo credential was redacted, prints a recording summary and a Prometheus metric, and cleans up every process and temporary file.

Why MCP Trace?

Generic reverse proxies measure HTTP but do not understand MCP methods, protocol revisions, JSON-RPC identifiers, or MCP header/body mismatches. Application instrumentation has the opposite problem: it changes the server and can capture tool arguments or credentials too freely.

MCP Trace keeps the boundary narrow:

  • Transparent: forwards JSON and streams SSE with backpressure and cancellation propagation.
  • MCP-aware: identifies methods, protocol revisions, tool/resource names, and mismatches.
  • Safe by default: records metadata only; body capture requires an explicit second switch.
  • Vendor-neutral: exports bounded Prometheus metrics and OpenTelemetry spans over OTLP/HTTP.
  • Replay-conscious: plans a dry run unless --execute is supplied and skips unsafe entries.
  • Auditable: does not implement MCP methods, terminate authorization, or select upstreams.

Use MCP Trace when you operate a fixed Streamable HTTP endpoint or local stdio server and need evidence without modifying the client or server. Use the official MCP Inspector when you need an active testing client. Use a full MCP gateway when you need server discovery, routing, identity, or policy enforcement.

MCP client  ──POST / GET / DELETE──▶  MCP Trace  ──transparent HTTP──▶  MCP server
                                            │
                                            ├── Prometheus metrics
                                            ├── OpenTelemetry spans
                                            └── sanitized NDJSON recording

Protocol compatibility

MCP transport revision Status Behavior
2026-07-28 Streamable HTTP Supported POST, JSON or request-scoped SSE, Mcp-Method, Mcp-Name, Mcp-Param-*
2025-03-26 through 2025-11-25 Supported POST/GET/DELETE, Mcp-Session-Id, Last-Event-ID, standalone SSE
2024-11-05 HTTP+SSE Not targeted Separate endpoint discovery is outside this fixed-endpoint gateway
stdio Supported Exact-byte newline forwarding, child lifecycle, v2 message recordings

The compatibility matrix distinguishes verified behavior from planned work. Integration tests exercise initialization, tools/list, and tools/call using the official TypeScript SDK 1.30.0 and Python SDK 2.1.1 as both clients and servers. The gateway targets the 2026 Streamable HTTP specification and 2025 transport specification.

Install and run

From source

The registry packages shown in the release workflow are not published yet. Until the first release, run the CLI from a verified source checkout:

git clone https://github.com/ryux1/mcp-trace.git
cd mcp-trace
corepack enable
pnpm install --frozen-lockfile
pnpm build
pnpm start -- proxy \
  --upstream http://127.0.0.1:3001/mcp

Point the MCP client at http://127.0.0.1:7331/mcp. MCP Trace binds only to 127.0.0.1 by default.

Local stdio servers

Use stdio when the MCP client normally launches a local server process. Everything after -- is passed directly to the executable without a shell:

mcp-trace stdio --record ./traffic.ndjson -- node ./server.mjs

An MCP client configuration uses MCP Trace as the server command and places the real server after the separator:

{
  "mcpServers": {
    "local-server": {
      "command": "mcp-trace",
      "args": [
        "stdio",
        "--record",
        "/absolute/path/to/traffic.ndjson",
        "--",
        "node",
        "/absolute/path/to/server.mjs"
      ]
    }
  }
}

The child inherits the proxy environment by default, which preserves environment-based MCP server configuration. Use --clear-env for a minimal launch environment and repeat --pass-env NAME for each additional variable the server needs. Values are never logged or added to recordings. The child still has the same operating-system identity and filesystem access as MCP Trace; this is not a sandbox.

Protocol messages are forwarded byte-for-byte and limited to 4 MiB each by default. Child stderr is forwarded separately to MCP Trace's stderr and never enters protocol stdout. Metadata-only v2 message recording is the default; --record-bodies adds best-effort-redacted JSON bodies. The HTTP-targeted replay command skips stdio message entries.

Container

The public v0.1.1 image is available for linux/amd64. Pin the version so deployment behavior does not change when a new release updates latest:

docker pull ghcr.io/ryux1/mcp-trace:v0.1.1

docker run --rm --network host \
  ghcr.io/ryux1/mcp-trace:v0.1.1 proxy \
  --host 127.0.0.1 \
  --upstream http://127.0.0.1:3001/mcp

The image is also tagged latest. The next release workflow targets both linux/amd64 and linux/arm64 with an SBOM and build provenance. CI builds and starts the container on native amd64 and arm64 runners before validating its health endpoint.

For a complete local Jaeger demonstration:

docker compose -f docker-compose.demo.yml up --build --detach

The Compose stack starts Jaeger, a mock MCP server, MCP Trace, and a one-shot client. Select the mcp-trace service at http://127.0.0.1:16686. Stop the stack with:

docker compose -f docker-compose.demo.yml down --volumes

Record and inspect

Metadata-only recording is the default:

mcp-trace proxy \
  --upstream http://127.0.0.1:3001/mcp \
  --record ./traffic.ndjson

Payload capture requires a second, explicit switch:

mcp-trace proxy \
  --upstream http://127.0.0.1:3001/mcp \
  --record ./traffic.ndjson \
  --record-bodies \
  --redact-key tenant-secret

Recording files are forced to owner-only mode (0600). Inspect them without starting a server:

mcp-trace inspect ./traffic.ndjson

The output summarizes request counts, failures, bytes, and p50/p95/p99 latency by MCP method. Read the recording schema and security model before capturing production traffic.

Create a self-contained report for offline review:

mcp-trace report ./traffic.ndjson --output ./report.html

The report contains aggregate counts, latency percentiles, capture/redaction evidence, and malformed line accounting. It includes no scripts, remote resources, recording path, headers, body values, or error messages. The output is owner-readable (0600) and will not replace an existing file unless --force is explicit. It also refuses any output path that resolves to the input recording.

Replay safely

Replay is a dry run by default. It reports how many requests are replayable and skips truncated, binary, body-less, and redacted entries.

mcp-trace replay ./traffic.ndjson \
  --upstream http://127.0.0.1:3001/mcp

Execute only against a system where repeating tool calls is safe:

mcp-trace replay ./traffic.ndjson \
  --upstream http://127.0.0.1:3001/mcp \
  --execute \
  --concurrency 4 \
  --rate 20

Authorization can be supplied with --header-env. Legacy Mcp-Session-Id values are never recorded or replayed, so replay is best suited to stateless 2026 traffic.

Metrics and tracing

The gateway exposes two local administrative endpoints:

  • GET /__mcp_trace/healthz
  • GET /__mcp_trace/metrics

Prometheus metrics include request totals, in-flight requests, recording failures, and latency histograms. Method-label cardinality is bounded; tool/resource names are not used as metric labels.

Export spans to any OTLP/HTTP collector:

export OTEL_AUTHORIZATION='Bearer collector-token'

mcp-trace proxy \
  --upstream http://127.0.0.1:3001/mcp \
  --otlp-endpoint http://127.0.0.1:4318 \
  --otlp-header-env Authorization=OTEL_AUTHORIZATION

Each span includes HTTP method/status, MCP method, protocol revision, upstream address, and detected header/body mismatch fields. Tool/resource names appear only on individual spans. MCP Trace preserves JSON _meta.traceparent, _meta.tracestate, and _meta.baggage fields without rewriting them, and separately propagates standard HTTP trace headers.

Security boundary

MCP Trace is not a data-loss-prevention system, authorization server, protocol validator, or dynamic forward proxy. The upstream is fixed at startup. Redaction is defense in depth, not proof that a recording contains no sensitive data.

Authenticated upstream headers are loaded from environment variables instead of command arguments:

export MCP_UPSTREAM_AUTHORIZATION='Bearer replace-me'

mcp-trace proxy \
  --upstream https://mcp.example.com/mcp \
  --upstream-header-env Authorization=MCP_UPSTREAM_AUTHORIZATION

When binding to 0.0.0.0 or ::, at least one --allow-host value is required. Browser origins are rejected unless explicitly allowed. Review recordings before sharing them.

Verification and evidence

pnpm verify
pnpm smoke:package
pnpm demo
pnpm benchmark

The verification gate runs formatting, ESLint, strict TypeScript checks, unit and integration tests with coverage thresholds, and a clean build. Package smoke testing installs the generated tarball in a temporary consumer project and proxies a real request through the installed executable. Hosted CI runs that consumer and demo path on Linux, macOS, and Windows.

Benchmark methodology and versioned raw results are documented in docs/benchmarks.md. Results are treated as regression evidence, not production capacity claims.

Documentation

License

MIT

About

Security-first MCP observability proxy for stdio and Streamable HTTP recording, inspection, tracing, and replay.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages