Qué es WebMCP: herramientas para agentes dentro de tu web
WebMCP es la API con la que una página registra herramientas para agentes de IA: document.modelContext, registerTool, anotaciones y diferencias con MCP.
Por Andrés León Bohórquez Actualizado el
Datos a 2 de octubre de 2026
WebMCP es una API de JavaScript con la que una página web registra herramientas para que un agente de IA las descubra y las invoque mientras el usuario tiene esa página abierta. Cada herramienta tiene un nombre, una descripción en lenguaje natural, un JSON Schema de entrada y una función execute. WebMCP no es un servidor MCP ni un transporte nuevo de MCP, sino una API del navegador que toma prestado el vocabulario de MCP.
Aquí tienes la API según el borrador del 2 de octubre de 2026, lo que comparte con MCP y lo que ya no existe.
Qué es WebMCP, según su especificación
La introducción del borrador lo dice así:
“WebMCP API is a new JavaScript interface that allows web developers to expose their web application functionality as “tools” - JavaScript functions with natural language descriptions and structured schemas that can be invoked by agents, browser’s agents, and assistive technologies. Web pages that use WebMCP can be thought of as Model Context Protocol [MCP] servers that implement tools in client-side script instead of on the backend.”
La última frase explica dónde vive la herramienta. Se ejecuta dentro de la pestaña, con el DOM, el estado de la aplicación y la sesión que ya tiene la página.
La especificación separa dos clases de agente. Por un lado está el agente del navegador, integrado en él o alojado por él, por ejemplo en una extensión. Por otro, los agentes escritos en JavaScript dentro de la página o de un iframe, que usan getTools(). Sobre el agente del navegador, el borrador dice que “the user agent’s browser agent uses a different internal mechanism to retrieve the tools exposed to it”.
flowchart LR P["Script de tu página"] -->|"registerTool()"| MC["document.modelContext"] MC -->|"mecanismo interno"| BA["Agente del navegador"] MC -->|"getTools() y executeTool()"| IA["Agente en la página o iframe"] MC -->|"content script"| EX["Extensión"] BA -.->|"formato no prescrito"| AI["Plataforma de IA"]
Quién lo lleva y en qué estado está
WebMCP lo incuba el W3C Web Machine Learning Community Group. Como es un grupo comunitario, el documento es un Draft Community Group Report. No es una recomendación del W3C ni un borrador de un grupo de trabajo en el Standards Track. Según los metadatos de index.bs, los editores son Brandon Walderman (Microsoft), Khushal Sagar (Google) y Dominic Farolino (Google).
Dos datos sitúan bien la madurez:
- La revisión del TAG, abierta el 11 de junio de 2026, es una “CG early review” en curso y lleva la etiqueta “Missing: Multi-stakeholder support”.
- El Intent to Extend Experiment de Chromium del 28 de septiembre de 2026 dice: “TAG review: Spec is being incubated. We will request TAG review before shipping.” Ese mismo intent pide ampliar el origin trial de Chrome hasta Chrome 162.
Ya hay implementaciones experimentales: los origin trials de Chrome y Edge, y las Site tools de ChatGPT Desktop, anunciadas el 25 de agosto de 2026. Mozilla tiene una posición neutral y WebKit está en contra. El detalle navegador por navegador está en dónde funciona WebMCP hoy.
La API: registerTool, getTools y executeTool
Todo cuelga de un objeto, document.modelContext. Este es un fragmento literal del WebIDL de index.bs:
partial interface Document {
[SecureContext, SameObject] readonly attribute ModelContext modelContext;
};
[Exposed=Window, SecureContext]
interface ModelContext : EventTarget {
Promise<undefined> registerTool(ModelContextTool tool, optional ModelContextRegisterToolOptions options = {});
Promise<sequence<RegisteredTool>> getTools(optional ModelContextGetToolOptions options = {});
Promise<DOMString> executeTool(RegisteredTool tool, optional object inputObject, optional ModelContextExecuteToolOptions options = {});
attribute EventHandler ontoolchange;
attribute EventHandler ontoolactivated;
attribute EventHandler ontoolcancel;
};
Así se registra una herramienta. El ejemplo es literal, del README del repositorio:
const controller = new AbortController();
await document.modelContext.registerTool({
name: "add-todo",
description: "Add a new item to the user's active todo list",
inputSchema: {
type: "object",
properties: {
text: { type: "string", description: "The text content of the todo item" }
},
required: ["text"]
},
async execute({ text }) {
// Reuse existing client-side application logic and update UI.
await addTodoItemToCollection(text);
return {
content: [
{
type: "text",
text: `Added todo item: "${text}" successfully.`
}
]
};
}
}, { signal: controller.signal });
// To unregister the tool later, abort the signal.
// controller.abort();
Según el algoritmo de la especificación, esto es lo que conviene saber de registerTool():
- Solo en contexto seguro.
modelContextlleva[SecureContext], así que necesitas HTTPS ohttp://localhost. - Permissions Policy
tools. Su allowlist por defecto es'self'. Funciona en el documento principal y en iframes del mismo origen, y un iframe de otro origen necesitaallow="tools". Si la política lo impide, la promesa se rechaza conNotAllowedError. - Nombres como en MCP. De 1 a 128 caracteres, solo
[A-Za-z0-9_.-], sin repetir. Un nombre inválido o duplicado, o una descripción vacía, hacen que la promesa se rechace conInvalidStateError. - Herramientas efímeras. Como dice Chrome, “WebMCP tools are ephemeral. They exist only when your page is open.”
Cuando se invoca la herramienta, el navegador parsea los argumentos, dispara toolactivated y llama a execute(inputObject, { signal }). Lo que devuelva se serializa con JSON, así que vale cualquier valor serializable. El formato { content: [...] } del README es una convención tomada de MCP, no un requisito. Los ejemplos de Chrome, de hecho, devuelven cadenas.
getTools() y executeTool() son para agentes escritos en JavaScript dentro de la página. Este es el ejemplo literal de la especificación:
const tools = await document.modelContext.getTools();
const tool = tools.find(t => t.name === 'example_tool');
if (tool) {
const result = await document.modelContext.executeTool(tool, {message: "hello"});
}
executeTool() resuelve con el resultado ya serializado (un DOMString) y solo funciona dentro de la misma pestaña. Los fallos llegan como un UnknownError genérico.
Desde el 17 de agosto de 2026, la especificación acepta un objeto como entrada. Antes era una cadena JSON. La documentación de Chrome anuncia que la cadena queda obsoleta en Chrome 155, cuya versión estable está prevista para el 6 de octubre de 2026 según el calendario de Chrome. En nuestras pruebas con Chrome 154 estable, executeTool() todavía exigía la cadena.
document.modelContext tiene tres eventos:
toolchange: cambia el conjunto de herramientas.toolactivated: empieza una ejecución.toolcancel: el llamador cancela.
Los dos últimos entraron en la especificación el 17 de septiembre de 2026. Chrome documenta que, desde Chrome 156, window.ontoolactivated y window.ontoolcancel dejan de funcionar. En Chrome 154 comprobamos que toolactivated todavía se dispara en window, pero Chrome 156 no lo hemos probado.
Retirar herramientas con AbortSignal
No hay un método para dar de baja una herramienta. Para retirarla, abortas el AbortSignal que pasaste al registrarla. Este ejemplo es literal de la guía de la API imperativa de Chrome:
const addTodoTool = {
name: "addTodo",
description: "Add a new item to the to-do list",
inputSchema: {
type: "object",
properties: { text: { type: "string" } },
},
execute: async ({ text }) => {
// You should handle the persistence logic here (omitted for demo)
return `Added to-do: ${text}`;
},
annotations: {
readOnlyHint: false,
untrustedContentHint: true
},
};
const controller = new AbortController();
await document.modelContext.registerTool(addTodoTool, { signal: controller.signal });
// Unregister the tool later...
controller.abort();
Desde el 19 de agosto de 2026, la especificación separa las dos señales: “The registration-time signal only controls tool availability, while the execution-time signal controls the lifetime of an specific invocation.” Es decir, retirar una herramienta no cancela una ejecución que ya está en marcha, aunque sea la propia ejecución la que la retire. Chrome lo aplica desde Chrome 153.
Tampoco puedes modificar una herramienta en caliente. Lo dice la sección de buenas prácticas del README: “WebMCP does not currently define an in-place updateTool() method, lazy schemas, or disabled and grouped tool states”. Para cambiar el nombre, la descripción o el esquema, la retiras y la vuelves a registrar.
Esto encaja con lo que recomiendan Chrome y el README: un registro dinámico, ligado al estado de la página. Por ejemplo, registrar las herramientas que necesitan sesión solo cuando la hay y abortar su señal al cerrarla.
Anotaciones: readOnlyHint, untrustedContentHint, consequentialHint y debugging
Las anotaciones son cuatro booleanos, todos false por defecto:
| Anotación | Qué indica (especificación) | Añadida |
|---|---|---|
readOnlyHint |
“the tool does not modify any state and only reads data” | Febrero de 2026 |
untrustedContentHint |
“the tool’s output contains data that is untrusted, from the perspective of the author registering the tool” | 23 de abril de 2026 |
consequentialHint |
“executing the tool will result in consequential actions that are significant, real-world, or non-reversible, ex: booking a flight, transferring money” | 3 de septiembre de 2026 |
debugging |
“the tool is intended for debugging and developer tooling rather than end-user interactions” | 17 de septiembre de 2026 (Chrome: “available from Chrome 156”) |
Ejemplo literal de Chrome con las cuatro:
await document.modelContext.registerTool({
name: 'book_flight',
description: 'Book a flight for the user with confirmed flight details.',
inputSchema: {
type: 'object',
properties: {
flightId: { type: 'string', description: 'ID of the flight to book' },
passengers: { type: 'number', description: 'Number of tickets to purchase' },
},
required: ['flightId', 'passengers'],
},
annotations: {
readOnlyHint: false,
consequentialHint: true,
untrustedContentHint: false,
debugging: false,
},
execute: async ({ flightId, passengers }) => {
// Add your flight booking transaction logic here.
return `Booked ${passengers} passenger(s) on flight ${flightId}.`;
},
});
Son pistas, igual que en MCP. La especificación no obliga a ningún agente a pedir confirmación. Dice que permiten que los agentes “can selectively enforce mandatory user confirmation prompts before executing high-stakes tools”. El borrador vigente tampoco tiene ninguna API para que la herramienta pida confirmación al usuario, así que la decisión es del agente o del navegador.
ChatGPT, por ejemplo, documenta que “each tool invocation receives a safety review before it runs” (Site tools). Stripe, por su parte, avisa a quien construye agentes: “Don’t interpret the hint itself as confirmation.”
Si una acción no debe completarse sin el usuario, no la completes en execute. Prepárala y devuelve el control a la interfaz.
Si vienes de MCP, ten en cuenta que el conjunto no coincide. Las anotaciones de MCP comparten readOnlyHint, pero tienen además destructiveHint, idempotentHint y openWorldHint, que WebMCP no define. A cambio, WebMCP añade untrustedContentHint, consequentialHint y debugging.
La forma declarativa en formularios
Aparte de la API imperativa, existe una variante con atributos HTML sobre un <form>. El formulario lleva toolname, tooldescription y toolautosubmit, y los controles llevan toolparamdescription. El atributo name de cada control da el nombre de la propiedad del esquema.
Sin toolautosubmit, el navegador rellena el formulario y deja el envío al usuario. Con él, el formulario se envía solo. Tu código distingue el envío del agente con SubmitEvent.agentInvoked y le responde con SubmitEvent.respondWith(). Así lo describe la documentación declarativa de Chrome.
Lo que no tiene es especificación. La sección declarativa del borrador dice: “This section is entirely a TODO. For now, refer to the Declarative API explainer.” Tampoco está resuelto cómo se sintetiza exactamente el esquema a partir del formulario. El borrador dice que Chromium implementa “a loose version of this”. Y ChatGPT Desktop no expone estas herramientas: “Tools defined through HTML form attributes aren’t available as site tools”.
El propio Farolino explica hacia dónde va el esfuerzo en su respuesta del 29 de septiembre en blink-dev: “The imperative API is a lot more popular than the declarative one, so we’re investing more into it in response to user needs.”
WebMCP frente a MCP
Chrome resume la diferencia en una tabla de su página WebMCP versus MCP, que reproducimos literal:
| MCP | WebMCP | |
|---|---|---|
| Lifecycle | Persistent (server and daemon) | Ephemeral (tab-bound) |
| Connectivity | Global (desktop, mobile, cloud, web) | Environment-specific (browser agents) |
| UI interaction | Headless and external | Browser-integrated and DOM-aware |
| Discovery | Agent-specific registration flows | Tools registered on the web page during the user’s visit. |
Comparten el vocabulario (herramientas, esquemas, anotaciones) y las reglas de nombre. El README lo explica así: “WebMCP derives direct inspiration and shares a common vocabulary with MCP (e.g., tools, schemas, parameters), but provides a form-fitting, client-safe solution designed natively for the web platform.” Desde el 28 de septiembre de 2026, la especificación cita la de MCP, aunque de forma no normativa.
Lo que no comparten pesa más:
- No hay JSON-RPC ni transportes (stdio, Streamable HTTP). Es una API de la plataforma web.
- No hay resources ni prompts, solo herramientas. Tampoco hay
outputSchema, ni progreso, ni elicitation. - El navegador no tiene por qué hablar MCP con su agente. Lo dice la sección Page observations del borrador: “this specification does not prescribe the format in which tools are exposed to the browser agent. Browsers are free to distill and expose tools via Model Context Protocol, other proprietary “function calling” methods, or any other way it deems appropriate.”
- El objetivo es complementar, no sustituir. El README lo incluye entre sus Non-Goals: “WebMCP is designed to complement, not replace, existing backend-focused protocols like MCP.”
No compiten. El servidor MCP atiende a cualquier cliente, sin navegador. WebMCP solo existe mientras el usuario está en tu página y aprovecha lo que esa página ya sabe.
Incluso hay puentes entre los dos. El developer preview de Cloudflare del 6 de agosto de 2026 toma las herramientas que devuelve el tools/list de un servidor MCP del propio sitio y las registra con document.modelContext.registerTool(). Después reenvía cada llamada como tools/call.
Si quieres repasar cómo se definen las herramientas en MCP, empieza por la lección de herramientas del curso.
Lo que ya no existe
Muchos tutoriales siguen escritos contra versiones anteriores del explicador. Si un ejemplo usa alguna de estas piezas, está desactualizado:
navigator.modelContext. El getter pasó deNavigatoraDocumentel 27 de mayo de 2026 (commitc7b5c70del repositorio). En nuestras pruebas con Chrome 154 estable,'modelContext' in navigatordafalse, también con WebMCP activado. La API vigente esdocument.modelContext.provideContext()yclearContext(). Se eliminaron el 5 de marzo de 2026 (commitfe84c67). Hoy cada herramienta se registra por separado conregisterTool().unregisterTool(). Desapareció del explicador el 27 de marzo de 2026 (commit90daeee). Lo sustituye elAbortSignaldel registro, como has visto arriba.ModelContextClientyrequestUserInteraction(). Se eliminaron el 11 de junio de 2026 (commit067a1c9, “RemoveModelContextClientfor now”). Importante: la página “WebMCP tool security” de Chrome, actualizada el 1 de septiembre, todavía dice que el borrador la incluye. No es así: no hay API de confirmación.- El requisito de origin-keyed agent cluster. Entre junio y septiembre,
registerTool()rechazaba el registro si el agent cluster no tenía clave de origen. El commitd61d0e6del 30 de septiembre de 2026 eliminó ese requisito.
Para detectar el soporte, usa la comprobación que recomienda OpenAI en su documentación de Site tools: typeof document.modelContext?.registerTool === "function". Si la API no está, deja que la página funcione igual.
Por dónde seguir
El estado navegador por navegador está en dónde funciona WebMCP hoy. Su lugar junto a A2A, AG-UI, Agent Skills y los protocolos de pagos lo tienes en el mapa de protocolos de agentes de IA. Si te falta la base de MCP (qué es una tool y cómo se invoca), el curso la cubre desde la introducción, con el nivel Básico gratuito con registro.
Aprende esto en el curso
- Básico Gratis Introducción a MCP · Qué es MCP, qué problema resuelve y el caso que recorre el curso
- Básico Gratis Herramientas · Acciones que el modelo puede invocar, con esquemas y errores
La lección 1 la puedes leer ya, sin registro. Las otras 13 del Básico son gratis con una cuenta.
Empieza gratis Ir a la lecciónFuentes
- WebMCP, Draft Community Group Report (2026-10-02)
- Repositorio webmachinelearning/webmcp (README y explicadores)
- Chrome: WebMCP versus MCP (2026-05-19)
- Chrome: Imperative API (2026-09-21)
- Chrome: Declarative API (2026-09-25)
- Intent to Extend Experiment: WebMCP (2026-09-28)
- Respuesta de Dominic Farolino en blink-dev (2026-09-29)
- TAG design review: Incubation: WebMCP (2026-06-11)
- Chrome: WebMCP tool security (2026-09-01)
- Mozilla standards-positions #1412: WebMCP (2026-08-05)
- WebKit standards-positions #670: WebMCP (2026-06-11)
- OpenAI Developer Community: Build agent-ready websites with ChatGPT (2026-08-25)
- ChatGPT: Site tools (WebMCP)
- Stripe: WebMCP para agentes
- Cloudflare: Give any website a WebMCP interface (2026-08-06)
- MCP 2026-07-28: Tools