Il y a quelques années, j’ai aidé à déplacer une application des sessions persistantes afin que nous puissions évoluer derrière un équilibreur de charge à tour de rôle ordinaire. Sur le papier, il s’agissait d’un changement d’infrastructure. Chaque service était censé être sans état, donc la suppression de l’affinité de session n’aurait rien dû changer.

Rien ne s’est écrasé. Le processeur avait l’air normal. Chaque bilan de santé est resté vert. Mais les utilisateurs ont commencé à signaler des flux de travail qui reculaient de manière aléatoire. Une demande reprendrait exactement là où la précédente s’était arrêtée. Le suivant se comporterait comme s’il appartenait à une conversation totalement différente.

Le bug ne venait pas de notre logique métier. Il s’agissait d’une hypothèse dont nous avions hérité quant à l’endroit où se situait la corrélation. Nous nous sommes tranquillement appuyés sur la plateforme pour nous rappeler quelles demandes allaient ensemble. Une fois cette responsabilité disparue, notre candidature n’a pas échoué bruyamment. Cela est devenu incohérent d’une manière très difficile à reproduire.

Nous l’avons résolu de la manière la plus évidente. Nous avons arrêté de nous fier à la plateforme et avons commencé à transmettre un identifiant explicite à chaque demande. Cela a fonctionné, et cela a continué à fonctionner, car la chose portant cet identifiant a fait exactement ce que nous lui avons demandé de faire.

C’est l’incident auquel je n’arrêtais pas de penser pendant que je lisais la nouvelle spécification Model Context Protocol.

Lorsque MCP a expédié son noyau apatride le 28 juillet, j’ai fait ce que tout le monde a fait. J’ai ouvert le journal des modifications, trouvé les notes de migration du SDK et défini le travail. La différence de code était plus petite que ce à quoi je m’attendais. J’ai pris cela comme une bonne nouvelle pendant environ quatre heures.

Je l’avais lu comme un changement de transport. Sessions terminées, requêtes autonomes, pas de routage persistant. Tout est vrai et tout est couvert ailleurs. Ce qui m’a manqué, c’est ce que les responsables avaient fait avec la corrélation.

Ils ne l’ont pas supprimé.

Ils l’ont remis au mannequin.

Ce que la spécification a réellement déplacé

La publication contient des conseils destinés aux serveurs qui ont encore besoin d’un état lors des appels : créez un identifiant explicite à partir d’un outil, tel qu’un identifiant de panier ou un identifiant de navigateur, puis demandez au modèle de le renvoyer comme argument ordinaire lors des appels ultérieurs. Les responsables comprennent clairement pourquoi. Le modèle peut voir le handle et le faire passer entre les outils, au lieu de cacher l’état dans une connexion que vous ne pouvez pas inspecter.

D’un point de vue technique, je pense qu’ils ont raison. Il évolue, survit à un équilibreur de charge et correspond au fonctionnement des API HTTP depuis des décennies.

Mais relisez-le en tant qu’opérateur. L’identifiant que votre serveur utilise pour décider quel panier, quel document ou quel locataire est désormais porté par un modèle de langage, conservé dans sa fenêtre contextuelle et réémis ultérieurement.

Nous venons d’intégrer un LLM au chemin de la requête. Ce n’est pas une phrase que je m’attendais à écrire sur une spécification de transport.

Cela signifie que l’exactitude de votre serveur dépend désormais, en partie, du modèle qui porte fidèlement un identifiant d’un tour à l’autre.

Il y a une objection que j’entends à chaque fois. MCP a toujours été apatride, dans le sens qui compte, disent les gens. Il n’a jamais retenu votre panier. Il n’a jamais stocké votre demande d’extraction. Connectez un calendrier et le modèle ne connaîtra pas la réunion que vous avez ajoutée il y a dix minutes jusqu’à ce que quelque chose la récupère. Tout est correct et tout est vrai depuis le lancement.

Mais le MCP a toujours eu deux types d’État. Le premier concerne les données de votre application, qui résident dans votre application, dans GitHub ou dans Outlook. MCP n’en a jamais été propriétaire et ne l’est toujours pas.

Le second est l’état de la session du protocole : la prise de contact, les capacités négociées et l’identifiant de session qui ont indiqué au serveur que deux requêtes appartenaient à la même conversation. MCP en était propriétaire, et c’est celui-là qui a disparu.

La confusion va dans une direction commode. Si vous pensez que MCP a toujours été sans état, cette version ressemble à une optimisation de mise à l’échelle sans conséquences architecturales.

Ce n’est pas le cas.

Le protocole n’a pas supprimé l’état de votre application. Il a déplacé la corrélation, hors d’une session gérée par un protocole, vers un argument que le modèle portait d’un tour à l’autre.

Nous avons des mesures à ce sujet

Ce qui transforme cela d’une observation en quelque chose qui blesse les équipes, c’est que le fait d’enfiler un identifiant à travers les tours n’est pas nouveau. Il a un nom dans la littérature de recherche. La fusion d’informations entre tours est l’un des modes de défaillance les plus étudiés dans le comportement des modèles multitours.

« LLMs Get Lost in Multi-Turn Conversation », un article exceptionnel présenté à l’ICLR 2026, a présenté plus de 200 000 conversations simulées sur quinze principaux modèles ouverts et fermés. Il a constaté une baisse moyenne des performances de 39 % dans les réglages multitours par rapport aux réglages monotour avec des informations identiques. L’appel de fonction était l’une des six tâches testées.

