WebMCP
La página le dice al agente de IA qué sabe hacer, en lugar de dejar que adivine clics.
Cada herramienta tiene un nombre, una descripción, un esquema JSON de entrada y una función. Se registra con document.modelContext.registerTool() o, sin JavaScript, marcando un formulario con toolname y tooldescription. Un agente del navegador o una extensión las descubre y las ejecuta.
Es una propuesta de Google y Microsoft en el grupo comunitario Web Machine Learning del W3C, en prueba de origen en Chrome (desde la 149) y Edge (desde la 150). Mozilla es neutral y WebKit está en contra. La API ha cambiado mucho este año: antes era navigator.modelContext, obsoleta desde Chrome 150.
Para qué sirve
- Que un asistente rellene un pedido o una reserva sin romper la interfaz
- Exponer búsquedas y filtros de un catálogo
- Automatizar tareas de una aplicación web con el usuario delante
Demo
Una lista de tareas que se ofrece a los agentes: cuatro herramientas (una de ellas, el formulario). A la derecha, la consola hace de agente: lista las herramientas de la página y las ejecuta como lo haría un asistente.
La aplicación
Consola del agente ·
Compatibilidad
Disponibilidad limitada| Función | Escritorio | Móvil | |||||
|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Safari | Chrome Android | Firefox Android | Safari iOS | |
| document.modelContext | 149prueba1Chrome: 149 prueba | 150prueba2Edge: 150 prueba | —3Firefox: No | —4Safari: No | —Chrome: No | —Firefox: No | —Safari: No |
| Formularios (toolname…) | 149prueba5Chrome: 149 prueba | 150pruebaEdge: 150 prueba | —Firefox: No | —Safari: No | —Chrome: No | —Firefox: No | —Safari: No |
- 1Prueba de origen «WebMCP» desde 149; en local, chrome://flags/#enable-webmcp-testing. La antigua navigator.modelContext es obsoleta desde la 150.
- 2Prueba de origen desde Edge 150, hasta el 30 de marzo de 2027.
- 3Posición de Mozilla: neutral.
- 4Posición de WebKit: en contra.
- 5Dentro de la misma prueba de origen.
Compatibilidad generada en cada publicación desde MDN browser-compat-data 8.1.3 (24 sep 2026) · web-features 3.40.0 · revisión manual: 1 oct 2026
Para probarla: chrome://flags/#enable-webmcp-testing y la extensión Model Context Tool Inspector, o un token de la prueba de origen en tu dominio.
Código mínimo
<!doctype html>
<meta charset="utf-8">
<title>WebMCP · ejemplo mínimo</title>
<!-- La página ofrece herramientas a los agentes de IA del navegador.
Chrome: chrome://flags/#enable-webmcp-testing o la prueba de origen «WebMCP». HTTPS o localhost. -->
<p>Tema actual: <b id="theme">claro</b></p>
<!-- 1 · API declarativa: un formulario normal se convierte en herramienta -->
<form id="search" toolname="search_notes" tooldescription="Busca notas por palabra clave." toolautosubmit>
<label>Palabra clave <input name="q" required toolparamdescription="Texto a buscar"></label>
<button>Buscar</button>
</form>
<pre id="out"></pre>
<script type="module">
const out = document.querySelector('#out');
const notes = ['Comprar pan', 'Llamar a Ana', 'Revisar WebGPU'];
const search = (q) => notes.filter((n) => n.toLowerCase().includes(q.toLowerCase()));
// El formulario sigue funcionando para las personas; si lo envía un agente, responde con datos.
document.querySelector('#search').addEventListener('submit', (e) => {
e.preventDefault();
const results = search(new FormData(e.target).get('q'));
out.textContent = results.join('\n') || 'Sin resultados';
if (e.agentInvoked) e.respondWith(Promise.resolve({ results }));
});
// 2 · API imperativa: document.modelContext (antes navigator.modelContext, obsoleto desde Chrome 150)
const mc = document.modelContext;
if (!mc) {
out.textContent = 'document.modelContext no está disponible: activa la flag o usa la prueba de origen.';
} else {
const registration = new AbortController(); // registration.abort() retira la herramienta
await mc.registerTool({
name: 'set_theme',
description: 'Cambia el tema de color de la página.',
inputSchema: {
type: 'object',
properties: { theme: { type: 'string', enum: ['claro', 'oscuro'] } },
required: ['theme'],
},
annotations: { readOnlyHint: false },
async execute({ theme }) {
document.querySelector('#theme').textContent = theme;
return { ok: true, theme }; // devuelve siempre algo serializable
},
}, { signal: registration.signal });
// La propia página puede hacer de agente para probar sus herramientas:
const tools = await mc.getTools();
out.textContent = 'Herramientas: ' + tools.map((t) => t.name).join(', ');
const tool = tools.find((t) => t.name === 'set_theme');
// La entrada es un objeto. Chrome, antes de la 155, la pedía como texto JSON y la rechazaba sin ejecutar nada
// («Failed to parse input»): solo en ese caso se reintenta así.
const run = (input) => mc.executeTool(tool, input).catch((e) => {
if (!/parse input/i.test(String(e?.message ?? e))) throw e;
return mc.executeTool(tool, JSON.stringify(input));
});
out.textContent += '\nset_theme → ' + (await run({ theme: 'oscuro' }));
}
</script><!doctype html>
<meta charset="utf-8">
<title>WebMCP · ejemplo mínimo</title>
<!-- La página ofrece herramientas a los agentes de IA del navegador.
Chrome: chrome://flags/#enable-webmcp-testing o la prueba de origen «WebMCP». HTTPS o localhost. -->
<p>Tema actual: <b id="theme">claro</b></p>
<!-- 1 · API declarativa: un formulario normal se convierte en herramienta -->
<form id="search" toolname="search_notes" tooldescription="Busca notas por palabra clave." toolautosubmit>
<label>Palabra clave <input name="q" required toolparamdescription="Texto a buscar"></label>
<button>Buscar</button>
</form>
<pre id="out"></pre>
<script type="module">
const out = document.querySelector('#out');
const notes = ['Comprar pan', 'Llamar a Ana', 'Revisar WebGPU'];
const search = (q) => notes.filter((n) => n.toLowerCase().includes(q.toLowerCase()));
// El formulario sigue funcionando para las personas; si lo envía un agente, responde con datos.
document.querySelector('#search').addEventListener('submit', (e) => {
e.preventDefault();
const results = search(new FormData(e.target).get('q'));
out.textContent = results.join('\n') || 'Sin resultados';
if (e.agentInvoked) e.respondWith(Promise.resolve({ results }));
});
// 2 · API imperativa: document.modelContext (antes navigator.modelContext, obsoleto desde Chrome 150)
const mc = document.modelContext;
if (!mc) {
out.textContent = 'document.modelContext no está disponible: activa la flag o usa la prueba de origen.';
} else {
const registration = new AbortController(); // registration.abort() retira la herramienta
await mc.registerTool({
name: 'set_theme',
description: 'Cambia el tema de color de la página.',
inputSchema: {
type: 'object',
properties: { theme: { type: 'string', enum: ['claro', 'oscuro'] } },
required: ['theme'],
},
annotations: { readOnlyHint: false },
async execute({ theme }) {
document.querySelector('#theme').textContent = theme;
return { ok: true, theme }; // devuelve siempre algo serializable
},
}, { signal: registration.signal });
// La propia página puede hacer de agente para probar sus herramientas:
const tools = await mc.getTools();
out.textContent = 'Herramientas: ' + tools.map((t) => t.name).join(', ');
const tool = tools.find((t) => t.name === 'set_theme');
// La entrada es un objeto. Chrome, antes de la 155, la pedía como texto JSON y la rechazaba sin ejecutar nada
// («Failed to parse input»): solo en ese caso se reintenta así.
const run = (input) => mc.executeTool(tool, input).catch((e) => {
if (!/parse input/i.test(String(e?.message ?? e))) throw e;
return mc.executeTool(tool, JSON.stringify(input));
});
out.textContent += '\nset_theme → ' + (await run({ theme: 'oscuro' }));
}
</script>Novedades
- El borrador añade anotaciones (consequentialHint, untrustedContentHint) y los eventos toolactivated y toolcancel.
- executeTool() recibe la entrada como objeto: pasarla como texto JSON queda obsoleto en Chrome 155.
- Edge 150 abre su prueba de origen, hasta el 30 de marzo de 2027.
- Prueba de origen «WebMCP» en Chrome desde la 149.
- El borrador mueve la API de navigator a document.modelContext; Chrome marca la antigua como obsoleta en la 150.
- Desaparecen provideContext, clearContext y unregisterTool: para retirar una herramienta se aborta su AbortSignal.
Ten en cuenta
- executeTool(herramienta, entrada): la entrada es un objeto, pero Chrome la pedía como texto JSON hasta la 154. Si falla con «Failed to parse input», reintenta con JSON.stringify().
- execute() debe devolver siempre algo serializable (un texto o un objeto): devolver undefined cuenta como fallo.
- Solo en contexto seguro. En un iframe de otro origen hace falta allow="tools".
- No hay modelo de consentimiento: marca con consequentialHint lo que tenga consecuencias para que el agente pida confirmación.
Más información
Fuentes
- WebMCP (Draft CG Report)30 sep 2026
- Chrome · WebMCP imperative API21 sep 2026
- Chrome · WebMCP declarative API25 sep 2026
- Chrome · WebMCP origin trial9 jun 2026
- Microsoft Edge 150 web platform release notes2 jul 2026
- Mozilla standards-positions #1412ago 2026
- WebKit standards-positions #670jun 2026