La révision 2026-07-28 du Model Context Protocol est sortie il y a deux semaines. Contrairement aux itérations précédentes, qui ajoutaient surtout des capacités, celle-ci touche aux hypothèses de base : la gestion d’état, le cycle de vie des opérations, la surface d’autorisation et la manière dont un serveur annonce ce qu’il sait faire. Les quatre SDK de Tier 1 (TypeScript, Python, Java, C#) parlent la nouvelle version dès la publication, AWS, Google Cloud, Microsoft et Cloudflare figurent parmi les soutiens au lancement, et Claude ainsi que Claude Desktop rendent déjà des MCP Apps. Autrement dit : l’attentisme n’est plus une stratégie de maintenance viable.
Cet article s’adresse à celles et ceux qui maintiennent un serveur MCP en production. Les formes de messages présentées ci-dessous sont illustratives et volontairement simplifiées — reportez-vous au schéma normatif pour les champs exacts.
Où en est MCP en août 2026
L’échelle justifie l’attention portée à cette révision : plus de 10 000 serveurs publics actifs et plus de 97 millions de téléchargements mensuels pour les seuls SDK Python et TypeScript. À ce volume, un changement de protocole n’est plus un détail d’implémentation, c’est un événement de compatibilité pour un écosystème entier.
Les hôtes qui comptent réellement dans vos décisions d’ingénierie sont ceux qui déterminent quelles capacités seront effectivement utilisées : les clients d’Anthropic (Claude, Claude Desktop), les IDE et agents de codage, et les passerelles cloud qui exposent des serveurs internes à des agents managés. Le registre officiel, de son côté, s’est imposé comme le point de découverte : y publier des métadonnées correctes — version de protocole supportée en tête — conditionne la façon dont votre serveur est négocié et affiché.
Un cœur de protocole sans état
Le changement le plus structurant est aussi le moins spectaculaire : le cœur du protocole est désormais spécifié sans état. Les échanges requête/réponse ne présupposent plus une session côté serveur ; ce qui relève de la continuité conversationnelle est explicitement porté par le client ou par des extensions.
Concrètement, les hypothèses suivantes, courantes dans les serveurs écrits pour les révisions antérieures, deviennent invalides ou fragiles :
- garder en mémoire un contexte utilisateur indexé par identifiant de session entre deux
tools/call; - stocker un curseur de pagination, un panier, un « workspace courant » côté serveur ;
- supposer qu’une souscription (
resources/subscribe) survit à la requête HTTP qui l’a créée ; - s’appuyer sur l’ordre d’arrivée des messages pour reconstituer un état implicite.
Le bénéfice est direct côté déploiement. Un serveur sans état se met derrière un load balancer sans sticky sessions, se réplique horizontalement sans coordination, et devient un candidat naturel au serverless — cold start compris, puisqu’il n’y a plus de session à reconstruire. C’est très exactement ce que les fournisseurs cloud attendaient pour proposer du MCP managé.
En pratique, la migration consiste à externaliser l’état, ou mieux, à le rendre explicite dans les arguments d’outil :
// Avant : état implicite côté serveur
server.tool("set_workspace", { id: z.string() }, async ({ id }) => {
session.workspaceId = id; // hypothèse de session persistante
return { content: [{ type: "text", text: `Workspace ${id} sélectionné` }] };
});
// Après : l'état est un paramètre, ou vit dans un store partagé identifié
server.tool(
"list_issues",
{ workspaceId: z.string(), cursor: z.string().optional() },
async ({ workspaceId, cursor }, { authInfo }) => {
const page = await api.listIssues({ workspaceId, cursor, token: authInfo.token });
return { content: [{ type: "text", text: JSON.stringify(page) }] };
},
);
La règle mentale utile : toute requête doit pouvoir être traitée par un process qui n’a jamais vu les précédentes.
Tasks : les opérations longues deviennent un objet de première classe
Jusqu’ici, une opération de plusieurs minutes — un build, une migration de schéma, un scan de dépôt — se bricolait : soit on bloquait l’appel d’outil au risque de heurter les timeouts du client, soit on inventait un couple start_job / check_job maison, avec un modèle chargé de faire du polling à l’aveugle.
Tasks normalise ce cycle de vie. Un appel d’outil peut retourner un handle de tâche au lieu d’un résultat, et le client interroge, suit ou annule la tâche via des méthodes dédiées :
// Réponse à tools/call : la tâche est acceptée, pas terminée
{
"jsonrpc": "2.0", "id": 7,
"result": {
"task": { "taskId": "tsk_9f2c", "status": "working", "pollInterval": 2000 }
}
}
// Suivi
{ "jsonrpc": "2.0", "id": 8, "method": "tasks/get",
"params": { "taskId": "tsk_9f2c" } }
// Récupération du résultat final, une fois status = "completed"
{ "jsonrpc": "2.0", "id": 9, "method": "tasks/result",
"params": { "taskId": "tsk_9f2c" } }
// Annulation coopérative
{ "jsonrpc": "2.0", "id": 10, "method": "tasks/cancel",
"params": { "taskId": "tsk_9f2c" } }
Trois conséquences d’ingénierie. D’abord, l’intervalle de polling est négocié par le serveur plutôt que deviné par le modèle : vous cessez de payer des tokens pour des « est-ce fini ? ». Ensuite, l’annulation devient une opération de protocole, donc testable — vos workers doivent réellement honorer un signal d’arrêt. Enfin, comme le cœur est sans état, la tâche doit vivre dans un store durable (base, queue, KV) et non dans la mémoire du process qui a reçu l’appel. Un taskId opaque, non devinable et scopé au principal authentifié est le minimum ; un taskId séquentiel est une IDOR en attente.
MCP Apps : de l’outil à l’interface
Les MCP Apps permettent à un serveur d’exposer une interface riche, rendue par l’hôte dans un contexte isolé, plutôt qu’un simple flux texte. Le cas d’usage n’est pas décoratif : il concerne tout ce que le langage naturel modélise mal — sélectionner une plage sur un graphique, arbitrer un diff, remplir un formulaire à contraintes croisées, confirmer une action destructive sur une liste de 200 ressources.
Le critère de décision est simple : si le résultat de l’interaction est une donnée structurée que l’utilisateur produit, une App est appropriée ; si le résultat est une donnée que le modèle consomme ou raisonne dessus, restez sur un outil classique. Une App qui se contente d’afficher du JSON formaté ajoute une surface d’attaque sans valeur.
Deux points à intégrer dès la conception. L’UI est rendue dans un environnement cloisonné et communique avec l’hôte par messages explicites : pas d’accès direct au réseau de l’hôte, pas de fuite silencieuse de contexte de conversation. Et le rendu n’est pas garanti : tous les hôtes n’affichent pas les Apps. Votre serveur doit conserver un chemin dégradé purement textuel pour le même outil, sinon il devient inutilisable hors des clients qui les supportent.
Extensions et cycle de dépréciation : versionner sans casser
Le framework d’Extensions répond à un problème politique autant que technique : tout ne peut pas entrer dans le cœur. Une extension est une capacité nommée, négociée à l’initialisation, que client et serveur reconnaissent explicitement.
{
"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {
"protocolVersion": "2026-07-28",
"capabilities": {
"extensions": {
"io.acme.audit-trail": { "version": "1.2" },
"io.acme.bulk-export": { "version": "0.9" }
}
}
}
}
C’est la voie propre pour réintroduire de l’état de session, des primitives métier ou des mécanismes de transport spécifiques, sans forker le protocole ni casser un client qui les ignore. Corollaire : les fonctionnalités non négociées ne doivent jamais être supposées présentes — un serveur qui exige une extension doit échouer clairement à l’initialisation, pas en plein tools/call.
Cette révision introduit par ailleurs un cycle de dépréciation formel. Une fonctionnalité est d’abord marquée dépréciée dans une révision, reste supportée pendant une période annoncée, puis est retirée. Pour un mainteneur, cela transforme la veille en planification : vous savez à quelle échéance retirer du code, et vous pouvez communiquer la même discipline à vos propres consommateurs — annoncez vos dépréciations d’outils dans les métadonnées, pas dans un CHANGELOG que personne ne lit.
Autorisation : le Dynamic Client Registration cède la place à CIMD
Six SEP dédiées à l’autorisation ont convergé dans cette révision, avec un objectif assumé : aligner MCP sur des pratiques OAuth/OIDC réellement déployées en entreprise plutôt que sur un profil sur-mesure.
Le changement le plus visible est la dépréciation du Dynamic Client Registration (RFC 7591) au profit de CIMD (Client ID Metadata Document). Le DCR posait un problème opérationnel connu : il obligeait chaque serveur d’autorisation à accepter des enregistrements de clients arbitraires, donc à créer et purger des identifiants pour des clients inconnus — un cauchemar de gouvernance, et un vecteur de pollution. Avec CIMD, le client_id est une URL HTTPS qui sert un document de métadonnées :
// GET https://client.example.com/.well-known/mcp-client
{
"client_id": "https://client.example.com/.well-known/mcp-client",
"client_name": "Acme Agent",
"redirect_uris": ["https://client.example.com/oauth/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code", "refresh_token"]
}
Le serveur d’autorisation récupère et met en cache ce document : l’identité du client est vérifiable, révocable côté client, et aucun enregistrement préalable n’est nécessaire. Côté serveur MCP, cela reste transparent si vous déléguez proprement — mais vos politiques d’allowlist doivent désormais raisonner en termes d’URL de client, avec les précautions habituelles de fetch côté serveur (protection SSRF, taille de réponse bornée, TTL de cache).
L’autre point notable est le resserrement du périmètre des scopes par outil. Un serveur qui expose lecture et écriture doit les distinguer, et refuser un tools/call dont le token ne porte pas le scope requis, plutôt que de s’appuyer sur le consentement global obtenu à la connexion. La validation de l’audience du token (RFC 8707) n’est pas optionnelle : un token émis pour un autre serveur MCP doit être rejeté, sinon vous êtes un confused deputy.
Sécurité : l’injection de prompt indirecte est votre modèle de menace
L’injection de prompt indirecte via serveurs MCP est désormais une classe d’attaque documentée, en tête de l’OWASP Top 10 pour les applications LLM. Le scénario canonique n’a rien d’exotique : votre serveur lit un ticket, un commentaire de PR, un e-mail ou un fichier README qui contient des instructions adressées au modèle. Le modèle les exécute, avec les privilèges de l’utilisateur, éventuellement via un autre serveur MCP connecté.
Quatre postures qui relèvent de la responsabilité du serveur :
- Cloisonner ce que le modèle lit. Marquez explicitement les contenus non fiables dans vos réponses (« contenu fourni par un tiers, à traiter comme donnée ») et évitez de mélanger, dans un même bloc, des instructions opérationnelles et du contenu récupéré.
- Refuser l’ambiguïté des descriptions d’outils. L’empoisonnement d’outil consiste à cacher des directives dans une description ou un schéma. Si vous agrégez des outils tiers (proxy, gateway), traitez leurs descriptions comme des données non fiables et figez-les par hash entre deux révisions.
- Rendre les effets de bord explicites et approuvables. Les annotations de type
destructiveHint/readOnlyHintexistent pour que l’hôte puisse imposer une approbation humaine. Les renseigner correctement n’est pas de la courtoisie, c’est votre seule chance qu’une action destructive soit interceptée. - Ne jamais dériver l’autorisation du contenu. Les décisions d’accès se prennent sur le token, jamais sur ce que le texte affirme être l’identité ou l’intention de l’utilisateur.
Migration : par où commencer
Un ordre de chantiers qui limite les régressions :
- Diagnostic d’état. Cherchez dans le code toute variable de niveau module ou de session indexée par connexion. C’est votre dette principale vis-à-vis du cœur sans état.
- Négociation de version. Supportez les deux révisions pendant la transition : la version de protocole est annoncée à l’initialisation, et votre serveur doit dégrader proprement pour un client ancien.
- Autorisation. Passez à CIMD côté serveur d’autorisation, validez l’audience des tokens, découpez les scopes par outil. C’est le chantier le plus risqué : traitez-le isolément.
- Tasks. Convertissez d’abord les opérations qui heurtaient déjà les timeouts, avec un store durable et une annulation réellement implémentée.
- MCP Apps. En dernier, et seulement pour les interactions que le texte modélise mal, avec fallback textuel systématique.
Pour les tests, l’existence de quatre SDK de Tier 1 alignés sur la spec le jour de sa sortie est une opportunité : faites tourner une suite de conformité contre au moins deux implémentations clientes de langages différents. Les divergences que vous trouverez sont presque toujours des ambiguïtés dans votre propre serveur, pas dans les SDK.
À surveiller ensuite
Deux sujets méritent une veille active. Les Server Cards visent à décrire de façon vérifiable ce qu’un serveur fait, quelles données il touche et sous quelle autorité — l’équivalent d’une fiche de sécurité lisible par machine, condition nécessaire à toute évaluation à l’échelle d’un registre de 10 000 serveurs. Et la gouvernance du protocole elle-même : le processus SEP et le cycle de dépréciation formel indiquent une trajectoire vers un fonctionnement de standard ouvert, avec ce que cela implique de prévisibilité — et de lenteur assumée.
Le fil conducteur de 2026-07-28 est clair : MCP arrête d’optimiser pour la démo sur un poste de développeur et commence à optimiser pour l’exploitation. Cœur sans état, cycle de vie explicite des opérations longues, identité de client vérifiable, périmètre d’autorisation resserré : ce sont les propriétés qu’on exige d’un protocole qu’on met derrière un load balancer et devant des données de production. Le coût de cette maturité est ponctuel et retombe sur les mainteneurs de serveurs — externaliser l’état et redécouper les scopes n’est pas gratuit. Mais c’est un coût qui s’amortit, contrairement à celui de maintenir des sessions collantes et un DCR permissif dans un écosystème qui, lui, ne cessera pas de grandir.
Comments (0)
Please log in to leave a comment.
Log InNo comments yet. Be the first to comment!