Premièrement, comment la dégradation se décompose. L’aptitude chute d’environ 16%. Le manque de fiabilité augmente de 112 %. Les modèles restent performants et deviennent considérablement moins cohérents. Si vous avez livré quelque chose d’agentique, vous savez à quoi cela ressemble vu de l’extérieur : un système qui fonctionne dans chaque démo, réussit tous les tests que vous avez écrits, puis produit un résultat inexplicable par semaine que personne ne peut reproduire.

Deuxièmement, tout ne s’est pas dégradé. La traduction, qui peut être effectuée phrase par phrase sans dépendance entre les tours, n’a montré aucune dégradation. Ce qui s’est effondré, ce sont les tâches qui nécessitaient que les informations soient transmises d’un tour à l’autre et fusionnées.

C’est exactement ce qu’est une poignée.

Ainsi, le protocole a déplacé l’état de session vers le seul endroit où les modèles de preuves ont le plus de difficulté : transmettre des informations de manière fiable d’un tour à l’autre. Il l’a fait pour de bonnes raisons.

C’est un mode de défaillance que j’ai rencontré à plusieurs reprises sur les systèmes agents, et c’est pourquoi je suis devenu insupportable en matière d’observabilité. Lorsqu’un modèle transmet le mauvais handle, votre serveur ne reçoit pas d’erreur. Il obtient une requête bien formée avec un argument d’apparence valide. Si la poignée pointe vers un objet réel, l’appel réussit.

Aucune ligne de journal n’indique que le modèle a perdu le fil. Aucune métrique ne devient rouge. Une session qui se divise discrètement en deux paniers à moitié remplis ressemble exactement à un utilisateur qui a changé d’avis.

Red Hat a récemment publié un rapport sur l’incident qui en montre la forme, sans MCP impliqué. Un agent devait facturer le compte A. L’identifiant figurait directement dans son invite. Le modèle a sélectionné le compte B. L’API de facturation a accepté l’appel et quatre mille dollars ont été attribués au mauvais client. Il avait passé avec succès tous les tests de mise en scène.

Dans un logiciel ordinaire, un appel mal acheminé est contenu par deux éléments : la portée des informations d’identification limite ce qu’une charge de travail peut atteindre, et l’API en aval impose les paramètres valides pour cet appelant. Personne ne livrerait une application Web dans laquelle un ensemble d’informations d’identification pourrait être écrit dans le dossier de facturation de chaque client. Nous expédions des agents comme ça tout le temps.

Maintenant, prenez cet échec et faites de l’identifiant quelque chose que le modèle transporte à travers les tours au lieu de quelque chose qui lui est transmis en une seule invite.

Il y a une conséquence de second ordre que je n’ai pas vue évoquée. Suivez la chaîne. Le comportement de votre serveur dépend du handle. La poignée est portée par le modèle. Le modèle est choisi par le client et non par vous.

Ainsi, la fiabilité de votre serveur MCP dépend désormais, en partie, du modèle utilisé par le client. Cela varie selon les fournisseurs, selon les mises à niveau de modèles et selon le même client au fil du temps. L’article de l’ICLR a révélé une répartition significative entre les quinze modèles testés. Votre suite d’intégration s’exécute sur l’un d’entre eux.

Ce que je fais à ce sujet

Rien d’exotique. Les contrôles sont ordinaires. Seule la raison est nouvelle.

J’autorise chaque manipulation contre l’appelant authentifié pour chaque demande, sans exemption pour les outils internes. Je leur donne une véritable entropie et des durées de vie courtes. J’utilise des clés d’idempotence afin qu’une nouvelle tentative après une poignée perdue ne crée pas silencieusement un deuxième objet. Et je teste à la profondeur de virage trente plutôt qu’au premier virage, car c’est dans le premier virage que tous ces systèmes semblent bien.

La lecture contradictoire de ceci n’est pas la mienne. L’équipe de recherche sur les menaces d’Akamai est arrivée la première et SecurityWeek l’a couvert avant la spécification finale : une fois les sessions de protocole terminées, les poignées qui les remplacent deviennent la surface d’attaque, ouvrant la voie au détournement de flux de travail, à la lecture des données d’un autre agent et aux actions entre locataires.

J’ajouterais une ride.

Un identifiant de session résidait dans un en-tête de protocole que le modèle n’a jamais vu. Un handle se trouve dans la fenêtre contextuelle, juste à côté de ce que le dernier appel d’outil a renvoyé. Si l’un de vos outils ingère du contenu non fiable, qu’il s’agisse d’une page Web, du corps d’un ticket ou d’un e-mail client, votre identifiant d’état et le texte d’un attaquant se trouvent désormais dans le même contexte, interprétés par le même modèle.

Je préfère avoir des descripteurs explicites que je peux auditer plutôt que l’état de session caché dans une connexion. C’est la meilleure architecture et j’aurais voté pour.

Mais il y a une différence entre un État que vous pouvez voir et un État auquel vous pouvez faire confiance.

Cette version a résolu le premier problème en introduisant le second.

Ce qui laisse la question à laquelle je ne peux m’empêcher de penser.

Si l’identifiant est désormais véhiculé par le modèle, quelle est exactement la limite qui décide si on aurait dû lui faire confiance en premier lieu ?

Ce n’est plus une question de transport.

C’est une question d’identité, et la réponse ne figure pas dans cette spécification.

A lire également