
Wireshark pour MCP. Un proxy transparent entre votre client IA et le serveur MCP. Observez chaque appel en direct dans votre terminal, faites échouer la CI sur ce qu'il détecte, exportez les spans OpenTelemetry.
<p align="center"> <img src="https://assets.kitploit.com/production/public/readmes/9109/91d664ea266713affb29238906792777021b43fa6627b13f46382f48ad340a61.png" alt="mcpsnoop" width="440"> </p> **Wireshark pour MCP.** mcpsnoop s'intercale entre votre client IA et votre serveur MCP et enregistre chaque trame JSON-RPC qu'ils échangent, sans modifier ni l'un ni l'autre. Observez-le en direct dans votre terminal, faites échouer la CI sur ce qu'il détecte, ou envoyez-le à votre backend de traçage sous forme de spans 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="démo mcpsnoop"> </p> ## Le problème L'[MCP Inspector](https://github.com/modelcontextprotocol/inspector) officiel se connecte en tant que client à part entière, il ne voit donc jamais ce que *votre* client (Cursor, Claude Code, Codex) envoie réellement à votre serveur. Et tout ce qui attend qu'une requête arrive ne peut pas montrer l'appel que le modèle n'a jamais effectué, ou qu'il a effectué avec les mauvais arguments. Quand un outil n'est silencieusement pas appelé, que les capacités ne correspondent pas, ou qu'un appel reste bloqué, vous vous retrouvez à fouiller les journaux et à deviner. **mcpsnoop s'installe à la place dans le véritable chemin des données.** Enveloppez votre commande de serveur avec lui et observez chaque trame JSON-RPC en direct, pendant que votre véritable client et votre serveur dialoguent. ## En CI Cette page sert aussi de fiche pour la [GitHub Action mcpsnoop](https://github.com/marketplace/actions/mcpsnoop), en voici donc l'intégralité. Elle vérifie une session capturée, consigne chaque constat comme une alerte d'analyse de code, et fait échouer la tâche sur ce que vous avez défini comme critère. ```yaml permissions: security-events: write contents: read steps: - uses: kerlenton/[email protected] with: session: artifacts/session.jsonl ``` Pas de capture sous la main ? Enregistrez une session avec votre propre client une fois, validez-la, et laissez l'action la rejouer contre chaque build. Aucun modèle et aucune clé API ne s'exécutent en CI. La relecture est vérifiée comme n'importe quelle capture, et la tâche échoue également lorsque le serveur s'est dégradé par rapport à l'enregistrement. Un serveur atteint via Streamable HTTP reçoit `target` avec son endpoint, et un enregistrement se rejoue sur l'un ou l'autre transport. ```yaml steps: - uses: kerlenton/[email protected] with: replay: tests/mcp/claude-code-session.jsonl server: node dist/index.js ``` Épinglez la version que vous souhaitez. La plus récente se trouve sur la [page des releases](https://github.com/kerlenton/mcpsnoop/releases). Chaque entrée et sortie est décrite dans [The GitHub Action](#the-github-action) plus bas, et chaque signal sur lequel la vérification peut échouer se trouve dans [docs/CI.md](https://github.com/kerlenton/mcpsnoop/blob/main/docs/CI.md). ## OpenTelemetry La révision MCP 2026-07-28 déprécie le Logging au niveau du protocole et indique aux implémentations de passer à `stderr` sur stdio, ou à OpenTelemetry pour une observabilité structurée. mcpsnoop couvre les deux sans toucher au client ni au serveur. Les lignes `stderr` d'un serveur stdio apparaissent dans le flux à côté de ses trames, et chaque requête devient un span qui suit les [conventions sémantiques OpenTelemetry pour 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 ``` Un appel d'outil arrive sous la forme d'un span nommé `tools/call search`, portant `mcp.method.name`, `gen_ai.tool.name` et `error.type`, de sorte qu'il atterrit dans un tableau de bord conçu pour MCP plutôt que pour mcpsnoop. Les métriques d'outils en direct pour Prometheus sont à un flag près. Les deux sont dans [docs/OPENTELEMETRY.md](https://github.com/kerlenton/mcpsnoop/blob/main/docs/OPENTELEMETRY.md). ## Démarrage rapide Voyez-le immédiatement, sans rien à configurer. ```bash mcpsnoop demo ``` Pour l'utiliser réellement, encapsulez votre serveur dans la configuration MCP de votre client. ```json { "mcpServers": { "my-server": { "command": "mcpsnoop", "args": ["--", "node", "build/index.js"] } } } ``` Tout ce qui suit `--` est la commande qui lance normalement votre serveur. Remplacez-la par ce que vous utilisez déjà, comme `python server.py`, `npx -y @scope/server`, ou un binaire compilé. Sur Claude Desktop, vous n'avez pas besoin de faire cette modification à la main. ```bash mcpsnoop wrap my-server # route my-server through mcpsnoop mcpsnoop unwrap my-server # put it back ``` `wrap` trouve `claude_desktop_config.json`, le copie vers `claude_desktop_config.json.mcpsnoop.bak` la première fois, et ne réécrit que l'entrée de ce seul serveur, de sorte que votre mise en forme et tous les autres serveurs restent intacts. À l'intérieur de l'entrée réécrite, les clés reviennent dans l'ordre alphabétique. `unwrap` restaure le fichier, et supprime la sauvegarde une fois qu'aucun serveur n'est plus enveloppé. Redémarrez Claude Desktop après l'une ou l'autre opération, car les serveurs MCP sont lancés une seule fois au démarrage. Utilisez ensuite votre client comme d'habitude et ouvrez l'interface. ```bash mcpsnoop ``` Aucun flag, aucun chemin de socket, aucun ordre de démarrage à mémoriser. Le shim et l'interface se trouvent d'eux-mêmes, et l'interface récupère les sessions passées depuis le disque. Pour un serveur HTTP streamable, exécutez mcpsnoop en tant que proxy inverse. ```bash mcpsnoop http --target http://localhost:3000/mcp --listen :7000 ``` Le statut HTTP de chaque réponse apparaît dans le flux, de sorte qu'une réponse qui ne porte aucun message JSON-RPC propre reste une trame visible plutôt que rien. Cela couvre le défi 401, le 403 sur une Origin rejetée, le 202 qui accuse réception d'une notification, et le 502 lorsque la cible est totalement inaccessible. L'en-tête `WWW-Authenticate` d'une réponse 401 est conservé verbatim et affiché dans l'inspecteur, puisqu'il nomme le schéma d'authentification et les métadonnées de ressource vers lesquelles se diriger ensuite. Filtrez par statut avec `status:401` dans la TUI, ou par n'importe quel échec avec `status:err`. Un 4xx ou 5xx compte comme une erreur, donc une exécution par défaut de `mcpsnoop check` échoue dessus, et l'appel auquel il a répondu est considéré comme échoué plutôt que comme encore en attente. Pas de serveur à vous ? [Essayez-le pour de vrai](https://github.com/kerlenton/mcpsnoop/blob/main/docs/TRY_IT.md) contre un serveur de test publié, piloté par votre propre client. Pour inspecter une session après coup, voir [revoir les sessions passées à partir des logs](https://github.com/kerlenton/mcpsnoop/blob/main/docs/POST_MORTEM.md). ## Installation ### npm Aucune chaîne d'outils Go nécessaire. La plupart des serveurs MCP sont écrits en Node ou en Python, c'est donc le chemin le plus court. ```bash npx mcpsnoop -- node build/index.js ``` Le paquet npm ne contient aucun code propre. Six paquets de plateforme contiennent chacun une compilation, et npm installe celui qui correspond à votre machine, il n'y a donc rien à télécharger au moment de l'installation et rien à débloquer dans un proxy. Pour le conserver plutôt que de le récupérer à chaque exécution, `npm i -g mcpsnoop`. ### Homebrew ```bash brew install mcpsnoop ``` ### Go ```bash go install github.com/kerlenton/mcpsnoop/cmd/mcpsnoop@latest ``` Des binaires précompilés pour chaque plateforme sont disponibles sur la page [Releases](https://github.com/kerlenton/mcpsnoop/releases). mcpsnoop fournit des complétions pour bash, zsh, fish et PowerShell. Exécutez `mcpsnoop completion <shell> --help` pour les étapes de configuration, qui couvrent l'activation de la complétion et le chemin d'installation pour votre OS. ## Commandes | Commande | Ce qu'elle fait | |---|---| | `mcpsnoop -- <server>` | enveloppe un serveur stdio comme un shim transparent | | `mcpsnoop` | ouvre l'interface TUI en direct | | `mcpsnoop --metrics-listen <addr>` | lance un hub sans interface et expose des métriques Prometheus en direct | | `mcpsnoop http --target <url>` | fait office de proxy pour un serveur streamable-HTTP | | `mcpsnoop export` | rend une session en json, html, text, har ou otlp | | `mcpsnoop check` | fait échouer la CI en cas d'erreurs, de trames invalides, d'avertissements tels qu'un résultat d'outil qui enfreint son propre outputSchema, d'incohérences de routage, d'appels bloqués, de résultats tardifs, d'appels susceptibles d'avoir été exécutés deux fois, de dérive des outils, d'annotations qui se sont relâchées ou ne disent rien, ou d'un budget de latence | | `mcpsnoop baseline` | inspecte, accepte ou réinitialise les définitions d'outils de confiance | | `mcpsnoop diff` | compare les outils et les appels entre deux sessions capturées | | `mcpsnoop open` | ouvre une session enregistrée dans l'interface TUI | | `mcpsnoop mock <session>` | rejoue une session capturée en tant que serveur MCP stdio | | `mcpsnoop replay <session> -- <server>` | pilote un serveur, via stdio ou Streamable HTTP, avec le côté client d'une session enregistrée, et compare le résultat avec l'enregistrement | | `mcpsnoop inventory` | liste tous les serveurs qui ont été exécutés via mcpsnoop sur cette machine | | `mcpsnoop stats` | regroupe toutes les captures stockées en une ligne par serveur et par outil | | `mcpsnoop clients` | montre ce que chaque client MCP a réellement fait sur le réseau, par nom et version | | `mcpsnoop prune` | supprime les journaux de session enregistrés antérieurs à une date limite | | `mcpsnoop wrap <server>` | fait passer l'un des serveurs de Claude Desktop par mcpsnoop | | `mcpsnoop unwrap <server>` | rétablit l'entrée de ce serveur telle qu'elle était | | `mcpsnoop remote <user@host>` | affiche la commande de tunnel SSH | | `mcpsnoop demo` | joue une session scénarisée | Exécutez `mcpsnoop help` pour la liste complète, ou `mcpsnoop help <command>` pour les options d'une commande. ## Comparaison Chacun de ces outils répond à une question différente, et la position d'un outil détermine les questions auxquelles il peut répondre. | Outil | Où il se situe | À quoi il sert | |---|---|---| | [MCP Inspector](https://github.com/modelcontextprotocol/inspector) | son propre client, connecté à votre serveur | essayer un serveur à la main, dans un navigateur ou depuis une CLI scriptable | | [Snyk Agent Scan](https://github.com/snyk/agent-scan) | son propre client, lançant ou se connectant aux serveurs de vos configurations pour lire leurs outils | analyser les agents, les serveurs MCP et les skills de votre machine à la recherche d'injections de prompt et de vulnérabilités | | [MCP Observatory](https://github.com/KryptosAI/mcp-observatory) | son propre client, lançant votre serveur pour le tester, l'enregistrer et le vérifier | tests de sécurité et de non-régression en CI, avec simulation d'attaques, dérive de schéma, et enregistrement, rejeu et vérification | | [mcprec](https://github.com/erphq/mcprec) | sur le réseau, entre le client et le serveur | enregistrer une session une fois et la rejouer comme fixture de test sans le réseau | | mcpsnoop | sur le réseau, entre le client et le serveur | observer ce que votre vrai client et votre vrai serveur échangent, rejouer la session d'un vrai client contre chaque build, faire échouer la CI en conséquence, et l'exporter en OpenTelemetry | Un outil qui est son propre client voit les appels qu'il effectue, pas ceux que votre client effectue ; il ne peut donc pas montrer l'appel que votre modèle n'a jamais fait ou qu'il a fait avec les mauvais arguments. Un scanner lit une définition avant que vous ne lui fassiez confiance. mcpsnoop observe ce qui se passe une fois que vous lui faites confiance, y compris si la définition change par la suite. ## Fonctionnement <p align="center"> <picture> <source media="(prefers-color-scheme: dark)" srcset="assets/architecture-dark.svg"> <img alt="mcpsnoop se place dans le flux entre votre client IA et vos serveurs MCP, copiant chaque trame JSON-RPC vers une interface de terminal en direct" src="https://raw.githubusercontent.com/kerlenton/mcpsnoop/HEAD/assets/architecture-light.svg" width="760"> </picture> </p> mcpsnoop remplit deux rôles dans un seul binaire. `mcpsnoop -- <server>` est le shim transparent que votre client lance, transmettant les octets tels quels tout en envoyant une copie de chaque trame au hub. `mcpsnoop` sans argument est ce hub et son TUI en direct. Ils s'apparient via un socket bien connu et des journaux sur disque, de sorte qu'aucun n'a besoin de démarrer en premier. Parce qu'il se trouve dans le véritable pipeline, et non à côté comme l'Inspector, il voit exactement ce que votre véritable client et votre serveur se disent, quel que soit le langage dans lequel le serveur est écrit. Ce qui borne sa mémoire et son disque est décrit dans [docs/HOW_IT_WORKS.md](https://github.com/kerlenton/mcpsnoop/blob/main/docs/HOW_IT_WORKS.md). ## La GitHub Action Tout ce qui suit est ce que l'action fait pour vous. Elle installe mcpsnoop, vérifie la capture, consigne les résultats dans l'onglet Security et fait échouer la tâche selon ce sur quoi vous avez défini un seuil. ```yaml permissions: security-events: write contents: read steps: - uses: kerlenton/[email protected] with: session: artifacts/session.jsonl ``` Épinglez une release, celle que vous voulez. La plus récente se trouve sur la [page des releases](https://github.com/kerlenton/mcpsnoop/releases). Il n'y a pas de `v1` flottant, volontairement. La release épinglée est aussi le binaire que l'action installe, ainsi les deux ne peuvent jamais diverger et il n'y a pas de version par défaut qui devienne obsolète. | Entrée | | |---|---| | `session` | la capture `.jsonl` à vérifier, ou un répertoire de captures, relatif à la racine du dépôt. Fournissez ceci ou `replay` | | `replay` | un enregistrement commité à rejouer contre `server` ou `target`, dont la capture est ensuite vérifiée et qui fait aussi échouer le job en cas de régression | | `server` | la commande qui démarre le serveur testé, entre guillemets comme sur une ligne de commande. Requis avec `replay` pour un serveur stdio. Avec `target`, elle démarre d'abord un serveur HTTP, et peut être omise lorsqu'un serveur tourne déjà | | `target` | le point de terminaison Streamable HTTP contre lequel rejouer, tel que `http://localhost:3000/mcp`. Un identifiant se place dans `replay-args` via `--header`, et le journal de l'étape affiche sa valeur masquée | | `replay-args` | tout autre drapeau de `replay`, tel que `--read-only`. `--out` est refusé, puisque l'action décide où va la capture | | `fail-on` | comme `--fail-on`, avec pour valeur par défaut celle du CLI | | `args` | tout autre drapeau de `check`, entre guillemets comme sur une ligne de commande. `--format` est refusé, puisque l'action lit le rapport | | `upload-sarif` | envoyer le rapport à l'analyse de code. `true` | | `category` | l'espace de noms de l'analyse de code. `mcpsnoop`. Variez-le par branche d'une matrice, sinon les branches s'écrasent mutuellement | | `fail-on-findings` | faire échouer le job sur une découverte. `true`. Mettez `false` pour déposer les alertes et laisser la vérification requise de l'analyse de code décider | | `version` | quel mcpsnoop installer. Par défaut, la release que vous avez épinglée | | `install` | `false` lorsque mcpsnoop est déjà dans le PATH, ce qui est la voie d'accès sur une plateforme pour laquelle aucune release n'est compilée | Les sorties sont `outcome`, `sarif`, `exit-code` et `capture`, le chemin de la capture qui a été vérifiée, laquelle, avec `replay`, est celle que le replay a écrite et qu'il vaut la peine de conserver comme artefact. `outcome` vaut `passed`, `findings` ou `error`, et le troisième mérite un traitement séparé. Il signifie que rien n'a été vérifié, ce qui n'est pas la même chose que rien n'a été trouvé. **Une exécution qui n'a pas pu vérifier fait échouer le job quoi que dise `fail-on-findings`**, car un pipeline qui passe au vert sans avoir rien vérifié est pire qu'un qui échoue. Le job a besoin de `security-events: write`, sinon l'upload répond 403. Mettez `upload-sarif: false` dans un dépôt sans analyse de code. Exécuter la même vérification sans l'action, les signaux sur lesquels elle peut échouer et les codes de sortie sont dans [docs/CI.md](https://github.com/kerlenton/mcpsnoop/blob/main/docs/CI.md). ## Documentation | Page | Ce qu'elle contient | |---|---| | [Vérifier les sessions en CI](https://github.com/kerlenton/mcpsnoop/blob/main/docs/CI.md) | rejouer un enregistrement contre chaque build, chaque signal sur lequel `check` peut échouer, les codes de sortie, les assertions, les rapports JUnit et SARIF, comparer deux sessions, et le mettre en place sans l'action | | [OpenTelemetry et Prometheus](https://github.com/kerlenton/mcpsnoop/blob/main/docs/OPENTELEMETRY.md) | les spans et ce qu'ils transportent, leur diffusion en flux vers un collecteur, et les métriques d'outils en direct | | [Utiliser mcpsnoop](https://github.com/kerlenton/mcpsnoop/blob/main/docs/USING.md) | les touches, le filtrage, les formats d'export, le replay, ce qu'un serveur a demandé à votre utilisateur, le coût en contexte, les statistiques sur l'ensemble des captures, ce que chaque client envoie réellement, l'inventaire des serveurs, les machines distantes et le fichier de configuration | | [Caviardage](https://github.com/kerlenton/mcpsnoop/blob/main/docs/REDACTION.md) | nettoyer les secrets, pendant la capture ou depuis une capture que vous possédez déjà | | [Comment ça marche](https://github.com/kerlenton/mcpsnoop/blob/main/docs/HOW_IT_WORKS.md) | les limites de mémoire, la limite d'historique, et l'élagage des anciens journaux | | [Essayez pour de vrai](https://github.com/kerlenton/mcpsnoop/blob/main/docs/TRY_IT.md) | un serveur de test publié, piloté par votre propre client | | [Revoir les sessions passées](https://github.com/kerlenton/mcpsnoop/blob/main/docs/POST_MORTEM.md) | où vivent les journaux de session et comment en ouvrir un après coup | | [Le format de capture](https://github.com/kerlenton/mcpsnoop/blob/main/docs/CAPTURE_FORMAT.md) | ce que contient chaque ligne d'un journal de session et ce qui ne changera jamais à son sujet, avec un JSON Schema pour les outils qui lisent les captures | ## Sécurité mcpsnoop exécute la commande de serveur que vous enveloppez, donc n'enveloppez que des serveurs auxquels vous faites confiance, et exécutez les serveurs non fiables dans un conteneur. Il n'exécute jamais rien que vous n'ayez pas mis dans la configuration de votre client. Pour les workflows distants, utilisez le tunnelling SSH ou le transfert de fichiers SSH afin que l'authentification du transport, le chiffrement, la vérification de l'hôte, la rotation des clés et la politique d'audit restent dans votre configuration SSH existante. ### Ce qu'une capture peut faire à votre terminal Une capture est une donnée choisie par l'autre partie. Les trames et les lignes stderr peuvent contenir des séquences d'échappement de terminal, et un terminal agit sur tout ce qu'on lui transmet, ce qui va d'un affichage brouillé jusqu'à OSC 52 écrivant dans le presse-papiers de votre système. mcpsnoop ne conserve que les séquences de couleur qu'il génère lui-même et supprime toute autre séquence d'échappement avant qu'une trame n'atteigne votre terminal. Les cellules de tableau échappent les caractères de contrôle pour que vous puissiez voir qu'ils étaient présents, l'inspecteur les affiche en toutes lettres, et la copie dans le presse-papiers contient la forme échappée, de sorte que rien ne vous est caché et rien ne s'exécute. ### Ce que contient une capture Les trames capturées peuvent inclure des prompts, des arguments d'outils, des identifiants et des résultats d'outils. [docs/REDACTION.md](https://github.com/kerlenton/mcpsnoop/blob/main/docs/REDACTION.md) traite de leur nettoyage, pendant ou après la capture. Pour signaler une vulnérabilité, consultez [SECURITY.md](https://github.com/kerlenton/mcpsnoop/blob/main/SECURITY.md). ## Contribution Les issues et les pull requests sont les bienvenues. Consultez [CONTRIBUTING.md](https://github.com/kerlenton/mcpsnoop/blob/main/CONTRIBUTING.md) pour les détails. ## Licence [MIT](https://github.com/kerlenton/mcpsnoop/blob/main/LICENSE)