New in Tech

MCP devient stateless : ce que la révision 2026-07-28 change pour vos serveurs en production — et pour leur surface d'attaque

La révision 2026-07-28 du Model Context Protocol est la plus lourde depuis le lancement du protocole : six SEP rendent le cœur du protocole stateless, avec routage par en-tête, requêtes multi-aller-retour, résultats de liste cachables et une autorisation nettement durcie. Cet article détaille les conséquences opérationnelles concrètes pour vos serveurs distants, la nouvelle surface d'attaque que le stateless déplace plutôt qu'il ne supprime, et un plan de migration testable.

| | | 11 min read · 19 Aug 2026 · by
Schéma d'un load balancer répartissant des requêtes MCP sans session vers plusieurs instances de serveur identiques

Depuis deux semaines, les équipes qui exploitent des serveurs MCP en production relisent la même chose : la révision 2026-07-28 du Model Context Protocol. Six SEP (Specification Enhancement Proposals) y convergent vers un objectif unique — rendre le cœur du protocole stateless — et cet objectif entraîne une réécriture de la couche transport HTTP, du modèle d’autorisation et des règles d’extensibilité.

Ce n’est pas une révision cosmétique. Si vous avez déployé un serveur MCP distant derrière une passerelle, avec un store de sessions et des sticky sessions, une bonne partie de votre plomberie devient inutile. Et comme toujours, ce qui disparaît d’un côté réapparaît ailleurs : la frontière de confiance se déplace, la surface d’attaque avec elle.

Note de lecture : les exemples de payloads et de configuration ci-dessous sont illustratifs. Avant migration, confrontez-les au texte de la révision et au changelog des SDK que vous utilisez — plusieurs détails de nommage ont bougé entre les brouillons des SEP et la version finale.

Rappel : la session, point de douleur n°1 des déploiements MCP distants

Dans les révisions précédentes, le transport Streamable HTTP reposait sur un identifiant de session émis par le serveur à l’initialize et renvoyé par le client dans l’en-tête Mcp-Session-Id. Élégant sur le papier, coûteux en exploitation :

  • Affinité obligatoire. Toutes les requêtes d’une session devaient atterrir sur l’instance qui détenait son état. Donc sticky sessions, donc déséquilibre de charge, donc redémarrages destructeurs : un rolling update tuait les sessions actives.
  • État partagé. Pour éviter l’affinité, il fallait externaliser l’état (Redis, Memcached, base) et payer une latence supplémentaire sur chaque appel, plus une invalidation à écrire soi-même.
  • Passerelles aveugles. Router intelligemment exigeait d’ouvrir le corps JSON-RPC pour lire le champ method. Un load balancer L7 devenait, de fait, un parseur de protocole applicatif — avec les risques de désynchronisation et le coût CPU associés.
  • Autoscaling contrarié. Impossible de traiter les instances comme jetables tant qu’elles portent l’état conversationnel.

Ajoutez la reprise de flux SSE, la gestion des sessions expirées côté client, et vous obtenez la raison pour laquelle beaucoup d’équipes s’étaient rabattues sur un serveur MCP mono-instance derrière un reverse proxy — solution qui ne survit ni à la charge ni au SLA.

Le cœur du changement : six SEP pour un protocole stateless

La révision poursuit la trajectoire annoncée en décembre dans le plan sur les transports. L’idée directrice : aucune requête ne doit dépendre d’un état serveur créé par une requête précédente. Concrètement, les informations nécessaires au routage remontent du corps JSON-RPC vers les en-têtes HTTP, et tout contexte qui devait survivre entre deux appels est soit porté par le client, soit encapsulé dans un jeton opaque signé.

Le pivot le plus visible est l’en-tête de routage, aux côtés de Mcp-Protocol-Version déjà existant :

POST /mcp HTTP/1.1
Host: mcp.exemple.fr
Authorization: Bearer eyJhbGciOi...
Mcp-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Content-Type: application/json

{"jsonrpc":"2.0","id":42,"method":"tools/call",
 "params":{"name":"search_tickets","arguments":{"query":"latence p99"}}}

