Accueil / Articles

Migrer un serveur MCP vers la spécification 2026-07-28 : vingt minutes, étape par étape

Migrer un serveur MCP vers la spécification du 28/07/2026 en environ vingt minutes : disparition des sessions, cinq changements importants à connaître, étapes pour le SDK Python 2.0 et la réécriture de MRTR.

Éditeur : REACTAPP.TOP10 min de lecture2207 mots

Sources: Your MCP Server Is Running on a Deprecated Spec. Here’s the 20-Minute Migration.

Rien ne s’est brisé, et c’est justement ce qui est inquiétant. Le 28 juillet 2026, le Model Context Protocol a publié sa spécification 2026-07-28, la plus importante modification depuis l’apparition initiale du MCP à distance. Une en-tête sur lequel les serveurs comptaient a été retiré et le modèle de transport a changé de forme, mais la compatibilité a été maintenue. Les serveurs ont continué à fonctionner sans trace d’erreur, sans alerte ni indication de build défaillante.

C’est ce genre de dette technique silencieuse. Elle reste cachée jusqu’à ce que quelqu’un ait besoin d’élargir les capacités, ou jusqu’à ce que la période de dépréciation de douze mois se termine et qu’une dépendance cesse d’être maintenue. Un serveur utilisant encore la version 2025-11-25 est donc en retard par rapport aux dernières mises à jour. Un serveur fonctionnant avec le transport HTTP+SSE obsolète utilise désormais une technologie dépréciée, de même que trois fonctionnalités dont le support est peut-être sur le point de prendre fin.

Ce qui suit décrit ce qui a changé, pourquoi les mainteneurs l’ont fait et comment se mettre à jour. Pour la plupart des serveurs, cela représente une vingtaine de minutes de travail. Cependant, un changement concerne une réécriture complète pour certains serveurs, et il vaut mieux le préciser dès le début.

Pourquoi les sessions ont disparu

La motivation technique explique tout le reste. MCP a été lancé à la fin de 2024 en tant que protocole orienté sessions : le client commence par une séquence d’initialisation initialize, le serveur émet un Mcp-Session-Id, et chaque demande ultérieure le transporte. Cela convenait au cas initial où il y avait un seul client et un seul serveur sur une même machine via stdio.

Puis les serveurs ont été déplacés sur des infrastructures réelles, et la conception a rencontré des limites. Les ingénieurs de Google l’ont décrit dans leur rapport sur la mise à jour sans état : une conception idéale pour un seul client local a cessé de fonctionner une fois que les serveurs MCP ont été répartis sur des infrastructures cloud natives.

Considérez ce qu’exige un identifiant de session : soit un routage « sticky », permettant à un client d’accéder toujours à la même instance, soit un stockage de sessions partagé que toute instance peut interroger. Un service HTTP classique a soudainement besoin d’un équilibrage de charge tenant compte de l’affinité, ainsi que d’un outil comme Redis, rien que pour assurer le transport, avant même de pouvoir effectuer des tâches utiles.

Le post de publication de David Soria Parra et Den Delimarsky le formule clairement : MCP passe d’un protocole bidirectionnel et à état à un protocole sans état basé sur des requêtes/réponses, ce qui faisait partie des changements les plus demandés par les développeurs souhaitant plus de fiabilité et de scalabilité. L’urgence est liée à l’ampleur : les SDK de niveau 1 connaissent près de 500 millions de téléchargements par mois, tandis que les SDK TypeScript et Python ont chacun dépassé le milliard de téléchargements au total. Un protocole à cette échelle ne peut pas continuer à exiger que chaque déploiement résolve le problème de l’affinité des sessions.

Ainsi, la session n’existe plus. Chaque requête contient sa propre version de protocole, son identité de client ainsi que ses capacités, ce qui signifie que toute requête peut atteindre n’importe quelle instance derrière un équilibreur circulaire simple sans stockage partagé. Tout ce qui suit en découle.

Cinq changements à comprendre

1. Pas de handshake, pas d’en-tête de session

L’échange initialize et initialized ainsi que l’en-tête Mcp-Session-Id ont été officiellement supprimés (SEP-2575 et SEP-2567). Chaque requête fonctionne de manière indépendante, avec la version, l’identité du client et ses capacités dans le champ _meta. Une requête selon la nouvelle spécification a l’aspect suivant :

POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search

{"jsonrpc":"2.0","id":1,"method":"tools/call",
 "params":{"name":"search","arguments":{"q":"otters"},
 "_meta":{"io.modelcontextprotocol/clientInfo":
              {"name":"my-app",
                "version":"1.0"}
          }}}

Un client qui souhaite connaître les capacités d’un serveur à l’avance peut utiliser le nouveau RPC server/discover, qui est optionnel et ne constitue plus une étape obligatoire de connexion.

Une crainte courante est que les applications ne puissent plus conserver un état. Ce n’est pas le cas : elles le peuvent toujours. La suppression de la session du protocole n’oblige pas une application à être sans état. Lorsqu’un serveur a besoin de continuité, un outil doit générer une identifiant explicite que le modèle restituera plus tard en tant qu’argument. Cela fonctionne mieux que de stocker l’état dans le mécanisme de transport, car le modèle peut voir cet identifiant et le transmettre d’un outil à l’autre. Un état visible est préférable à un état invisible.

2. Deux en-têtes obligatoires

Désormais, les requêtes HTTP de Streamable doivent contenir Mcp-Method et Mcp-Name (SEP-2243), et le serveur doit confirmer qu’elles correspondent à la requête. Avantages pour l’infrastructure : un gateway, un limiteur de débit ou un WAF peut router et mesurer l’utilisation en se basant sur ces en-têtes, tout en évitant l’analyse JSON. Ceux qui avaient abandonné le limiteur de débit par outil en raison du nom de l’outil caché à l’intérieur du payload disposent désormais d’une solution.

3. Réponses de liste pouvant être mémorisées

Les résultats de tools/list, prompts/list, resources/list et resources/read incluent désormais ttlMs et cacheScope (SEP-2549) et sont renvoyés dans un ordre déterministe. Les clients peuvent mettre en cache votre catalogue d’outils et maintenir la stabilité des caches de prompts en amont lors des reconnections. Étant donné que une grande partie de la consommation de tokens d’un agent provient des définitions d’outils envoyées à plusieurs reprises, cela constitue également un avantage en termes de coûts.

4. Autorisation plus stricte

Quatre modifications ont été appliquées, dont une pourrait expliquer un bug avec lequel vous avez déjà dû faire face :

  • Les serveurs d’autorisation doivent renvoyer le paramètre iss défini dans RFC 9207, et les clients doivent le vérifier avant d’échanger un code (SEP-2468), ce qui ferme une faille d’attaque liée aux confusions.
  • Les clients définissent application_type lors de l’inscription dynamique du client (SEP-837), ce qui fait que les serveurs d’autorisation cessent de refuser les redirections vers localhost pour les applications de bureau et les CLI. Si le flux OAuth d’une CLI a déjà échoué en raison d’une erreur redirect_uri, c’est probablement pour cette raison.
  • Les identifiants du client sont liés à l’émetteur qui les a créés et ne peuvent pas être réutilisés entre différents serveurs d’autorisation (SEP-2352).
  • L’inscription dynamique du client est officiellement dépréciée au profit des documents de métadonnées d’ID de client. Elle fonctionne encore mais sera supprimée dans une version ultérieure.

5. La liste des éléments dépréciés

Le terme « déprécié » a ici une grande importance. Roots, Sampling and Logging (SEP-2577) sont dépréciés mais fonctionnels, avec au moins douze mois avant leur suppression définitive, et de nouvelles implémentations ne devraient pas les adopter. Le transport HTTP+SSE obsolète est également déprécié, avec un délai d’un an pour passer à une alternative.

Les tâches ont été déplacées, non dépréciées. Elles sont passées du noyau expérimental à l’extension io.modelcontextprotocol/tasks, consultées via tasks/get et mises à jour grâce à la nouvelle fonction tasks/update (SEP-2663). Les notifications de modification circulent désormais via un seul flux subscriptions/listen auquel les clients peuvent s’abonner.

La meilleure nouvelle est l’existence d’une politique de dépréciation formelle prévoyant une période minimale de douze mois. Selon Real Python, un délai minimal de 90 jours ne s’applique qu’aux risques de sécurité actifs, ce qui représente un préavis plus long que jamais auparavant dans cet écosystème. Cette politique est peut-être plus importante que tout le reste dans cette version, car elle distingue un protocole destiné aux expérimentations d’un protocole sur lequel on peut construire des entreprises.

