
Wireshark per MCP. Un proxy trasparente tra il tuo client AI e il server MCP. Osserva ogni chiamata in tempo reale nel tuo terminale, fai fallire la CI in base a ciò che rileva, esporta span OpenTelemetry.
<p align="center"> <img src="https://assets.kitploit.com/production/public/readmes/9109/91d664ea266713affb29238906792777021b43fa6627b13f46382f48ad340a61.png" alt="mcpsnoop" width="440"> </p> **Wireshark per MCP.** mcpsnoop si colloca tra il tuo client AI e il tuo server MCP e registra ogni frame JSON-RPC che si scambiano, senza modificare nessuna delle due parti. Osservalo in tempo reale nel tuo terminale, fai fallire la CI in base a ciò che rileva, oppure invialo al tuo backend di tracing come span OpenTelemetry. [](https://github.com/kerlenton/mcpsnoop/actions/workflows/ci.yml) [](https://pkg.go.dev/github.com/kerlenton/mcpsnoop) [](LICENSE) [](https://github.com/marketplace/actions/mcpsnoop) <p align="center"> <img src="https://assets.kitploit.com/production/public/readmes/9109/30466d77be15250e4bab6639e48a4cd5b0d44cd96e48606b60c6bacb67c15c3d.gif" alt="mcpsnoop demo"> </p> ## Il problema L'[MCP Inspector](https://github.com/modelcontextprotocol/inspector) ufficiale si connette come client a sé stante, quindi non vede mai ciò che *il tuo* client (Cursor, Claude Code, Codex) invia effettivamente al tuo server. E qualsiasi strumento che attende l'arrivo di una richiesta non può mostrare la chiamata che il modello non ha mai effettuato, o che ha effettuato con argomenti errati. Quando uno strumento non viene chiamato silenziosamente, le capacità non corrispondono, o una chiamata si blocca, ti ritrovi a scavare nei log e a tirare a indovinare. **mcpsnoop si colloca invece nel percorso reale dei dati.** Avvolgi il comando del tuo server con esso e osserva ogni frame JSON-RPC in tempo reale, mentre il tuo client e il tuo server reali comunicano. ## In CI Questa pagina è anche la scheda della [GitHub Action mcpsnoop](https://github.com/marketplace/actions/mcpsnoop), quindi eccola per intero. Verifica una sessione catturata, registra ogni rilevamento come avviso di code scanning e fa fallire il job in base a ciò su cui hai impostato il controllo. ```yaml permissions: security-events: write contents: read steps: - uses: kerlenton/[email protected] with: session: artifacts/session.jsonl ``` Non hai una cattura a portata di mano? Registra una sessione con il tuo client una volta, esegui il commit e lascia che l'action la riproduca su ogni build. Nessun modello e nessuna chiave API vengono eseguiti in CI. La riproduzione viene verificata come qualsiasi cattura, e il job fallisce anche quando il server peggiora rispetto alla registrazione. Un server raggiunto tramite Streamable HTTP riceve `target` con il suo endpoint, e una registrazione viene riprodotta su entrambi i trasporti. ```yaml steps: - uses: kerlenton/[email protected] with: replay: tests/mcp/claude-code-session.jsonl server: node dist/index.js ``` Fissa la release che preferisci. La più recente è nella [pagina delle release](https://github.com/kerlenton/mcpsnoop/releases). Ogni input e output è in [The GitHub Action](#the-github-action) più in basso, e ogni segnale sul quale il controllo può fallire è in [docs/CI.md](https://github.com/kerlenton/mcpsnoop/blob/main/docs/CI.md). ## OpenTelemetry La revisione MCP 2026-07-28 depreca il Logging a livello di protocollo e indica alle implementazioni di passare a `stderr` su stdio, oppure a OpenTelemetry per un'osservabilità strutturata. mcpsnoop copre entrambi senza toccare il client o il server. Le righe `stderr` di un server stdio compaiono nello stream accanto ai suoi frame, e ogni richiesta diventa uno span che segue le [convenzioni semantiche OpenTelemetry per MCP](https://github.com/open-telemetry/semantic-conventions-genai/tree/main/model/mcp). ```bash mcpsnoop export -T otlp -o trace.json # spans from a capture mcpsnoop --otlp-endpoint http://localhost:4318/v1/traces -- node build/index.js # spans as calls complete ``` Una chiamata a uno strumento arriva come span denominato `tools/call search`, che trasporta `mcp.method.name`, `gen_ai.tool.name` e `error.type`, così finisce in una dashboard costruita per MCP anziché per mcpsnoop. Le metriche live degli strumenti per Prometheus sono a un flag di distanza. Entrambe sono in [docs/OPENTELEMETRY.md](https://github.com/kerlenton/mcpsnoop/blob/main/docs/OPENTELEMETRY.md). ## Avvio rapido Provalo subito, senza alcuna configurazione. ```bash mcpsnoop demo ``` Per un utilizzo reale, inserisci il tuo server nella configurazione MCP del tuo client. ```json { "mcpServers": { "my-server": { "command": "mcpsnoop", "args": ["--", "node", "build/index.js"] } } } ``` Tutto ciò che segue `--` è il comando che normalmente avvia il tuo server. Sostituiscilo con qualsiasi cosa tu già utilizzi, come `python server.py`, `npx -y @scope/server`, o un binario compilato. Su Claude Desktop non devi effettuare questa modifica manualmente. ```bash mcpsnoop wrap my-server # route my-server through mcpsnoop mcpsnoop unwrap my-server # put it back ``` `wrap` trova `claude_desktop_config.json`, lo copia in `claude_desktop_config.json.mcpsnoop.bak` la prima volta, e riscrive solo la voce di quel singolo server, così la tua formattazione e ogni altro server restano intatti. All'interno della voce riscritta le chiavi tornano in ordine alfabetico. `unwrap` ripristina il file e rimuove il backup una volta che nessun server è più wrappato. Riavvia Claude Desktop dopo l'una o l'altra operazione, poiché i server MCP vengono avviati una sola volta all'avvio. Poi usa il tuo client come al solito e apri l'interfaccia utente. ```bash mcpsnoop ``` Nessun flag, nessun percorso di socket, nessun ordine di avvio da ricordare. Lo shim e l'interfaccia utente si trovano da soli, e l'interfaccia utente recupera le sessioni passate dal disco. Per un server streamable-HTTP, esegui mcpsnoop come reverse proxy. ```bash mcpsnoop http --target http://localhost:3000/mcp --listen :7000 ``` Lo stato HTTP di ogni risposta è visibile nello stream, quindi una risposta che non trasporta alcun messaggio JSON-RPC proprio resta comunque un frame visibile anziché nulla. Questo vale per la challenge 401, per il 403 su un Origin rifiutato, per il 202 che conferma una notifica e per il 502 quando il target non è raggiungibile affatto. L'header `WWW-Authenticate` di un 401 viene mantenuto verbatim e mostrato nell'inspector, poiché indica lo schema di autenticazione e i metadati della risorsa a cui rivolgersi successivamente. Filtra per stato con `status:401` nella TUI, oppure per qualsiasi errore con `status:err`. Un 4xx o 5xx conta come errore, quindi un'esecuzione predefinita di `mcpsnoop check` fallisce in tal caso, e la chiamata a cui ha risposto risulta fallita anziché ancora in attesa. Nessun server tuo? [Provalo davvero](https://github.com/kerlenton/mcpsnoop/blob/main/docs/TRY_IT.md) contro un server di test pubblico, pilotato dal tuo client. Per ispezionare una sessione dopo che si è verificata, vedi [rivedere sessioni passate dai log](https://github.com/kerlenton/mcpsnoop/blob/main/docs/POST_MORTEM.md). ## Installazione ### npm Nessuna toolchain Go necessaria. La maggior parte dei server MCP è scritta in Node o Python, quindi questa è la via più breve. ```bash npx mcpsnoop -- node build/index.js ``` Il pacchetto npm non contiene codice proprio. Sei pacchetti di piattaforma contengono ciascuno una build, e npm installa quello singolo che corrisponde alla tua macchina, quindi non c'è nulla da scaricare al momento dell'installazione e nulla da sbloccare in un proxy. Per mantenerlo disponibile invece di scaricarlo a ogni esecuzione, `npm i -g mcpsnoop`. ### Homebrew ```bash brew install mcpsnoop ``` ### Go ```bash go install github.com/kerlenton/mcpsnoop/cmd/mcpsnoop@latest ``` I binari precompilati per ogni piattaforma sono disponibili nella pagina [Releases](https://github.com/kerlenton/mcpsnoop/releases). mcpsnoop include i completamenti per bash, zsh, fish e PowerShell. Esegui `mcpsnoop completion <shell> --help` per i passaggi di configurazione, che coprono l'abilitazione dei completamenti e il percorso di installazione per il tuo sistema operativo. ## Comandi | Comando | Cosa fa | |---|---| | `mcpsnoop -- <server>` | avvolge un server stdio come shim trasparente | | `mcpsnoop` | apre la TUI live | | `mcpsnoop --metrics-listen <addr>` | esegue un hub headless ed espone metriche Prometheus live | | `mcpsnoop http --target <url>` | fa da proxy per un server streamable-HTTP | | `mcpsnoop export` | esporta una sessione in json, html, text, har o otlp | | `mcpsnoop check` | fa fallire la CI in caso di errori, frame non validi, avvisi come un risultato di uno strumento che viola il proprio outputSchema, disallineamenti di routing, chiamate bloccate, risultati in ritardo, chiamate che potrebbero essere state eseguite due volte, drift degli strumenti, annotazioni che si sono allentate o non dicono nulla, o un budget di latenza | | `mcpsnoop baseline` | ispeziona, accetta o reimposta le definizioni degli strumenti considerate attendibili | | `mcpsnoop diff` | confronta strumenti e chiamate tra due sessioni catturate | | `mcpsnoop open` | apre una sessione salvata nella TUI | | `mcpsnoop mock <session>` | ripropone una sessione catturata come server MCP stdio | | `mcpsnoop replay <session> -- <server>` | pilota un server, via stdio o Streamable HTTP, con il lato client di una sessione registrata, e confronta il risultato con la registrazione | | `mcpsnoop inventory` | elenca ogni server che è stato eseguito tramite mcpsnoop su questa macchina | | `mcpsnoop stats` | aggrega ogni cattura memorizzata in una riga per server e strumento | | `mcpsnoop clients` | mostra cosa ha effettivamente fatto ogni client MCP sulla rete, per nome e versione | | `mcpsnoop prune` | elimina i log delle sessioni salvate più vecchi di una data limite | | `mcpsnoop wrap <server>` | instrada uno dei server di Claude Desktop attraverso mcpsnoop | | `mcpsnoop unwrap <server>` | ripristina la voce di quel server allo stato originale | | `mcpsnoop remote <user@host>` | stampa il comando del tunnel SSH | | `mcpsnoop demo` | riproduce una sessione predefinita | Esegui `mcpsnoop help` per l'elenco completo, oppure `mcpsnoop help <command>` per i flag di un singolo comando. ## Come si confronta Ognuno di questi strumenti risponde a una domanda diversa, e la posizione in cui si colloca un tool determina a quali domande può rispondere. | Strumento | Dove si colloca | A cosa serve | |---|---|---| | [MCP Inspector](https://github.com/modelcontextprotocol/inspector) | un proprio client, connesso al tuo server | provare un server manualmente, in un browser o da una CLI scriptabile | | [Snyk Agent Scan](https://github.com/snyk/agent-scan) | un proprio client, che avvia o si connette ai server nelle tue configurazioni per leggerne gli strumenti | scansionare agenti, server MCP e skill sulla tua macchina alla ricerca di prompt injection e vulnerabilità | | [MCP Observatory](https://github.com/KryptosAI/mcp-observatory) | un proprio client, che avvia il tuo server per testarlo, registrarlo e verificarlo | test di sicurezza e di regressione in CI, con simulazione di attacchi, drift degli schemi e record, replay e verifica | | [mcprec](https://github.com/erphq/mcprec) | sulla rete, tra client e server | registrare una sessione una volta e riprodurla come fixture di test senza la rete | | mcpsnoop | sulla rete, tra client e server | osservare cosa si dicono realmente il tuo client e il tuo server, riprodurre la sessione di un client reale contro ogni build, far fallire la CI su di essa ed esportarla come OpenTelemetry | Uno strumento che è un proprio client vede le chiamate che effettua, non quelle che effettua il tuo client, quindi non può mostrare la chiamata che il tuo modello non ha mai fatto o ha fatto con argomenti sbagliati. Uno scanner legge una definizione prima che tu ti fidi di essa. mcpsnoop osserva cosa succede dopo che ti sei fidato, incluso se la definizione cambia in seguito. ## Come funziona <p align="center"> <picture> <source media="(prefers-color-scheme: dark)" srcset="assets/architecture-dark.svg"> <img alt="mcpsnoop si colloca nel canale tra il tuo client AI e i tuoi server MCP, copiando ogni frame JSON-RPC in una TUI live" src="https://raw.githubusercontent.com/kerlenton/mcpsnoop/HEAD/assets/architecture-light.svg" width="760"> </picture> </p> mcpsnoop è due ruoli in un unico binario. `mcpsnoop -- <server>` è lo shim trasparente che il tuo client avvia, inoltrando i byte verbatim mentre invia una copia di ogni frame all'hub. `mcpsnoop` senza argomenti è quell'hub e la sua TUI live. Si accoppiano tramite un socket ben noto e log su disco, così nessuno dei due deve essere avviato per primo. Poiché si trova nella pipe effettiva, non di lato come l'Inspector, vede esattamente ciò che il tuo client e server reali si dicono, qualunque sia il linguaggio in cui è scritto il server. Ciò che limita la sua memoria e il suo disco è in [docs/HOW_IT_WORKS.md](https://github.com/kerlenton/mcpsnoop/blob/main/docs/HOW_IT_WORKS.md). ## La GitHub Action Tutto quanto segue è ciò che l'action fa per te. Installa mcpsnoop, verifica la cattura, registra i risultati nella scheda Security e fa fallire il job in base a ciò su cui hai impostato il gate. ```yaml permissions: security-events: write contents: read steps: - uses: kerlenton/[email protected] with: session: artifacts/session.jsonl ``` Fissa una release, quella che preferisci. La più recente è sulla [pagina delle release](https://github.com/kerlenton/mcpsnoop/releases). Non esiste una `v1` mobile, di proposito. La release fissata è anche il binario che l'action installa, quindi le due non possono mai discordare e non c'è un default di versione che diventi obsoleto. | Input | | |---|---| | `session` | la cattura `.jsonl` da controllare, o una directory che le contiene, relativa alla radice del repository. Specifica questo o `replay` | | `replay` | una registrazione committata da riprodurre contro `server` o `target`, la cui cattura viene poi controllata e che fa fallire il job anche in caso di regressione | | `server` | il comando che avvia il server sotto test, quotato come su una riga di comando. Richiesto con `replay` per un server stdio. Con `target` avvia prima un server HTTP, e può essere omesso quando ne è già in esecuzione uno | | `target` | l'endpoint Streamable HTTP contro cui riprodurre, come `http://localhost:3000/mcp`. Una credenziale va in `replay-args` come `--header`, e il log dello step mostra il suo valore nascosto | | `replay-args` | qualsiasi altro flag di `replay`, come `--read-only`. `--out` viene rifiutato, poiché è l'action a decidere dove va la cattura | | `fail-on` | come `--fail-on`, con il default della CLI | | `args` | qualsiasi altro flag di `check`, quotato come su una riga di comando. `--format` viene rifiutato, poiché è l'action a leggere il report | | `upload-sarif` | invia il report al code scanning. `true` | | `category` | il namespace del code scanning. `mcpsnoop`. Variailo per ogni gamba di una matrice, altrimenti le gambe si sovrascrivono a vicenda | | `fail-on-findings` | fa fallire il job su un finding. `true`. Imposta `false` per registrare gli alert e lasciare che decida il check richiesto del code scanning | | `version` | quale mcpsnoop installare. Default alla release che hai fissato | | `install` | `false` quando mcpsnoop è già nel PATH, che è il modo per entrare su una piattaforma per cui non è compilata alcuna release | Gli output sono `outcome`, `sarif`, `exit-code` e `capture`, il percorso della cattura che è stata controllata, che con `replay` è quella scritta dal replay e vale la pena conservare come artifact. `outcome` è `passed`, `findings`, o `error`, e il terzo vale la pena gestirlo separatamente. Significa che non è stato controllato nulla, il che non è lo stesso di non aver trovato nulla. **Un'esecuzione che non ha potuto controllare fa fallire il job qualunque cosa dica `fail-on-findings`**, perché una pipeline che diventa verde senza aver verificato nulla è peggio di una che fallisce. Il job necessita di `security-events: write`, altrimenti l'upload risponde 403. Imposta `upload-sarif: false` in un repository senza code scanning. Eseguire lo stesso controllo senza l'action, i segnali su cui può fallire e i codici di uscita sono in [docs/CI.md](https://github.com/kerlenton/mcpsnoop/blob/main/docs/CI.md). ## Documentazione | Pagina | Cosa contiene | |---|---| | [Checking sessions in CI](https://github.com/kerlenton/mcpsnoop/blob/main/docs/CI.md) | riprodurre una registrazione contro ogni build, ogni segnale su cui `check` può fallire, codici di uscita, asserzioni, report JUnit e SARIF, confrontare due sessioni e collegare il tutto senza l'action | | [OpenTelemetry and Prometheus](https://github.com/kerlenton/mcpsnoop/blob/main/docs/OPENTELEMETRY.md) | gli span e cosa trasportano, inviarli in streaming a un collector e metriche live degli strumenti | | [Using mcpsnoop](https://github.com/kerlenton/mcpsnoop/blob/main/docs/USING.md) | chiavi, filtraggio, formati di esportazione, replay, cosa un server ha chiesto al tuo utente, costo in contesto, statistiche tra le catture, cosa invia effettivamente ogni client, l'inventario dei server, macchine remote e il file di configurazione | | [Redaction](https://github.com/kerlenton/mcpsnoop/blob/main/docs/REDACTION.md) | ripulire i segreti, durante la cattura o da una cattura che hai già | | [How it works](https://github.com/kerlenton/mcpsnoop/blob/main/docs/HOW_IT_WORKS.md) | limiti di memoria, il limite della cronologia e la potatura dei vecchi log | | [Try it for real](https://github.com/kerlenton/mcpsnoop/blob/main/docs/TRY_IT.md) | un server di test pubblicato, pilotato dal tuo client | | [Review past sessions](https://github.com/kerlenton/mcpsnoop/blob/main/docs/POST_MORTEM.md) | dove risiedono i log delle sessioni e come aprirne uno a posteriori | | [The capture format](https://github.com/kerlenton/mcpsnoop/blob/main/docs/CAPTURE_FORMAT.md) | cosa contiene ogni riga di un log di sessione e cosa non cambierà mai al riguardo, con un JSON Schema per gli strumenti che leggono le catture | ## Sicurezza mcpsnoop esegue il comando del server che avvolgi, quindi avvolgi solo server di cui ti fidi, ed esegui quelli non attendibili in un container. Non esegue mai nulla che tu non abbia messo nella configurazione del tuo client. Per i flussi di lavoro remoti, utilizzare il tunnelling SSH o il trasferimento file SSH in modo che l'autenticazione del trasporto, la crittografia, la verifica dell'host, la rotazione delle chiavi e i criteri di audit restino nella configurazione SSH esistente. ### Cosa può fare una cattura al tuo terminale Una cattura è un dato scelto dall'altra parte. I frame e le righe di stderr possono contenere sequenze di escape del terminale, e un terminale agisce su qualunque cosa gli venga consegnata, il che va da una visualizzazione confusa fino a OSC 52 che scrive negli appunti di sistema. mcpsnoop conserva solo le sequenze di colore che genera esso stesso e scarta ogni altro escape prima che un frame raggiunga il tuo terminale. Le celle della tabella citano i caratteri di controllo così puoi vedere che erano presenti, l'inspector li esplicita per intero, e la copia negli appunti riporta la forma con escape, così nulla ti è nascosto e nulla viene eseguito. ### Cosa contiene una cattura I frame catturati possono includere prompt, argomenti degli strumenti, credenziali e risultati degli strumenti. [docs/REDACTION.md](https://github.com/kerlenton/mcpsnoop/blob/main/docs/REDACTION.md) illustra come ripulirli, durante o dopo la cattura. Per segnalare una vulnerabilità, consulta [SECURITY.md](https://github.com/kerlenton/mcpsnoop/blob/main/SECURITY.md). ## Contribuire Issue e pull request sono benvenute. Consulta [CONTRIBUTING.md](https://github.com/kerlenton/mcpsnoop/blob/main/CONTRIBUTING.md) per i dettagli. ## Licenza [MIT](https://github.com/kerlenton/mcpsnoop/blob/main/LICENSE)