La passerelle lit Mcp-Method et route. Elle n’ouvre plus le corps. Un simple round-robin suffit :

upstream mcp_backends {
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
    server 10.0.1.13:8080;
    # plus de ip_hash, plus de sticky cookie
}

location /mcp {
    proxy_pass http://mcp_backends;
    proxy_set_header Mcp-Method $http_mcp_method;
    # cache possible sur les méthodes de liste (voir plus bas)
}

Bien sûr, la règle d’or reste valable : l’en-tête n’est pas une source de vérité. Le serveur doit vérifier que Mcp-Method correspond au champ method du corps et rejeter la requête en cas de divergence. Sans cette vérification, vous venez d’offrir un vecteur de routing confusion.

Conséquence opérationnelle immédiate

Ce que vous pouvez retirer de votre stack :

  1. Les sticky sessions et la configuration d’affinité au niveau du load balancer.
  2. Le store de sessions partagé, avec ses TTL, son invalidation et son mode dégradé.
  3. L’inspection profonde du corps dans la passerelle, remplacée par un match d’en-tête.

Ce que vous gagnez : des instances véritablement jetables. Rolling update sans casser de conversation, scale-to-zero possible sur les serveurs peu sollicités, tests de charge qui reflètent enfin la production.

Les autres nouveautés à connaître

Requêtes multi-aller-retour. Un appel d’outil peut nécessiter un échange supplémentaire — demander une confirmation, réclamer un paramètre manquant, solliciter une complétion du modèle. Sans session, ce dialogue doit être auto-porteur : le serveur renvoie une réponse intermédiaire accompagnée d’un contexte opaque que le client doit lui restituer tel quel. Dans l’esprit :

// Réponse intermédiaire du serveur
{"jsonrpc":"2.0","id":42,
 "result":{"status":"input_required",
           "prompt":{"field":"environment","enum":["staging","prod"]},
           "continuation":"v1.eyJ0b29sIjoi...signature"}}

// Reprise par le client, sans état côté serveur
{"jsonrpc":"2.0","id":43,"method":"tools/call",
 "params":{"name":"deploy","arguments":{"environment":"staging"},
           "continuation":"v1.eyJ0b29sIjoi...signature"}}

Point de sécurité non négociable : ce jeton de continuation est un objet signé et daté, jamais une structure lisible et rejouable. S’il n’est ni authentifié ni horodaté, un attaquant peut le forger, en modifier les paramètres implicites ou le rejouer après expiration de l’intention utilisateur.

Résultats de liste cachables. tools/list, resources/list et prompts/list deviennent explicitement cachables, avec les mécanismes HTTP standards (ETag, validation conditionnelle). C’est le gain de latence le plus tangible côté client : ces appels dominaient le trafic au démarrage de chaque conversation. Attention néanmoins : si votre catalogue d’outils dépend de l’identité de l’appelant, le cache doit varier sur la dimension d’autorisation, sinon vous exposez à un utilisateur la liste d’outils d’un autre.

Cadre d’extensions formalisé. Les extensions propriétaires disposent enfin d’un espace de noms et de règles de négociation propres, au lieu de squatter des champs libres. Vos capacités maison deviennent déclarables et détectables.

Politique de dépréciation explicite. Le protocole s’engage sur des fenêtres de dépréciation annoncées, ce qui rend enfin planifiable la gestion de la dette côté client.

SDK Tier 1 mis à jour. Les SDK de premier niveau sont alignés sur la révision. Vérifiez toutefois la maturité de l’implémentation stateless dans le vôtre avant de retirer votre store de sessions : « supporté » et « éprouvé en production » ne sont pas synonymes.

Autorisation durcie

Le volet le plus intéressant sur le plan sécurité concerne OAuth. Trois exigences se renforcent.

Validation de l’iss selon RFC 9207. Le serveur d’autorisation doit renvoyer son identifiant d’émetteur dans la réponse d’autorisation, et le client doit le valider avant d’échanger le code contre un token. C’est la parade directe contre les attaques de type mix-up : sans cette vérification, un client qui parle à plusieurs serveurs d’autorisation peut être amené à présenter un code légitime au mauvais endpoint de token et à fuiter des credentials.