La migration, étape par étape

La démarche utilise le SDK Python, dont la rénomination est la plus perturbatrice des quatre, bien que la structure reste identique en TypeScript, Go et C#.

Minutes 0 à 2 : décider. Si le serveur utilise l’échantillonnage, l’élucidation ou les racines, il nécessite une véritable réécriture, abordée ci-dessous. S’il ne propose que des outils et des ressources, continuer.

Minutes 2 à 5 : mettre à jour le SDK. Le SDK Python a atteint la version 2.0.0 le jour où les spécifications ont été publiées, et pip install mcp télécharge désormais la branche 2.x.

pip install --upgrade "mcp>=2"

Un changement important à connaître : le SDK a été déplacé de httpx à httpx2. Si httpx est utilisé ailleurs dans votre arborescence de dépendances, résolvez ce problème dès maintenant.

Minutes 5 à 10 : renommez la classe. Tous les serveurs Python en sont affectés. FastMCP devient maintenant MCPServer, sans alias ni mécanisme de dépréciation :

# Before, on mcp 1.x
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Demo")

# After, on mcp 2.x
from mcp.server.mcpserver import MCPServer

mcp = MCPServer("Demo")

Trois autres renommages font partie de cette même mise à jour :

# Wire types are snake_case now
result.isError        # → result.is_error
tool.inputSchema      # → tool.input_schema

# The error class matches the new capitalisation
except McpError:      # → except MCPError:

mcp-types est désormais un package indépendant, mais mcp.types reste la voie d’importation prise en charge, de sorte que ces imports continuent de fonctionner. Précaution : ceux qui utilisent le package autonome fastmcp au lieu du SDK officiel ne sont pas affectés. Il s’agit d’un projet distinct avec ses propres versions 3.x, et l’une des raisons du changement de nom est justement de les séparer.

Minutes 10 à 15 : supprimer les mécanismes de session. Les dictionnaires de session, les temporisateurs de nettoyage ainsi qu’une instance Redis créée uniquement pour le stockage de l’état de session peuvent tous être supprimés. Si une continuité entre les appels est vraiment nécessaire, utilisez le modèle de handle :

# Instead of hiding state in a session the model can't see:
@mcp.tool()
def open_dataset(path: str) -> str:
    """Open a dataset and return a handle for subsequent calls."""
    handle = register_dataset(path)     # your own store, your own TTL
    return handle                        # the model now HOLDS this

@mcp.tool()
def query_dataset(handle: str, query: str) -> list[dict]:
    """Query a previously opened dataset."""
    return lookup(handle).query(query)

Minutes 15 à 18 : valider les nouveaux en-têtes. Le serveur doit vérifier que les valeurs Mcp-Method et Mcp-Name reçues correspondent à la demande. Le SDK gère le cas habituel, mais derrière un gateway personnalisé ou un mécanisme de transport écrit manuellement, il est nécessaire de le vérifier de bout en bout.

Minutes 18 à 20 : corriger le code d’erreur. Il est facile de l’oublier, ce qui entraîne un comportement confus du client. Les erreurs liées à l’absence de ressource doivent utiliser le code JSON-RPC standard -32602 pour les paramètres invalides, et non le code -32002 propre à MCP.

Prêt pour le déploiement

Un seul MCPServer prend en charge les deux époques du protocole, de sorte qu’un client de l’époque 2025 continue de fonctionner avec un serveur migré sans qu’aucune configuration soit nécessaire de part et d’autre. C’est pourquoi cela peut être déployé un mardi ordinaire, sans nécessiter de journée spéciale coordonnée entre tous les clients.

Lorsque cela prend plus de temps

Les serveurs utilisant l’échantillonnage, l’élucidation ou d’autres méthodes similaires doivent être entièrement réécrits, ce que Real Python qualifie de tâche la plus importante de la liste de migration. Auparavant, le serveur pouvait initier une demande et communiquer avec le client via un flux bidirectionnel maintenu ouvert. Une architecture sans état ne dispose pas de tel flux ; par conséquent, on recourt à des requêtes en plusieurs allers-retours (SEP-2322).

