WebMCP est une API navigateur en cours de spécification qui permet à une page web d'exposer des tools — des fonctions décrites par un schéma — qu'un agent IA peut découvrir et appeler directement, sans passer par le DOM. Par agent, on entend ici l'assistant IA intégré à un navigateur — Gemini in Chrome, par exemple : la fonctionnalité qui permet de lui parler en langage naturel depuis une barre latérale, et qui peut agir sur la page que l'utilisateur a ouverte. Trois rôles distincts entrent en jeu : la page, qui déclare les tools ; l'agent, qui les découvre et les appelle ; et le modèle (le LLM) qui pilote cet agent et décide quoi appeler. C'est la même famille de vocabulaire que le Model Context Protocol côté serveur — tool, schéma JSON, les mêmes primitives que dans tools vs resources — mais transposée dans l'origine d'une page web plutôt que dans un process serveur.
Le problème que ça résout
Aujourd'hui, un agent qui veut faire agir un site à la place de l'utilisateur a deux options, et la spec les nomme explicitement comme le problème à résoudre : parser le DOM et cliquer à l'aveugle (fragile, casse à chaque refonte), ou passer par une intégration backend séparée — un serveur MCP dédié — qui duplique l'authentification et l'état de l'utilisateur en dehors de l'UI qu'il utilise déjà. Les auteurs de WebMCP appellent ça la disintermediation : l'agent contourne l'interface web du service au lieu de s'appuyer dessus. WebMCP propose une troisième voie : la page réutilise son code JavaScript existant et l'expose directement comme tool, dans le même contexte, avec le même état de session que ce que voit l'utilisateur.
Le flux complet
Le README du projet décrit la séquence en 8 étapes ; ramenée à un exemple concret sur ce blog — une page qui expose un tool search_articles — ça donne :
- L'utilisateur formule une demande en langage naturel à l'agent de son navigateur : « trouve-moi les articles sur la sécurité MCP ».
- L'agent découvre les tools déclarés par la page ouverte, via
document.modelContext.getTools()— ici,search_articles. - L'agent transmet ce tool et la demande de l'utilisateur au modèle qui le pilote (cloud ou on-device — la spec ne dit rien sur ce point).
- Le modèle choisit d'appeler
search_articlesavec{ query: "sécurité" }, et le communique à l'agent — pas encore de réponse pour l'utilisateur à ce stade. - L'agent invoque réellement le tool via
document.modelContext.executeTool(). - Le callback
execute()de la page tourne dans son propre contexte JS — pas dans celui de l'agent — et renvoie un résultat structuré : 3 articles, chacun avec un titre et un slug. - Ce résultat structuré remonte au modèle, qui décide quoi en faire.
- Le modèle formule une réponse : « J'ai trouvé 3 articles sur la sécurité MCP : Sécuriser un serveur MCP, Sandboxer les tool calls, Injection de prompt : défense. Je t'ouvre le premier ? »
À aucun moment l'agent n'a lu le HTML de la page ni deviné où se trouvait un champ de recherche : il a appelé une fonction avec des arguments définis par un schéma, et reçu une réponse structurée en retour.
Si l'utilisateur répond « oui », c'est toujours le même agent qui agit — mais plus via un tool WebMCP. Il utilise sa capacité générale de navigation, celle qu'il a de toute façon, pour charger l'article dans l'onglet, en construisant l'URL à partir du slug renvoyé à l'étape 6. Cette navigation-là est en dehors du périmètre de WebMCP : la spec couvre l'appel de tools sur une page ouverte, pas la façon dont un agent passe d'une page à l'autre. C'est justement pour ça que search_articles renvoie un slug avec chaque titre : le titre sert à formuler la réponse, le slug sert à construire cette URL. Un tool qui ne renverrait que du texte à afficher n'aurait rien à offrir pour cette suite.
Vu côté développeur, la question n'est donc pas « dois-je exposer toute mon UI en WebMCP » mais « quelles actions de mon site un agent devrait pouvoir accomplir de façon fiable, plutôt que de les deviner en cliquant à l'aveugle ». D'après les objectifs affichés par la spec elle-même, ce n'est ni de la navigation headless sans UI, ni des agents totalement autonomes : le cas d'usage visé garde un humain dans la boucle, qui voit le résultat s'afficher dans la même interface qu'il utilise déjà.
La mécanique de l'API
Un tool se déclare avec un nom, une description en langage naturel, un JSON Schema pour les arguments, et une fonction execute :
document.modelContext.registerTool({
name: 'search_articles',
description: 'Recherche des articles du blog par mot-clé ou tag',
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', description: 'Terme de recherche' }
},
required: ['query']
},
async execute({ query }) {
// searchArticles() renvoie [{ title, slug }, ...] — le slug est ce qui
// permet à l'agent d'agir ensuite (naviguer), pas seulement d'afficher.
const results = searchArticles(query);
return { content: [{ type: 'text', text: JSON.stringify(results) }] };
},
annotations: { readOnlyHint: true }
});
Côté agent, la découverte se fait via getTools(), l'appel via executeTool(tool, arguments). Le désenregistrement passe par un AbortSignal transmis à l'inscription plutôt que par une méthode unregister dédiée — pratique pour un composant qui apparaît et disparaît du DOM (un modal, un onglet). Un événement toolchange permet à l'agent de se tenir à jour quand la page ajoute ou retire des tools selon l'état de l'UI.
| MCP (serveur) | WebMCP | |
|---|---|---|
| Où ça tourne | Process serveur ou desktop dédié | Dans la page, origine par origine |
| Transport | JSON-RPC (stdio, HTTP) | Appel JS direct, pas de sérialisation réseau |
| Client typique | Claude Desktop, un IDE, un agent backend | Un agent intégré au navigateur (ex. Gemini in Chrome) |
| État partagé avec l'utilisateur | Non — session et auth dupliquées côté serveur | Oui — même page, même session, même UI |
Deux consommateurs, une seule fonction
Le point à retenir tient en un schéma : qu'un humain clique sur un bouton de recherche ou qu'un agent appelle search_articles via WebMCP, c'est la même fonction execute(query) qui tourne côté page. Ce qui change, c'est uniquement ce que chacun reçoit en sortie — une liste HTML injectée dans le DOM d'un côté, un objet JSON structuré de l'autre, sans passage par le DOM :
Avec la vraie API, l'inscription du tool se fait derrière une détection de fonctionnalité, puisque le support reste très partiel :
if ('modelContext' in document) {
document.modelContext.registerTool(searchArticlesTool);
}
Sécurité : la même règle que pour tout tool
Un tool WebMCP a beau tourner côté client, les risques restent ceux d'un tool serveur — décrits pour MCP — plus une variante propre au navigateur. Trois points à connaître avant d'en exposer un en prod :
- Multi-origine encadré — par défaut, un tool n'est visible que par la fenêtre top-level et les iframes de même origine. L'exposer à d'autres origines demande de le lister explicitement (
exposedTocôté page hôte,fromOriginscôté consommateur), et un iframe cross-origin doit porterallow="tools"dans sa Permissions Policy. - Annotations de confiance —
readOnlyHintindique à l'agent si un appel modifie un état. C'est une indication, pas une garantie d'exécution : le code de l'executereste seul responsable de ce qu'il fait réellement. - Le contrat compte, pas la promesse — la description et l'
inputSchemasont ce que l'agent lit pour décider d'appeler le tool. Si le tool sous-jacent fait plus que ce que sa description annonce, c'est le même problème de dispatch qui ment sur son périmètre que côté serveur — juste rejoué dans le contexte du navigateur.
Il y a aussi un angle inverse, plus insidieux : la page peut être compromise plutôt que le tool mal conçu. Un XSS classique sur une page qui expose des tools WebMCP peut réinscrire un tool malveillant, ou faire répondre execute avec un contenu piégé — exactement le mécanisme décrit dans « sortie IA, le nouveau XSS », sauf que la source non fiable n'est plus une réponse de LLM affichée à l'utilisateur, mais le résultat d'un tool consommé par l'agent lui-même. L'échappement systématique de tout ce qui atteint le DOM reste la première ligne de défense, WebMCP ou pas.
Où en est la spec
WebMCP est un projet du Web Machine Learning Community Group du W3C, publié pour la première fois en août 2025 par des ingénieurs de Microsoft et Google, avec un support en origin trial dans Chrome à partir de la version 153 — un statut expérimental, activement en discussion (plus de 100 issues ouvertes sur le dépôt). Un signe de cette instabilité : le point d'entrée est passé de navigator.modelContext à document.modelContext dans le brouillon de mai 2026, l'ancien getter étant désormais déprécié. Les auteurs sont explicites sur ce que WebMCP n'essaie pas d'être : ni de la navigation headless sans interface, ni des agents entièrement autonomes, ni un remplacement des intégrations MCP côté serveur — un humain reste dans la boucle. Comme pour le reste de l'écosystème MCP, mieux vaut détecter la fonctionnalité au runtime et suivre le dépôt de la spec que figer une intégration sur la forme actuelle de l'API.
FAQ
WebMCP et MCP, c'est la même chose avec un nom différent ?
Non — même vocabulaire (tool, schéma JSON) mais deux mécaniques séparées. MCP est un protocole JSON-RPC vers un process serveur ou desktop ; WebMCP est une API JavaScript qui vit dans une page web, avec le même état et la même session que l'utilisateur voit déjà.
Un tool WebMCP peut-il être appelé par n'importe quel site ?
Non par défaut — un tool n'est visible que dans son origine. L'exposer à d'autres origines est un choix explicite (exposedTo/fromOrigins), et un iframe cross-origin doit en plus porter la Permissions Policy allow="tools".
Peut-on utiliser WebMCP en prod aujourd'hui ?
Avec prudence — le support est limité à un origin trial Chrome récent et l'API a déjà changé de forme une fois (navigator → document). Une intégration doit détecter la fonctionnalité et prévoir un chemin UI classique en repli.