Credentials liés à leur émetteur. Un client_id et son secret sont désormais réputés valides uniquement auprès du serveur d’autorisation qui les a produits. Toute logique de client qui stocke un couple de credentials dans une table globale, indexée par nom de serveur MCP, doit être réécrite pour indexer par émetteur.

Non-réutilisation entre serveurs d’autorisation. Corollaire du point précédent : plus de partage opportuniste de credentials entre AS, y compris quand ils appartiennent à la même organisation.

DCR déprécié au profit des Client ID Metadata Documents

Le Dynamic Client Registration (RFC 7591) était le talon d’Achille pratique de MCP : chaque client devait s’enregistrer dynamiquement auprès de chaque serveur d’autorisation, ce qui imposait aux AS d’accepter des enregistrements anonymes — un aimant à pollution de base et à abus.

La révision le déprécie au profit des Client ID Metadata Documents (CIMD) : le client_id devient une URL HTTPS que le serveur d’autorisation résout pour obtenir les métadonnées du client.

// https://client.exemple.fr/.well-known/oauth-client
{
  "client_id": "https://client.exemple.fr/.well-known/oauth-client",
  "client_name": "Assistant Interne Exemple",
  "redirect_uris": ["https://client.exemple.fr/oauth/callback"],
  "token_endpoint_auth_method": "none",
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"]
}

Implications concrètes :

  • L’identité du client devient vérifiable et révocable : vous contrôlez le document, donc vous contrôlez les redirect_uris déclarées.
  • Le document doit être servi en HTTPS, disponible et immuable dans son URL. Il entre dans votre périmètre de disponibilité : s’il tombe, plus d’autorisation.
  • Une période de compatibilité est prévue, pendant laquelle les serveurs d’autorisation peuvent accepter les deux mécanismes. Ne la gaspillez pas : les clients qui reposent encore sur DCR devront migrer, et le côté client est toujours celui qu’on met le plus longtemps à mettre à jour dans un parc.

Le revers : chaque simplification déplace la frontière de confiance

Le stateless supprime des classes de bugs et en crée d’autres. Les points de vigilance à ajouter à vos revues :

  • Confiance dans les en-têtes. Mcp-Method circule en clair, modifiable par tout intermédiaire. Si une règle de politique (rate limiting, autorisation, journalisation) s’appuie sur cet en-tête sans revalidation côté serveur, elle est contournable.
  • Jetons de continuation. Nouveau matériel cryptographique à gérer : signature, rotation de clés, durée de vie courte, liaison à l’identité de l’appelant. Un jeton non lié à un sujet est un jeton porteur transférable.
  • Empoisonnement de cache. Les listes cachables sont une aubaine pour un attaquant capable d’influencer le cache : injecter une définition d’outil malveillante dans un tools/list partagé, c’est distribuer une prompt injection à tous les clients d’un tenant.
  • Perte de contexte pour la détection. Sans session, la corrélation entre appels d’outils est à reconstruire dans vos logs. Votre détection d’anomalies comportementales doit s’appuyer sur l’identité et un identifiant de corrélation explicite, plus sur le transport.

Ce que l’écosystème a déjà payé cash

Le calendrier n’est pas anodin : cette révision arrive après dix-huit mois d’incidents qui ont façonné la perception du protocole.

La plus emblématique reste CVE-2025-6514, notée 9.6, sur mcp-remote — le proxy qui permet aux clients ne parlant que stdio de joindre un serveur distant. Une injection de commande côté client, déclenchable par un serveur MCP malveillant, dans un paquet installé dans plus de 437 000 environnements. La leç: le maillon faible n’était pas le serveur, mais le shim de compatibilité que tout le monde avait installé sans le lire.

À cela s’ajoutent la vague d’incidents supply chain de 2026 sur des serveurs MCP distribués via les registres de paquets publics, la divulgation d’avril 2026 par OX Security, et le flot continu de prompt injections servies par des serveurs MCP tiers — descriptions d’outils piégées, ressources dont le contenu est repris tel quel dans le contexte du modèle.

