Tous les articles

Supprimer le handshake initialize : ce qui bouge dans ton code

La spec MCP 2026-07-28 retire le handshake initialize. Où atterrissent la version de protocole et les capabilities, et comment server/discover remplace la découverte.


Dans toutes les révisions précédentes du Model Context Protocol, une connexion commençait par une poignée de main. Le client envoyait initialize, le serveur répondait avec ses capacités, le client confirmait avec notifications/initialized, et à partir de là les deux parties savaient à qui elles parlaient.

La révision 2026-07-28 supprime cette étape. initialize et notifications/initialized ne sont plus requis. Il n'y a plus de moment où le serveur apprend quelque chose qu'il pourra réutiliser plus tard.

C'est une conséquence directe du passage à un cœur stateless : s'il n'y a plus de session, il n'y a plus rien pour porter le résultat du handshake entre deux requêtes.

Où va l'information qui transitait par le handshake

Elle voyage désormais avec chaque requête, dans le champ _meta, sous deux clés :

  • io.modelcontextprotocol/protocolVersion pour la version de protocole que le client parle
  • io.modelcontextprotocol/clientCapabilities pour ses capacités

Autrement dit, chaque requête se suffit à elle-même. N'importe quelle instance de ton serveur peut la traiter sans avoir vu la précédente, ce qui est exactement l'objectif.

Pour la découverte dans l'autre sens, la spec introduit server/discover. C'est par là que le client apprend quelles versions ton serveur parle et quelles capacités il expose.

Ce que ça casse concrètement chez toi

Le code de handshake lui-même n'est presque jamais le problème. Le problème, c'est tout ce que ton serveur faisait pendant le handshake et gardait ensuite.

Regarde chez toi si l'une de ces choses est initialisée une fois puis réutilisée :

Le contexte utilisateur. Tenant résolu, plan tarifaire, permissions, quotas. Beaucoup de serveurs font une requête base de données au handshake et gardent le résultat. Ça n'existe plus. Ce contexte doit se reconstruire à partir du token de la requête courante, avec un cache court si le coût le justifie, mais un cache qui reste une optimisation et pas une hypothèse de correction.

La négociation de version. Si tu adaptais le comportement de ton serveur selon la version annoncée au handshake, la même décision se prend maintenant par requête, à partir de _meta.

Les capabilities du client. Même logique. Tu les lis à chaque appel plutôt qu'une fois.

La liste d'outils personnalisée par client. C'est le piège le plus courant. Beaucoup de serveurs renvoyaient une liste d'outils différente selon le plan de l'utilisateur, calculée au handshake. Or les endpoints de liste ne varient plus par connexion. Si tes outils dépendent du plan, tu dois maintenant exposer la liste complète et refuser proprement à l'appel, avec un message clair, plutôt que de masquer l'outil.

Ce dernier point mérite d'être décidé consciemment, parce qu'il change ce que l'utilisateur voit. Un outil visible mais refusé avec un message du type « cet outil nécessite le plan Pro » est souvent une meilleure expérience qu'un outil invisible, et c'est aussi une meilleure conversion. Mais c'est un choix produit, pas seulement une migration technique.

Ce qui continue de marcher

La compatibilité descendante est prise en charge, et c'est ce qui rend la migration sereine.

Un client qui parle 2026-07-28 sait retomber sur le handshake initialize quand il tombe sur un serveur en 2025-11-25 ou plus ancien. Les anciens serveurs et les nouveaux clients continuent donc de fonctionner ensemble.

Côté serveur, le comportement dépend du SDK. Un serveur Python en v2 répond aux deux révisions depuis le même endpoint. Le transport HTTP de la préversion C# passe en mode stateless par défaut. Vérifie le comportement exact de ton SDK avant de planifier, parce que ça change la stratégie : soit tu peux servir les deux et migrer tranquillement, soit tu dois basculer d'un coup avec une fenêtre de rollback.

Le test qui révèle le problème

Le handshake supprimé ne provoque pas d'erreur bruyante. Il provoque des comportements dégradés difficiles à relier.

Le test utile est simple : envoie une requête isolée, sans rien avant elle, depuis un client qui n'a jamais parlé à cette instance, et vérifie qu'elle produit exactement le même résultat que la même requête en milieu de conversation. Si ce n'est pas le cas, quelque chose dépend encore d'un état construit en amont.

Refais le test sur chaque outil, pas seulement sur un. Les dépendances au handshake sont rarement uniformes dans un serveur.

FAQ

Est-ce que je dois supprimer mon code initialize ?

Pas si ton serveur sert encore d'anciens clients. Tu le gardes comme chemin de compatibilité, mais tu arrêtes de faire dépendre quoi que ce soit de son passage.

Comment savoir quelle version un client parle ?

Elle est dans _meta sur chaque requête. C'est plus fiable qu'avant, puisque l'information ne peut plus se perdre entre deux appels.

Est-ce que ça augmente la charge sur ma base de données ?

Oui, si tu résolvais le contexte utilisateur une seule fois par connexion. C'est le vrai coût de cette migration. La réponse habituelle est un cache court côté serveur, indexé par token, avec un TTL de quelques secondes à quelques minutes. Ce cache reste une optimisation : ton serveur doit rester correct si le cache est vide.

Ton serveur dépend peut-être du handshake sans que tu le saches

C'est le genre de chose qui se voit en lisant le code, pas en lisant la doc. Envoie-moi ton dépôt, tu reçois sous 24 heures ouvrées la liste des dépendances au handshake et leur coût de suppression.

Prêt à faire le point ? Faire auditer mon serveur MCP →

Lectures liées

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
Supprimer le handshake initialize : ce qui bouge dans ton code