Protocole MCP avancé : transports et architecture
Spécification JSON-RPC 2.0, transports stdio/SSE/HTTP, capabilities negotiation, sécurité et debugging des MCP.
Au-delà des bases
Vous savez créer un MCP, installer des tools et les utiliser dans Claude Code. Cette page va plus loin : le protocole JSON-RPC sous-jacent, les différents transports disponibles, la négociation de capabilities et les techniques de debugging avancé.
Pour qui ?
Ce contenu s'adresse aux développeurs qui veulent comprendre le protocole en profondeur, déployer des MCP distants (SSE, HTTP), ou diagnostiquer des problèmes complexes. Si vous débutez, commencez par les tutoriels TypeScript ou Python.
Spécification JSON-RPC 2.0
Le MCP repose sur JSON-RPC 2.0, un protocole léger de communication par messages JSON. Chaque échange suit un format strict : requête, réponse, ou notification.
Format d'une requête
{"jsonrpc": "2.0","id": 1,"method": "tools/call","params": {"name": "get-weather","arguments": { "city": "Paris" }}}
jsonrpc: toujours"2.0"id: identifiant unique pour corréler la réponsemethod: la méthode appeléeparams: les paramètres de l'appel
Format d'une réponse
{"jsonrpc": "2.0","id": 1,"result": {"content": [{"type": "text","text": "Météo à Paris : 18°C, Nuageux"}]}}
Les principales méthodes MCP
| Méthode | Direction | Description |
|---|---|---|
initialize | Client vers Server | Initialise la connexion, échange les capabilities |
tools/list | Client vers Server | Liste tous les tools exposés par le serveur |
tools/call | Client vers Server | Appelle un tool avec des arguments |
resources/list | Client vers Server | Liste toutes les resources disponibles |
resources/read | Client vers Server | Lit le contenu d'une resource par URI |
prompts/list | Client vers Server | Liste les prompts disponibles |
prompts/get | Client vers Server | Récupère un prompt avec ses arguments |
notifications/cancelled | Client vers Server | Annule une requête en cours |
Notifications vs Requêtes
Les notifications n'ont pas de champ id et n'attendent pas de réponse. Elles servent pour les événements unidirectionnels : changement de resource, mise à jour de progression, annulation.
Capabilities negotiation
Au démarrage, Claude Code et le MCP Server échangent leurs capabilities. C'est la première interaction après la connexion.
Requête d'initialisation
{"jsonrpc": "2.0","id": 1,"method": "initialize","params": {"protocolVersion": "2024-11-05","capabilities": {"sampling": {}},"clientInfo": {"name": "claude-code","version": "1.0.0"}}}
Réponse du serveur
{"jsonrpc": "2.0","id": 1,"result": {"protocolVersion": "2024-11-05","capabilities": {"tools": {},"resources": { "subscribe": true },"prompts": {}},"serverInfo": {"name": "mcp-weather","version": "1.0.0"}}}
Le client et le serveur s'accordent sur la version du protocole et annoncent ce qu'ils supportent. Un serveur qui ne déclare pas tools dans ses capabilities ne recevra pas d'appels tools/call.
Capabilities disponibles
| Capability | Côté | Description |
|---|---|---|
tools | Server | Le serveur expose des outils |
resources | Server | Le serveur expose des resources |
resources.subscribe | Server | Le client peut s'abonner aux changements de resources |
prompts | Server | Le serveur expose des prompts |
sampling | Client | Le client supporte le sampling (voir plus bas) |
Transport stdio : le mode par défaut
Le transport stdio (standard input/output) est le plus simple et le plus courant. Claude Code lance le processus MCP Server et communique via les flux stdin/stdout du processus.
Fonctionnement
Claude Code MCP Server (processus fils)
| |
|--- stdin: requête JSON-RPC ------->|
| |--- traitement
|<--- stdout: réponse JSON-RPC ------|
| |
|--- stdin: notification ----------->|
Chaque message est une ligne JSON terminée par \n. Les logs du serveur passent par stderr pour ne pas interférer avec le protocole.
Configuration
{"mcpServers": {"my-mcp": {"command": "node","args": ["dist/index.js"],"env": { "API_KEY": "..." }}}}
Avantages et limites
- Simple : pas de réseau, pas de ports, pas de configuration serveur
- Sécurisé : la communication est locale, pas de surface d'attaque réseau
- Limité : un processus par connexion, pas de partage entre plusieurs clients
- Local : le MCP doit tourner sur la même machine que Claude Code
Transport SSE : Server-Sent Events
Le transport SSE permet de connecter Claude Code à un MCP Server distant via HTTP. Le client envoie des requêtes POST et reçoit les réponses via un flux SSE (Server-Sent Events).
Quand l'utiliser
- Le MCP Server tourne sur un serveur distant (cloud, VPS, réseau interne)
- Plusieurs clients doivent se connecter au même MCP Server
- Vous voulez un MCP Server toujours disponible, sans le relancer à chaque session
Configuration
{"mcpServers": {"remote-db": {"url": "https://mcp.example.com/sse","headers": {"Authorization": "Bearer votre-token"}}}}
Sécurité obligatoire
Un MCP SSE est accessible sur le réseau. Protégez-le impérativement : authentification par token, HTTPS obligatoire, liste blanche d'IPs si possible. Un MCP exposé sans protection est une faille de sécurité critique.
Flux de communication
Claude Code MCP Server (HTTP)
| |
|--- GET /sse (établir le flux SSE) --->|
|<--- SSE: endpoint URL ----------------|
| |
|--- POST /messages (requête) --------->|
|<--- SSE: réponse JSON-RPC ------------|
Transport Streamable HTTP : le nouveau standard
Le transport Streamable HTTP est le successeur du SSE pour les MCP distants. Il combine la simplicité du HTTP avec le streaming bidirectionnel.
Différences avec SSE
| Critère | SSE | Streamable HTTP |
|---|---|---|
| Direction | Unidirectionnel (serveur vers client) | Bidirectionnel |
| Connexion | Longue durée (flux SSE persistant) | Requêtes individuelles, streamées si besoin |
| Reprise | Reconnexion manuelle | Support natif de la reprise |
| Proxy | Certains proxies coupent les SSE | Compatible avec tous les proxies HTTP |
Configuration
{"mcpServers": {"remote-api": {"url": "https://mcp.example.com/mcp","headers": {"Authorization": "Bearer votre-token"}}}}
Adoption progressive
Le transport Streamable HTTP est plus récent que SSE. Vérifiez que le serveur MCP que vous ciblez le supporte. Le SDK officiel (TypeScript et Python) le supporte dans les versions récentes.
Sampling : quand le MCP demande au LLM
Le sampling est une capability spéciale : elle permet au MCP Server de demander à Claude de compléter un prompt. C'est un flux inversé où le serveur devient temporairement "client" du LLM.
Cas d'usage
- Un tool de traduction qui demande à Claude de traduire un texte
- Un tool d'analyse qui demande à Claude de résumer des données
- Un outil de génération qui utilise Claude pour produire du contenu
Flux de communication
Claude Code MCP Server Claude (LLM)
| | |
|-- tools/call --->| |
| |--- sampling/request ---->|
| |<--- réponse LLM ---------|
|<-- résultat -----| |
Impact sur les coûts
Chaque requête de sampling consomme des tokens supplémentaires. Un MCP qui utilise le sampling de manière intensive peut augmenter vos coûts. Surveillez la consommation avec /cost dans Claude Code.
Performance et latence
Les MCP ajoutent de la latence à chaque interaction. Voici les sources principales et comment les optimiser.
Sources de latence
| Source | Latence typique | Optimisation |
|---|---|---|
| Démarrage du processus (stdio) | 500ms-2s | Garder le processus actif |
Découverte des tools (tools/list) | 10-50ms | Mise en cache côté client |
Appel d'un tool (tools/call) | Variable selon le tool | Timeouts appropriés |
| Appel API externe | 100ms-5s | Cache, retry, fallback |
| Transport réseau (SSE/HTTP) | 20-100ms | Serveur proche géographiquement |
Gestion des timeouts
Claude Code impose un timeout par défaut sur les appels MCP. Si votre tool fait des opérations longues :
// Dans votre tool handler, envoyez des notifications de progressionserver.tool("long-operation","Opération qui prend du temps",{ input: z.string() },async ({ input }, { sendProgress }) => {await sendProgress(0, 100, "Démarrage...");// ... opération longueawait sendProgress(50, 100, "Traitement en cours...");// ... suiteawait sendProgress(100, 100, "Terminé");return {content: [{ type: "text" as const, text: "Résultat de l'opération" }],};});
Sécurité avancée
Sandboxing
Chaque MCP Server tourne dans son propre processus. Mais il a accès au système de fichiers et au réseau de la machine hôte. Pour limiter les risques :
- Exécutez les MCP dans un conteneur Docker avec des volumes restreints
- Utilisez des tokens avec scopes minimaux (lecture seule quand possible)
- Appliquez des règles réseau pour limiter les connexions sortantes
Audit logs
Pour tracer ce que fait un MCP :
// Wrapper de logging pour tous les appels de toolsserver.tool("my-tool", "Description", { param: z.string() }, async ({ param }) => {console.error(`[AUDIT] tool=my-tool param=${param} time=${new Date().toISOString()}`);// ... logique du toolconst result = "...";console.error(`[AUDIT] tool=my-tool result_length=${result.length}`);return { content: [{ type: "text" as const, text: result }] };});
Les logs sur stderr ne perturbent pas le protocole et peuvent être capturés par votre système de monitoring.
Token rotation
Pour les MCP qui utilisent des tokens d'API externe :
- Stockez les tokens dans des variables d'environnement, pas dans le code
- Mettez en place une rotation régulière des tokens (tous les 90 jours minimum)
- Utilisez un gestionnaire de secrets (Vault, AWS Secrets Manager) pour la production
- Révoquez immédiatement tout token potentiellement compromis
Debugging : diagnostiquer les problèmes
Inspection JSON-RPC
L'inspecteur MCP est votre meilleur outil pour débugger :
# Inspecter un serveur stdionpx @modelcontextprotocol/inspector node dist/index.js# Inspecter un serveur SSEnpx @modelcontextprotocol/inspector --url https://mcp.example.com/sse
L'inspecteur affiche chaque message JSON-RPC échangé, ce qui permet de voir exactement ce que le serveur reçoit et retourne.
Logging verbeux côté Claude Code
# Lancer Claude Code avec les logs MCP détaillésclaude --verbose
Le flag --verbose affiche les échanges JSON-RPC avec chaque MCP dans le terminal.
Vérifier la santé d'un MCP
# Lister les MCP configurés et leur statutclaude mcp list
Si un MCP apparaît comme "disconnected" ou "error" :
Vérifier que la commande fonctionne
Exécutez la commande du MCP directement dans votre terminal pour voir les erreurs :
# Exemple pour un MCP Node.jsnode /chemin/vers/mcp/dist/index.js
Si ça plante, le message d'erreur vous indiquera le problème (dépendance manquante, erreur de syntaxe, etc.).
Vérifier les variables d'environnement
Les tokens manquants sont la cause la plus fréquente. Vérifiez que toutes les variables env du .mcp.json sont correctes.
Tester avec l'inspecteur
npx @modelcontextprotocol/inspector node /chemin/vers/mcp/dist/index.js
Si l'inspecteur fonctionne mais pas Claude Code, le problème vient de la configuration Claude (chemin, arguments, permissions).
Erreurs fréquentes en debug
| Symptôme | Cause probable | Diagnostic |
|---|---|---|
| MCP "disconnected" au démarrage | Processus qui plante | Exécuter la commande manuellement |
| Tools non listés | Erreur dans initialize | Vérifier avec l'inspecteur MCP |
| Réponse vide ou timeout | Handler qui ne retourne rien | Ajouter des logs stderr |
parse error JSON-RPC | console.log() dans le code | Remplacer par console.error() |
| Token expiré | Credentials périmées | Régénérer le token et mettre à jour env |
Prochaines étapes
- Créer un MCP Server en TypeScript : tutoriel complet avec le SDK TypeScript
- Créer un MCP Server en Python : tutoriel avec le SDK Python et les décorateurs
- Sécurité des MCP : guide complet de sécurisation
- Comprendre les MCP : revenir aux fondamentaux du protocole