Le nouveau flux de travail fonctionne de la manière suivante : le serveur répond avec resultType: “input_required” ainsi que les questions auxquelles il faut des réponses, puis le client réitère la demande initiale en incluant ses réponses dans inputResponses. Cela modifie la manière dont les outils sont conçus. Un gestionnaire ne peut pas s’arrêter en cours de route pour attendre une réponse. Il peut être appelé plusieurs fois pour une même opération logique et doit pouvoir reprendre correctement le traitement dès l’arrivée des données d’entrée ; par conséquent, tout ce qui est stocké dans des variables locales pendant cette pause doit être conservé à un endroit accessible en cas de tentative de réessai.

Les avantages sont réels. Le responsable du produit chez Supabase a indiqué que cette fonctionnalité figurait depuis longtemps au programme de développement, mais qu’elle n’était pas réalisable car leur serveur MCP fonctionne sans stockage d’état, tandis que MRTR rend cela possible, en permettant aux outils de demander d’abord l’approbation de l’utilisateur, par exemple pour connaître le coût d’un nouveau projet ou pour une requête susceptible de supprimer des données. Écrire un tel outil devient légèrement plus complexe, mais il devient possible de le faire fonctionner à grande échelle sans stockage d’état.

Ce que le nouveau protocole apporte

Manufact héberge des milliers de serveurs MCP et maintient le framework open source mcp-use. Il a constaté que la version SDK v2 était environ 83 % plus petite et 25 % plus rapide, ce qui est dû à la nouvelle architecture client-serveur. Selon le bilan de l’écosystème de la Agentic AI Foundation, un serveur fonctionne désormais comme n’importe quel autre service HTTP, répondant depuis l’instance choisie par un équilibreur round-robin, tandis que les passerelles gèrent le routage et imposent des limites de vitesse via des en-têtes. La politique de douze mois signifie que le protocole ne continuera pas à évoluer de manière imprévisible.

Le déploiement a été rapide pour un standard ouvert. En quelques jours à peine, les fournisseurs d’infrastructure, les mainteneurs de SDK, les plateformes cloud et les vendeurs d’outils ont annoncé leur soutien, publié des notes de migration et sorti des implémentations en production. Le SDK Agents de Cloudflare a géré les spécifications dès le premier jour, Amazon Bedrock AgentCore propose un noyau sans état, et Microsoft Foundry, Netlify, Figma, Supabase et Honeycomb se sont également joints à l’effort. Honeycomb indique que près d’un agent sur cinq de ses requêtes interactives mensuelles provient désormais de ces agents, ce qui explique l’importance de ce développement. Les agents sont désormais sortis de la phase de démonstration.

Rester sur la version 1.x

C’est un choix légitime. Fixer la version et attendre :

# Buys you time, keeps security patches coming
pip install "mcp>=1.28,<2"

Apprenez deux choses pendant ce temps. La ligne 1.x est en mode maintenance, ne recevant que des correctifs de sécurité. De plus, l’extension Tasks n’est pas encore incluse dans la version 2.0 du SDK Python, ce qui signifie que Tasks a quitté la spécification principale sans faire partie du SDK. Pour les utilisateurs Python qui dépendent de Tasks, il est préférable d’attendre. Ajoutez un rappel dans votre calendrier pour la date du douzième mois concernant Roots, Sampling et Logging, car les périodes de dépréciation semblent interminables jusqu’à leur fin.

Le danger de la dépréciation silencieuse

Un changement brisant est évident : il fait échouer la compilation, alerte les utilisateurs et est rapidement corrigé. La dépréciation, elle, est conçue pour être discrète. Le serveur continue de fonctionner, les tests passent et rien ne s’affiche en rouge, tandis que les problèmes s’accumulent : un mécanisme de transport avec une date d’expiration, aucune possibilité de mise à l’échelle horizontale facile, et une dépendance en mode maintenance alors que l’écosystème progresse. La valeur indiquée dans MCP-Protocol-Version est une date, et il est utile de vérifier son âge actuel.

Pour la plupart des serveurs, il suffit au plus d’une après-midi, et moins d’une demi-heure de travail réel, pour rattraper le retard. Les serveurs utilisant des méthodes d’échantillonnage ou d’élucidation doivent prévoir une journée entière et lire d’abord la spécification MRTR. Dans tous les cas, faites-le avant que les douze mois ne se transforment silencieusement en deux ans.