{"id":51631550,"url":"https://github.com/kerlenton/mcpsnoop","last_synced_at":"2026-07-15T03:00:34.039Z","repository":{"id":367913782,"uuid":"1282103176","full_name":"kerlenton/mcpsnoop","owner":"kerlenton","description":"Wireshark for MCP. A transparent proxy that shows every real tool call between your AI client and your MCP servers, live in your terminal.","archived":false,"fork":false,"pushed_at":"2026-07-07T11:08:21.000Z","size":4597,"stargazers_count":217,"open_issues_count":4,"forks_count":11,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-07-07T12:19:03.090Z","etag":null,"topics":["bubbletea","claude","cli","codex","cursor","debugging","devtools","golang","mcp","model-context-protocol","proxy","terminal","tui"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kerlenton.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-27T10:25:09.000Z","updated_at":"2026-07-07T11:20:34.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kerlenton/mcpsnoop","commit_stats":null,"previous_names":["kerlenton/mcpsnoop"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/kerlenton/mcpsnoop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kerlenton%2Fmcpsnoop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kerlenton%2Fmcpsnoop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kerlenton%2Fmcpsnoop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kerlenton%2Fmcpsnoop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kerlenton","download_url":"https://codeload.github.com/kerlenton/mcpsnoop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kerlenton%2Fmcpsnoop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35488230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-15T02:00:06.706Z","response_time":131,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bubbletea","claude","cli","codex","cursor","debugging","devtools","golang","mcp","model-context-protocol","proxy","terminal","tui"],"created_at":"2026-07-13T08:00:23.698Z","updated_at":"2026-07-15T03:00:34.032Z","avatar_url":"https://github.com/kerlenton.png","language":"Go","funding_links":[],"categories":["claude","MCP 服务器精选列表"],"sub_categories":["💻 开发与代码执行"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/png/mcpsnoop-lockup.png\" alt=\"mcpsnoop\" width=\"440\"\u003e\n\u003c/p\u003e\n\n**Wireshark for MCP.** A transparent proxy that shows every real tool call\nbetween your AI client and your MCP servers, live in your terminal.\n\n[![CI](https://github.com/kerlenton/mcpsnoop/actions/workflows/ci.yml/badge.svg)](https://github.com/kerlenton/mcpsnoop/actions/workflows/ci.yml)\n[![Go Reference](https://pkg.go.dev/badge/github.com/kerlenton/mcpsnoop.svg)](https://pkg.go.dev/github.com/kerlenton/mcpsnoop)\n[![MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/demo.gif\" alt=\"mcpsnoop demo\"\u003e\n\u003c/p\u003e\n\n## The problem\n\nThe official [MCP Inspector](https://github.com/modelcontextprotocol/inspector)\nconnects as its own client, so it never sees what *your* client (Cursor, Claude\nCode, Codex) actually sends your server. And anything that waits for a request\nto arrive can't show the call the model never made, or made with the wrong\narguments. When a tool silently isn't called, capabilities don't line up, or a\ncall just hangs, you're left digging through logs and guessing.\n\n**mcpsnoop sits in the real data path instead.** Wrap your server command with\nit and watch every JSON-RPC frame live, as your real client and server talk.\n\n## Quick start\n\nSee it right away, with nothing to set up.\n\n```bash\nmcpsnoop demo\n```\n\nTo use it for real, wrap your server in your client's MCP config.\n\n```json\n{\n  \"mcpServers\": {\n    \"my-server\": {\n      \"command\": \"mcpsnoop\",\n      \"args\": [\"--\", \"node\", \"build/index.js\"]\n    }\n  }\n}\n```\n\nEverything after `--` is the command that normally launches your server. Swap in\nwhatever you already use, like `python server.py`, `npx -y @scope/server`, or a\ncompiled binary. Then use your client as usual and open the UI.\n\n```bash\nmcpsnoop\n```\n\nNo flags, no socket paths, no startup order to remember. The shim and the UI find\neach other on their own, and the UI backfills past sessions from disk.\n\nFor a streamable-HTTP server, run mcpsnoop as a reverse proxy.\n\n```bash\nmcpsnoop http --target http://localhost:3000/mcp --listen :7000\n```\n\nNo server of your own? [Try it for real](docs/TRY_IT.md) against a published\ntest server, driven by your own client. To inspect a session after it happened,\nsee [review past sessions from logs](docs/POST_MORTEM.md).\n\n### Config file\n\nIf you reuse the same shim flags across a project, put them in a\n`.mcpsnoop.toml` file in the current working directory.\n\n```toml\nlabel = \"filesystem\"\ntrace-file = \"trace.jsonl\"\nredact-secrets = true\nredact-key = \"token,authorization\"\nredact-path = \"$.params.arguments.password\"\nno-trace = false\n```\n\nThose are all the keys it supports.\n\nThe file is only looked up in the current working directory, not in parent\ndirectories.\n\nExplicit command-line flags override values from the config file.\n\n## Commands\n\n| Command | What it does |\n|---|---|\n| `mcpsnoop -- \u003cserver\u003e` | wrap a stdio server as a transparent shim |\n| `mcpsnoop` | open the live TUI |\n| `mcpsnoop http --target \u003curl\u003e` | proxy a streamable-HTTP server |\n| `mcpsnoop export` | render a session to json, html, text, or otlp |\n| `mcpsnoop check` | fail CI on errors, invalid frames, warnings, slow, or hung calls |\n| `mcpsnoop open` | open a saved session in the TUI |\n| `mcpsnoop remote \u003cuser@host\u003e` | print the SSH tunnel command |\n| `mcpsnoop demo` | play a scripted session |\n\nRun `mcpsnoop help` for the full list, or `mcpsnoop help \u003ccommand\u003e` for the flags of one.\n\n## How it compares\n\n| | MCP Inspector | mcpsnoop |\n|---|:---:|:---:|\n| Sees your real client and server traffic | no | yes |\n| Flags slow and hung calls | no | yes |\n| Flags stray output that corrupts the stream | no | yes |\n| Flags malformed JSON-RPC frames | no | yes |\n| Interactive terminal UI | no | yes |\n| Zero-config, no flags or ordering | no | yes |\n| Capability inspector | partial | yes |\n| Replay a captured call | no | yes |\n| Session export (json / html / text / otlp) | no | yes |\n| Single binary, no runtime deps | no | yes |\n\n## Install\n\n### Go\n\n```bash\ngo install github.com/kerlenton/mcpsnoop/cmd/mcpsnoop@latest\n```\n\n### Homebrew\n\n```bash\nbrew install kerlenton/mcpsnoop/mcpsnoop\n```\n\nPrebuilt binaries for every platform are on the [Releases](https://github.com/kerlenton/mcpsnoop/releases) page.\n\n### Shell completions\n\nmcpsnoop ships completions for bash, zsh, fish, and PowerShell. Run\n`mcpsnoop completion \u003cshell\u003e --help` for the setup steps, which cover enabling\ncompletion and the install path for your OS.\n\n## How it works\n\n\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"assets/architecture-dark.svg\"\u003e\n    \u003cimg alt=\"mcpsnoop sits in the pipe between your AI client and your MCP servers, copying every JSON-RPC frame to a live terminal UI\" src=\"assets/architecture-light.svg\" width=\"760\"\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\nmcpsnoop is two roles in one binary. `mcpsnoop -- \u003cserver\u003e` is the transparent\nshim your client spawns, forwarding bytes verbatim while shipping a copy of every\nframe to the hub. `mcpsnoop` with no arguments is that hub and its live TUI. They\npair through a well-known socket and on-disk logs, so neither has to start first.\n\nBecause it sits in the actual pipe, not off to the side like the Inspector, it\nsees exactly what your real client and server say to each other, whatever the\nserver is written in.\n\n## Keybindings\n\n| Key | Action | | Key | Action |\n|---|---|---|---|---|\n| `enter` | inspect / drill in | | `/` | filter |\n| `esc` | back | | `:` | command |\n| `j` / `k` | move | | `r` | replay a call |\n| `g` / `G` | top / bottom | | `c` | capabilities |\n| `ctrl-f` / `ctrl-b` | page | | `y` | copy |\n| `shift`+`\u003ckey\u003e` | sort by column | | `e` | export |\n| `p` | pause | | `ctrl-d` | delete session |\n| `f` | follow | | `?` | help |\n\nPress `?` in the app for the full list.\n\n## Filtering the stream\n\nPress `/` in a session and combine space-separated tokens, ANDed. Plain text\nmatches the method, tool, id, and payload.\n\n| Token | Filters by | Example |\n|---|---|---|\n| `tool:` | tool name | `tool:search` |\n| `method:` | JSON-RPC method | `method:tools/call` |\n| `id:` | request id | `id:7` |\n| `dir:` | direction (`c2s`, `s2c`) | `dir:s2c` |\n| `kind:` | frame type (`req`, `resp`, `notify`, `stderr`, `invalid`) | `kind:invalid` |\n| `status:` | call outcome (`ok`, `error`, `slow`, `pending`, `bad`, `warn`) | `status:slow` |\n\nStack tokens to get specific.\n\n```text\ntool:search status:slow           # slow calls to one search tool\nmethod:tools/call status:error    # tool calls that failed\ndir:s2c kind:req                  # server-initiated requests (sampling, roots)\n```\n\n## Exporting sessions\n\nTurn any captured session into a portable file.\n\n```bash\nmcpsnoop export -T json|html|text|otlp [-o file|-] [session-id|log.jsonl|-]\n```\n\n| Format | What you get |\n|---|---|\n| `json` | correlated calls, durations, status, tool-level `isError`, capabilities, and raw frames |\n| `html` | a self-contained browser file with search and collapsible JSON |\n| `text` | a pretty plain-text dump |\n| `otlp` | OTLP JSON with a trace per session and a span per correlated call |\n\n```bash\nmcpsnoop export -T html -o out.html       # an HTML file to open in a browser\nmcpsnoop export -T text server.py-48213   # a specific session, as text\nmcpsnoop export -T json | jq              # the newest session, piped to jq\nmcpsnoop export -T otlp -o trace.json     # import into an OTLP-compatible tracing backend\n```\n\nOmit `-o` to write to stdout, and omit the session to take the newest, or pass\n`-` to read JSONL from stdin. In the TUI, press `e` to export the selected\nsession as HTML, or run `:export json|html|text|otlp [path]` from command mode.\n\n## Checking sessions in CI\n\nGate a recorded agent run on errors, stream corruption, protocol warnings, slow\ncalls, or calls that never got a response.\n\n```bash\nmcpsnoop check [--fail-on error,invalid,warn,slow,pending] [--slow-threshold 1s] [session-id|log.jsonl|-]\n```\n\nThe three default signals (error, invalid, warn) fail the check. Add `slow` to\ngate on calls longer than `--slow-threshold`, one second by default, and\n`pending` to gate on calls that never got a response. Pass a comma-separated\nsubset to select only the conditions relevant to a job. Omit the session to\ncheck the newest capture, or use `-` to read JSONL from stdin.\n\n```bash\nmcpsnoop check build-agent\nmcpsnoop check --fail-on error,invalid artifacts/session.jsonl\nmcpsnoop check --fail-on error,slow --slow-threshold 2s - \u003c trace.jsonl\n```\n\n## Watching from another machine\n\nKeep capture local to the machine where the traffic happens and use SSH for the\nnetwork hop, so mcpsnoop never needs a remote transport of its own.\n\n### Live view\n\nRun the TUI on your workstation and forward the remote machine's mcpsnoop socket\nback to it. The live tunnel uses SSH Unix-socket forwarding, so both ends must\nrun Linux or macOS. On Windows, use the post-mortem log copy below.\n\n```bash\n# on your workstation, start the TUI\nmcpsnoop\n\n# create the remote socket directory once\nssh remote-user@remote-host 'mkdir -p ~/.local/state/mcpsnoop'\n\n# print the tunnel command, then run the printed ssh -R line\nmcpsnoop remote remote-user@remote-host\n\n# on the remote host, wrap your server as usual\nmcpsnoop -- node build/index.js\n```\n\nThe socket lives under the remote's state directory, resolved as `MCPSNOOP_HOME`,\nelse `XDG_STATE_HOME/mcpsnoop`, else `~/.local/state/mcpsnoop`. By default mcpsnoop\nassumes the Linux home `/home/\u003cuser\u003e` from your `user@host` and prints a reminder\nto stderr whenever it falls back to that guess. If the remote resolves elsewhere,\nname the one non-default piece.\n\n```bash\n# a non-Linux or custom home, macOS is /Users/\u003cuser\u003e and root is /root\nmcpsnoop remote --remote-home /Users/remote-user remote-user@remote-host\n\n# an explicit MCPSNOOP_HOME on the remote\nmcpsnoop remote --remote-mcpsnoop-home /srv/mcpsnoop remote-user@remote-host\n\n# an explicit XDG_STATE_HOME on the remote\nmcpsnoop remote --remote-xdg-state-home /var/lib/state remote-user@remote-host\n```\n\n### Post-mortem\n\nStream a remote session straight into the TUI over SSH, no local copy needed.\n\n```bash\nssh remote-user@remote-host 'cat ~/.local/state/mcpsnoop/sessions/session.jsonl' | mcpsnoop open -\n```\n\nTo keep a local copy instead, scp the logs into your sessions directory and run\nthe TUI as normal.\n\n```bash\n# copy the remote logs into your local sessions directory\nmkdir -p ~/.local/state/mcpsnoop/sessions\nscp remote-user@remote-host:'~/.local/state/mcpsnoop/sessions/*.jsonl' \\\n  ~/.local/state/mcpsnoop/sessions/\n\n# open the TUI, it backfills the copied sessions\nmcpsnoop\n```\n\n## Security\n\nmcpsnoop runs the server command you wrap, so only wrap servers you trust, and\nrun untrusted ones in a container. It never executes anything you didn't put in\nyour client config.\n\nCaptured frames can include prompts, tool arguments, credentials, and tool\nresults. If payloads can carry secrets, opt in to redaction to scrub the\nobserved trace copies while the proxied bytes still pass through unchanged.\nKey-based redaction replaces whole values under matching JSON object keys.\nPath-based redaction replaces only values selected by a JSONPath expression,\nwhich is useful when a common key name is sensitive in one location but safe in\nanother. Repeat `--redact-path` to scrub more than one location.\nValue-based redaction applies regular expressions to observed string values,\nstderr text, and non-JSON text frames. All redaction modes are best effort.\nRegexes can miss secrets, overmatch harmless text, or fail to see transformed\nor encoded values.\n\n```bash\n# built-in preset of common secret keys\nmcpsnoop --redact-secrets -- node build/index.js\n\n# or name your own keys\nmcpsnoop --redact-key token,api_key,password -- node build/index.js\n\n# scrub one location without redacting every field named password\nmcpsnoop --redact-path '$.params.arguments.password' -- node build/index.js\n\n# wildcards scrub every matching array element\nmcpsnoop --redact-path '$.params.arguments.accounts[*].password' -- node build/index.js\n\n# scrub obvious token-shaped values outside known keys\nmcpsnoop --redact-value 'sk-[A-Za-z0-9]+' -- node build/index.js\n\n# combine the layers in http mode\nmcpsnoop http --target http://localhost:3000/mcp --redact-secrets --redact-value 'Bearer\\s+\\S+'\n```\n\nFor remote workflows, use SSH tunnelling or SSH file transfer so transport auth,\nencryption, host verification, key rotation, and audit policy stay in your\nexisting SSH setup.\n\n## Contributing\n\nIssues and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for\nthe details.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkerlenton%2Fmcpsnoop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkerlenton%2Fmcpsnoop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkerlenton%2Fmcpsnoop/lists"}