mcpsnoop: a transparent MCP proxy that shows the tool calls your client actually makes
Wireshark for MCP. A transparent proxy that shows every real tool call between your AI client and your MCP servers, live in your terminal.
At a glance
- What is it?
- mcpsnoop sits in the real data path between an AI client and an MCP server and renders every JSON-RPC frame in a terminal UI. It is useful precisely where a client-side inspector is blind, and it carries the costs of being a proxy.
- Who is it for?
- Adopt mcpsnoop if you are debugging a real client against a real MCP server and need to see the frames the client actually sends, or if you want captured sessions checked in CI through the GitHub Action. Do not adopt it if you need an authenticated metrics endpoint, a durable store of record, or a tool that inspects other clients without becoming part of their launch command.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The blind spot mcpsnoop was built to fill
The official MCP Inspector connects as its own client. That means it exercises your server with requests the Inspector chooses, not the requests Cursor, Claude Code or Codex choose. When a tool is silently not called, or is called with arguments you did not expect, an inspector that is a separate client cannot show it. Neither can anything that waits passively for a request to arrive, since a call the model never made produces no request to observe.
mcpsnoop takes the other position. It is a transparent proxy placed in the launch path of your server, so the traffic it renders is the traffic your real client and your real server exchange. The README frames the audience directly: people debugging MCP integrations who are, in its words, "left digging through logs and guessing". That is the whole product thesis, and it is a narrow one. If your problem is server-side logic, an ordinary test harness will do. If your problem is what the client actually transmitted, this is the class of tool you need.
How the proxy, the shim and the TUI fit together
There are two entry points and they behave differently. Wrapped as a subprocess, mcpsnoop launches your server command, forwards JSON-RPC frames in both directions, and records them. Run bare as `mcpsnoop`, it starts the terminal UI, which finds the shim on its own and backfills past sessions from disk. The README is explicit that there is no socket path to pass and no startup order to remember, which is a design decision rather than an accident: the shim and the UI discover each other.
For streamable-HTTP servers the shape changes. `mcpsnoop http` runs as a reverse proxy in front of a target URL, and the HTTP status of every response becomes a visible frame even when the response carries no JSON-RPC message of its own. The README names the cases: a 401 challenge, a 403 on a rejected Origin, a 202 acknowledging a notification, and a 502 when the target is unreachable. A 401's WWW-Authenticate header is preserved verbatim and shown in the inspector, because it names the auth scheme and the resource metadata to follow. That is a detail most proxies discard, and keeping it is the right call for anyone debugging an auth handshake that never completes.
Installing mcpsnoop and wrapping a server for real
The README's first instruction is a demo that needs no configuration, which is a reasonable way to confirm the binary runs before you touch any client config:
mcpsnoop demoFor actual use, the client's MCP config is edited so that mcpsnoop becomes the command and your server command moves behind a `--` separator. Everything after `--` is the command that normally launches the server, so `node build/index.js`, `python server.py` or `npx -y @scope/server` all slot in unchanged:
{
"mcpServers": {
"my-server": {
"command": "mcpsnoop",
"args": ["--", "node", "build/index.js"]
}
}
}On Claude Desktop the edit can be made for you. `mcpsnoop wrap my-server` locates claude_desktop_config.json, copies it to claude_desktop_config.json.mcpsnoop.bak the first time, and rewrites only that one server's entry, leaving formatting and every other server alone; inside the rewritten entry the keys come back in alphabetical order. `mcpsnoop unwrap my-server` restores the file and removes the backup once no server is wrapped. Restart Claude Desktop after either command, because MCP servers are launched once at startup. Then run `mcpsnoop` with no flags to open the UI and use your client as usual.
For a streamable-HTTP server, the reverse proxy form takes a target and a listen address:
mcpsnoop http --target http://localhost:3000/mcp --listen :7000The status of each response appears in the stream, and the TUI accepts filters such as `status:401` or `status:err`. A 4xx or 5xx counts as an error, so a default `mcpsnoop check` run fails on it. The README does not document a rollback path for the HTTP mode, because there is nothing to roll back: you stop the proxy and point the client at the original URL.
Prometheus metrics, and the authentication that is not there
A headless hub can expose live tool-call metrics on a separate listener, which is disabled unless the flag is given:
mcpsnoop --metrics-listen 127.0.0.1:9464
curl http://127.0.0.1:9464/metricsThe public series are `mcpsnoop_tool_calls_total`, `mcpsnoop_tool_errors_total`, `mcpsnoop_tool_call_duration_seconds` and `mcpsnoop_transport_errors_total`. Every series carries `server`, `server_id` and `tool` labels; `server_id` is a short fingerprint of the recorded server identity, so two servers sharing a label stay separate without exposing commands, paths, endpoints or session IDs. Error counters add `error_type`, either `tool` for `result.isError` or `protocol` for a JSON-RPC or protocol-level failure. The histogram exports the standard `_bucket`, `_sum` and `_count` series with 0.005 through 10 second buckets plus `+Inf`.
The README states plainly that the endpoint has no authentication and that anything able to reach the address gets the tool names of every server the hub is watching. It uses `127.0.0.1` in the example for that reason and warns that binding `:9464` publishes those names to the network. Two bounds keep the label from being attacker-controlled: a tool name over 128 bytes is truncated, and past two thousand distinct series per hub the remainder are counted under `tool="(over-series-cap)"`. The README gives the motivation, noting that one 4 MiB name measured out at a 71 MB response, which Prometheus drops whole. A restart resets the counters, so this is a live view, not a store of record.
Where mcpsnoop is the wrong tool
The limitations follow from the architecture. Because mcpsnoop is a proxy, it must be in the launch path. A server you cannot restart, a client whose config you cannot edit, or a hosted MCP endpoint you do not control cannot be wrapped, and the HTTP mode still requires you to point the client at a different URL. Debugging a third party's client behaviour without altering it is outside what this does.
Metrics are unauthenticated by design and reset on restart, so the endpoint is unsuitable as a long-term record or for anything reachable from an untrusted network. Error attribution is also partial: `mcpsnoop_tool_errors_total` covers failures arriving as a JSON-RPC error or as `result.isError`, but a failure that never became a JSON-RPC message, such as a 502 from a gateway or a 401 challenge, cannot be attributed to a tool because nothing in the response says which request it answered. Those land in `mcpsnoop_transport_errors_total` with a status instead. If per-tool error rates are what you need, that gap matters.
The tool is also young. The last push was on 2026-09-11, and releases v0.20.0 through v0.22.0 landed in the weeks before that, so the interface is still moving. The Makefile comments describe a deliberate effort to pin the analyser, the timezone and the shellcheck version so that `make check` matches CI, which suggests the project has been burned by environment drift before. That is a good sign for contributors and no guarantee of API stability for anyone scripting against the CLI.
How it differs from MCP Inspector
The comparison the README draws is with the official MCP Inspector, and the difference is structural rather than cosmetic. The Inspector is a client. It connects to your server and sends its own requests, which is excellent for exercising a server and useless for observing a client you do not control. mcpsnoop is a proxy. It observes the traffic that already exists, which means it can show a call the model never made, or a call made with the wrong arguments, because absence and misconstruction are visible in a stream of real traffic and invisible to a synthetic client.
The trade is that mcpsnoop must be installed into the path it observes. The Inspector needs only a server address. If you are developing a server and want to poke at its capabilities, the Inspector is the lighter instrument. If you are diagnosing why your assistant did not call the tool you expected, you need something in the data path, and that is the category mcpsnoop occupies. The GitHub Action extends the same idea to CI: it checks a captured session, files findings as code scanning alerts, and fails the job on what you gated on, with `session: artifacts/session.jsonl` as the input in the README's example.
Editorial conclusion
Adopt mcpsnoop if you are debugging a real client against a real MCP server and need to see the frames the client actually sends, or if you want captured sessions checked in CI through the GitHub Action. Do not adopt it if you need an authenticated metrics endpoint, a durable store of record, or a tool that inspects other clients without becoming part of their launch command. Before wrapping anything, verify the backup file claude_desktop_config.json.mcpsnoop.bak exists after mcpsnoop wrap, and check whether the metrics listener is bound to 127.0.0.1 or to a wider address, because the endpoint has no authentication.
Frequently asked questions
How do I install mcpsnoop and start it for the first time?
The README's quick start is to run `mcpsnoop demo`, which shows the tool with nothing to set up. For real use you wrap your server command in your client's MCP config, or use `mcpsnoop wrap my-server` on Claude Desktop, then run bare `mcpsnoop` to open the UI.
Does mcpsnoop work with Cursor, Claude Code and Codex?
The README names Cursor, Claude Code and Codex as the clients whose real traffic the proxy is meant to show, and it documents an automatic `wrap` command specifically for Claude Desktop. Any client that launches MCP servers from a command entry can be configured the same way by hand.
Is the mcpsnoop Prometheus metrics endpoint authenticated?
No. The README states that the endpoint has no authentication and that anything able to reach the address gets the tool names of every server the hub is watching, which is why the example binds 127.0.0.1:9464. Binding :9464 publishes those names to the network.
Community notes