Migrer un serveur MCP vers la spec 2026-07-28 : le guide complet
La spec MCP 2026-07-28 supprime les sessions, le handshake initialize et trois primitives. Voici les 7 changements qui cassent, dans l'ordre où il faut les traiter.
Le 28 juillet 2026, le Model Context Protocol a publié sa plus grosse révision depuis le lancement. Ce n'est pas un ajout de champs. Le cœur du transport a été réécrit, trois primitives sont dépréciées, l'autorisation se durcit et deux extensions passent en première classe.
Si tu fais tourner un serveur MCP en production sur 2025-11-25, rien n'est cassé aujourd'hui. C'est le premier point à comprendre, parce que la moitié des articles sur le sujet vendent une panique qui n'existe pas. La bascule est volontaire des deux côtés : tant que tes clients ne parlent pas la nouvelle révision, ton serveur continue de répondre. Et un client qui parle 2026-07-28 sait retomber sur l'ancien handshake quand il tombe sur un serveur plus vieux.
Ce que tu perds en attendant, ce n'est pas la disponibilité, c'est le bénéfice. Les serveurs qui migrent tournent derrière un simple load balancer round-robin, sans sessions collantes, sans store partagé, sans passerelle qui ouvre les paquets pour router. Et ils deviennent éligibles à ce qui arrive ensuite.
Voici les sept changements, dans l'ordre où il faut les traiter.
1. Le protocole devient stateless
C'est le changement structurant, et tout le reste en découle.
Les sessions au niveau protocole disparaissent. L'en-tête Mcp-Session-Id est retiré du transport Streamable HTTP. Les endpoints de liste (tools/list, resources/list, prompts/list) ne varient plus selon la connexion : deux clients qui interrogent ton serveur reçoivent la même liste.
Un serveur qui a besoin d'un état entre plusieurs appels le gère explicitement, avec des identifiants qu'il fabrique lui-même et qu'il fait circuler comme des arguments d'outil ordinaires. Le pattern s'appelle handle. Ton serveur émet une valeur opaque, le client la rend au tour suivant, ton serveur la résout côté stockage.
Le travail réel n'est pas d'écrire ce pattern. C'est de trouver tous les endroits où ton code lit encore un identifiant de session sans le savoir. Un curseur de pagination gardé en mémoire, un panier de configuration construit sur deux appels, un état d'authentification mis en cache par connexion. Tant que tu tournais sur une seule instance, ça marchait, et ça masquait le problème.
Le symptôme classique après migration : ça marche en local, ça marche en staging sur un seul pod, et ça échoue une fois sur trois en prod dès que le load balancer distribue.
2. Le handshake initialize disparaît
initialize et notifications/initialized ne sont plus requis. Il n'y a plus de moment où le client et le serveur se présentent puis se souviennent l'un de l'autre.
À la place, chaque requête transporte ce qu'il faut pour être comprise seule. La version de protocole et les capabilities du client voyagent dans le champ _meta, sous les clés io.modelcontextprotocol/protocolVersion et io.modelcontextprotocol/clientCapabilities.
Pour la découverte, la spec introduit server/discover. C'est là que le client va chercher les versions et les capacités que ton serveur annonce.
Concrètement, ce que ça veut dire pour ton code : tout ce qui était initialisé une fois au handshake et réutilisé ensuite doit être recalculé ou récupéré à chaque requête. Si ton serveur configure un contexte utilisateur au moment du handshake, ce contexte doit maintenant se reconstruire à partir du token et des métadonnées de la requête courante.
3. Deux en-têtes HTTP deviennent obligatoires
Mcp-Method et Mcp-Name doivent accompagner les requêtes sur Streamable HTTP. Ils reflètent la méthode JSON-RPC et le nom appelé dans le corps de la requête.
C'est le changement le plus rentable de toute la spec pour qui exploite l'infrastructure. Jusque-là, appliquer une politique par outil obligeait à ouvrir le body à la passerelle. Maintenant, un rate limit sur ton outil d'export, une règle WAF sur les outils d'écriture, un routage vers un pool dédié pour les appels coûteux, une métrique par outil : tout ça se fait au niveau HTTP, avec les outils que tu as déjà.
Un point de vigilance, et il est important. L'en-tête est déclaratif. Une requête peut annoncer dans Mcp-Name un outil anodin en lecture seule et appeler dans le corps JSON-RPC un outil sensible. Si ta politique de sécurité fait confiance à l'en-tête sans vérifier la cohérence avec le body, tu viens de créer un contournement. Le serveur doit rejeter le décalage, et ce rejet doit remonter dans ta télémétrie.
4. Le code d'erreur -32002 devient -32602
MCP avait introduit -32002 pour signaler une ressource absente. JSON-RPC 2.0 a déjà -32602 pour des paramètres invalides. La spec supprime le doublon.
C'est deux lignes de code et c'est le piège le plus vicieux du lot, parce qu'il casse en silence. Un client qui teste la valeur littérale -32002 ne plante pas, il ne reconnaît simplement plus l'erreur. Tu ne le vois ni dans les logs d'erreur ni dans les alertes, juste dans un comportement dégradé que personne ne relie à la migration.
Cherche la chaîne dans tout le code, y compris les tests et les SDK maison.
5. Les listes d'outils deviennent cachables
La nouvelle révision introduit une sémantique de cache. Ton serveur peut indiquer une durée de validité via ttlMs, et les clients ont le droit de garder tools/list en cache pendant ce temps.
Sur un serveur avec beaucoup d'outils et beaucoup de clients, c'est du trafic en moins et de la latence en moins au premier appel. Mais ça t'oblige à une discipline : si tes outils changent selon le plan de l'utilisateur ou selon un feature flag, un TTL trop long fait apparaître des outils que le client ne peut pas appeler, ou disparaître des outils qui existent. Choisis un TTL cohérent avec ta fréquence réelle de changement, pas la valeur maximale.
6. Trois primitives sont dépréciées
roots, sampling et logging passent en déprécié.
Sampling est celui qui fait mal, parce que c'est le seul dont la disparition change une architecture. Un serveur qui demandait au client de faire tourner un modèle pour lui doit maintenant appeler un fournisseur directement, ou passer par une couche d'inférence à lui. Ça déplace un coût et une clé d'API depuis le client vers toi.
La bonne nouvelle : la spec s'est dotée d'une politique de cycle de vie. Une fonctionnalité dépréciée reste fonctionnelle au moins douze mois avant d'être retirée, et les dépréciations sont suivies publiquement avec des échéances. Tu n'as donc pas à traiter ça dans le même sprint que le reste.
La mauvaise : du code qui compile mais qui lève à l'exécution est plus coûteux à déboguer plus tard qu'à supprimer maintenant. Si tu as des chemins de sampling morts, retire-les pendant que tu as le contexte en tête.
7. L'autorisation se durcit
Trois changements côté OAuth, motivés par la forme réelle des déploiements MCP, où un client parle à beaucoup de serveurs.
Le serveur d'autorisation doit inclure le paramètre iss dans ses réponses, et le client doit valider ce iss contre l'issuer enregistré avant d'échanger le code d'autorisation. C'est une protection contre la substitution de serveur d'autorisation.
Le client doit préciser un application_type approprié à l'enregistrement, pour éviter les conflits de redirect URI côté OpenID Connect.
Les credentials d'un client sont liés au serveur d'autorisation qui les a émis. Il faut donc les stocker indexés par issuer, et se réenregistrer si le serveur d'autorisation change.
Enfin, le Dynamic Client Registration OAuth 2.0 est formellement déprécié comme mécanisme d'enregistrement, au profit des Client ID Metadata Documents. Il continue de fonctionner pour la compatibilité, mais il a une date.
Ce qui ne casse pas
Il faut le dire aussi clairement que le reste, parce que ça change l'urgence :
- Ta définition d'outils, tes schémas d'entrée et tes réponses ne changent pas
- Un client 2026-07-28 sait revenir au handshake
initializeface à un serveur plus ancien - Selon le SDK, un serveur peut répondre aux deux révisions depuis le même endpoint
- Rien ne bascule tant que le client et le serveur n'ont pas bougé tous les deux
Autrement dit, ce n'est pas une migration à faire dans la nuit. C'est une migration à faire proprement, avec une fenêtre de rollback.
Le plan en six étapes
1. Audit statique. Cherche dans tout le dépôt les lectures de session, Mcp-Session-Id, -32002, les appels de sampling, les configurations de sticky sessions. Fais-le sur le serveur, mais aussi sur les clients maison, les passerelles et les fichiers de déploiement. Un audit statique ne prouve pas la compatibilité, il liste les endroits à regarder.
2. Cartographie de l'état. Pour chaque lecture de session trouvée, écris quelle donnée métier était réellement cachée derrière. C'est cette étape que les équipes sautent, et c'est celle qui fait échouer les migrations.
3. Externalisation. Remplace chaque état par un handle explicite, un stockage partagé ou une tâche durable. Choisis une portée et un TTL par type de handle, et prévois la révocation.
4. Mise en conformité protocole. server/discover, métadonnées de version dans _meta, en-têtes Mcp-Method et Mcp-Name avec vérification de cohérence, code d'erreur corrigé, TTL de cache.
5. Test de bascule. Retire les sticky sessions du load balancer et lance un scénario multi-étapes réel pendant que tu tues des instances. Si un workflow survit à un failover en plein milieu, l'externalisation est faite. Sinon, il reste de l'état caché.
6. Fenêtre de rollback. Garde la possibilité de revenir à l'ancienne révision pendant au moins deux semaines de trafic réel, et surveille les erreurs par outil, maintenant que tu peux les compter par outil.
Les erreurs qu'on voit le plus souvent
Migrer le transport sans migrer l'état. Le code est conforme, la session est partie, et l'état vit toujours dans une variable d'instance. Ça passe tous les tests unitaires et ça échoue en prod à la première montée en charge.
Oublier les abonnements et les ressources en tâche de fond. Ils portaient de l'état, ils ne sont pas dans le chemin de requête principal, personne ne les regarde.
Faire confiance aux nouveaux en-têtes. Voir le point 3. Un en-tête déclaratif n'est pas une autorisation.
Traiter les dépréciations dans le même sprint. Douze mois minimum, ce n'est pas le même niveau d'urgence que le transport. Sépare les deux chantiers.
Ne pas mesurer avant. Si tu n'as pas de baseline de latence et de taux d'erreur par outil avant la bascule, tu ne sauras pas dire si la migration a dégradé quelque chose.
FAQ
Est-ce que mon serveur va s'arrêter de fonctionner ?
Non. La bascule est opt-in des deux côtés. Un serveur sur 2025-11-25 continue de répondre aux clients qui parlent cette révision.
Combien de temps prend une migration ?
Pour un serveur simple, en lecture seule, sans état entre appels, quelques jours. Pour un serveur multi-tenant avec OAuth, des workflows multi-étapes et une passerelle devant, compte deux à quatre semaines dont l'essentiel part dans la cartographie de l'état, pas dans le code.
Faut-il migrer avant de soumettre à l'annuaire des connecteurs Claude ?
Pas obligatoirement, mais tu ne veux pas soumettre un serveur que tu vas réécrire trois semaines plus tard. L'ordre logique est : migration, durcissement, puis dossier.
Que faire si je n'ai pas d'équipe protocole ?
C'est le cas normal. La plupart des SaaS ont un serveur MCP écrit par un dev en deux semaines il y a un an, et personne ne suit les SEP depuis. C'est exactement pour ça que l'audit existe.
Où en es-tu vraiment
Envoie ton dépôt ou un accès à ton serveur MCP. Tu reçois sous 24 heures ouvrées un diagnostic écrit : ce qui casse, ce qui ne casse pas, et le chiffrage de la remise à niveau. Gratuit, sans engagement.
Prêt à faire le point ? Faire auditer mon serveur MCP →
Lectures liées
- Serveur MCP sans session : remplacer Mcp-Session-Id par des handles
- Audit de migration MCP : la checklist en 12 points
- Supprimer le handshake initialize : ce qui bouge dans ton code
Sources officielles
Un serveur MCP à faire auditer ?
Cinq minutes pour le décrire. Je réponds sous 24 heures ouvrées avec un premier diagnostic écrit et gratuit.
Faire auditer mon serveur MCP