mcpspan

Proxy, no code changes

mcpspan analytics for an MCP server without changing its code. The proxy runs in front of the server, passes everything between it and the client through unchanged, and reports the calls it sees: which tools are called, by which client, how fast, and how they fail.

For a server you cannot or would rather not change: one in a language without an mcpspan SDK, one you did not write, or one you want to try mcpspan on first. Where you can add an SDK, it sees a little more (see What it sees).

A server over stdio

In your client's MCP settings, put the proxy in front of the server's own command, after --:

npx mcpspan-proxy -- node dist/server.js
npx mcpspan-proxy -- uv run server.py
npx mcpspan-proxy -- ./target/release/my-server --stdio

with your API key and the address of your mcpspan in the environment. In Claude Code, for example:

{
  "mcpServers": {
    "flights": {
      "command": "npx",
      "args": ["-y", "mcpspan-proxy", "--", "node", "/path/to/dist/server.js"],
      "env": {
        "MCPSPAN_API_KEY": "your-key",
        "MCPSPAN_ENDPOINT": "https://api.mcpspan.com"
      }
    }
  }
}

MCPSPAN_ENDPOINT is https://api.mcpspan.com on mcpspan Cloud, or your own installation's address when you run it yourself. The server gets the rest of the environment as before. Needs Node 20 or newer.

A server over HTTP

Run the proxy with the server's address, and point clients at the proxy instead:

npx mcpspan-proxy http://localhost:3000/mcp

It listens on port 6273 (--port to change it), and passes every request to the same path on the server. In Docker:

docker run -p 6273:6273 -e MCPSPAN_API_KEY -e MCPSPAN_ENDPOINT \
  ghcr.io/mcpspan/proxy http://flights:3000/mcp

Answers stream through as the server sends them, and each client session the server opens is a session in mcpspan. Headers go through too, the Authorization a client sends among them; the server sees its own address as the Host, and where the request came from in X-Forwarded-For.

Settings

The API key, endpoint and version come from the environment, as for the SDKs:

Variable
MCPSPAN_API_KEYThe server's key, from Settings in mcpspan. Without it the proxy passes everything through and reports nothing.
MCPSPAN_ENDPOINTYour mcpspan: https://api.mcpspan.com on Cloud, your installation's address when you run it yourself.
MCPSPAN_SERVER_VERSIONThe version to record calls under, when the one the server gives itself is not the one you want.
Option
--exclude <tool>Leave a tool out of the numbers, such as a health check. Repeat for more.
--parameter-namesRecord the names and types of the arguments a tool is called with, never their values.
--no-error-messagesLeave out the text of failures, for tools that can fail with something you would not send anywhere.
--flush-interval <seconds>How long a batch of calls waits before it is sent. 5 when left out.
--port <port>Over HTTP: where to listen. 6273 when left out.
--host <address>Over HTTP: the address to listen on. 127.0.0.1 when left out, 0.0.0.0 in the Docker image.
--debugWrite delivery problems to stderr.

The server does not get MCPSPAN_API_KEY: if it has an mcpspan SDK of its own, that SDK stays quiet rather than count every call a second time.

What it sees

The proxy sees what the server and the client say to each other, and records from it what an SDK does: tool calls, resources and prompts, the client, the server's version, sessions, response sizes, the tools the server lists and how large their definitions are, repeated calls, and which arguments a refused call got wrong. Values never leave it, as with the SDKs.

An SDK inside the server sees two things the proxy cannot:

Both are checked: the SDKs' own conformance suite runs through the proxy on every change.

Licence

MIT

This page is packages/mcpspan-proxy/README.md on GitHub.