Le fil rouge est identique dans les trois cas : un serveur MCP est une dépendance exécutable qui parle directement au modèle, avec toute la latitude d’un plugin et aucune des restrictions d’une sandbox.

Checklist de durcissement

  • Inventaire. Listez tous les serveurs MCP joignables par vos clients, y compris ceux ajoutés localement par les développeurs. Ce qui n’est pas inventorié n’est pas gouverné.
  • Épinglage et audit. Versions figées, lockfiles commités, vérification d’intégrité. Pas d’installation via un @latest.
{
  "mcpServers": {
    "tickets": {
      "command": "npx",
      "args": ["-y", "@exemple/mcp-tickets@2.4.1"], // version épinglée
      "env": { "TICKETS_TOKEN": "${TICKETS_TOKEN_RO}" }
    }
  }
}
  • Périmètre des tokens. Un token par serveur, scopes minimaux, lecture seule par défaut, durée de vie courte. Aucun token d’organisation dans un serveur MCP.
  • Journalisation des appels d’outils. Nom de l’outil, arguments (rédigés), identité de l’appelant, identifiant de corrélation, résultat. C’est la seule source dont vous disposerez pour l’analyse post-incident.
  • Validation humaine sur les effets de bord. Écriture, suppression, paiement, déploiement : confirmation explicite, hors du canal contrôlé par le modèle.
  • Isolation d’exécution. Container, filesystem en lecture seule, egress réseau filtré par allowlist.

Plan de migration en étapes

  1. Mesurer avant de bouger. Instrumentez la répartition de vos méthodes, la latence de vos accès au store de sessions et le taux de succès des reprises de flux. Sans cette baseline, vous ne saurez pas si la migration a apporté quoi que ce soit.
  2. Monter la version des SDK, sans changer d’architecture. Négociez 2026-07-28 en conservant sessions et affinité. Objectif : isoler les régressions de sérialisation et de négociation de capacités.
  3. Ajouter le routage par en-tête en shadow. La passerelle émet Mcp-Method, le serveur vérifie la cohérence avec le corps et journalise les divergences — sans encore router dessus.
  4. Rendre le serveur stateless. Supprimez l’état en mémoire, introduisez les jetons de continuation signés. Test prioritaire : un appel multi-aller-retour dont chaque étape atterrit délibérément sur une instance différente.
  5. Activer le cache de listes. Avec la dimension d’autorisation dans la clé de cache. Test prioritaire : deux identités aux droits distincts ne doivent jamais voir la même réponse tools/list.
  6. Basculer le load balancer en round-robin, retirer l’affinité, puis le store de sessions. Validez par un rolling update sous charge, avec appels multi-tours en cours.
  7. Migrer l’autorisation. Publiez le CIMD, activez la validation iss, indexez les credentials par émetteur, puis retirez DCR — dans cet ordre, en gardant les deux chemins actifs pendant la fenêtre de compatibilité.
  8. Rejouer la checklist sécurité sur la nouvelle topologie. Les règles écrites pour un monde à sessions ne couvrent pas le monde sans sessions.

Cette révision est une bonne nouvelle d’ingénierie : elle rend MCP compatible avec la manière dont on exploite réellement des services HTTP — instances interchangeables, load balancer bête, cache HTTP standard. Le durcissement d’OAuth et la fin de DCR corrigent en outre deux faiblesses structurelles que le terrain avait largement documentées.

Mais aucune de ces améliorations ne touche au risque dominant. Ce qui a fait mal à l’écosystème en 2025 et 2026, ce ne sont pas les sessions collantes : ce sont des dépendances non auditées, des tokens trop larges et du texte non fiable injecté dans le contexte d’un modèle qui dispose de capacités d’action. Le stateless rend vos serveurs MCP plus faciles à exploiter au sens ops. Il ne les rend pas plus difficiles à exploiter au sens offensif. Traitez la migration comme une occasion d’appliquer la seconde moitié du travail — c’est le moment où vous avez de toute façon le code ouvert.

Comments (0)

Please log in to leave a comment.

Log In

No comments yet. Be the first to comment!