WebMCP: Qué es y cómo convierte tu web en agéntica
🏄♂️ Antes de que sigas leyendo, una actualización importante: este post se publicó en febrero de 2026 y se ha refrescado el 19 de mayo con las novedades anunciadas por el equipo de Chrome. Lo detallamos todo justo a continuación.
Sigue siendo tecnología en fase experimental (early preview), pero la dirección está cada vez más clara y se nota que esto avanza.
Qué problema intenta resolver WebMCP ¶
Vamos a ponernos en contexto. Hoy, cuando un agente de IA quiere interactuar con una web (comprar un billete, rellenar un formulario, buscar un producto), tiene que hacer lo mismo que haría un humano: mirar la pantalla, interpretar el HTML, encontrar botones e ir haciendo clic.
Esto funciona. Más o menos.
El problema es que es frágil, lento y caro. El agente necesita “tokenizar” toda la interfaz, procesarla con el modelo de lenguaje, decidir dónde hacer clic y rezar para que el DOM no haya cambiado desde la última vez. Es como si para pedir un café tuvieras que leer toda la carta, estudiar la tipografía del menú y adivinar dónde está el camarero.
Y no es solo una cuestión de elegancia técnica. Cada captura de pantalla, cada análisis del HTML, cada decisión sobre “¿es este el botón correcto?” consume tokens. Y los tokens cuestan dinero, tiempo y fiabilidad. Un cambio menor en el CSS de la página puede hacer que el agente deje de funcionar. Un popup inesperado, un banner de cookies, una variación en el texto de un botón… cualquier cosa rompe la cadena.
Herramientas como Playwright o Puppeteer han sido el parche durante años. Funcionan, pero obligan al agente a operar como un titiritero que mueve hilos sobre una interfaz diseñada para dedos humanos. WebMCP propone cortar esos hilos.
WebMCP propone algo más elegante: que la propia web le diga al agente qué puede hacer y cómo hacerlo. En lugar de que el agente interprete la interfaz humana, el sitio web expone acciones estructuradas (lo que llaman “tools”) que el agente puede descubrir e invocar directamente.
🔑 La idea central es sencilla: no obligues al agente a actuar como un humano. Dale un menú de acciones claras con instrucciones precisas.
MCP vs WebMCP: primos hermanos, no gemelos ¶
Si llevas tiempo siguiendo el mundo de los agentes de IA, seguro que te suena MCP (Model Context Protocol). Es el protocolo que permite que herramientas como Claude Code o Cursor se conecten con servicios externos a través de un servidor que expone “tools”. Si quieres profundizar, tenemos un tutorial completo para crear un servidor MCP desde cero con TypeScript.
MCP vive en el lado del servidor. Necesitas levantar un servidor MCP, configurar la comunicación y gestionar la autenticación. Funciona genial para entornos de desarrollo, para automatización en segundo plano, y para tareas que no necesitan una interfaz visual. Con MCP Apps las herramientas MCP ya pueden devolver interfaces interactivas directamente dentro de la conversación. De hecho, instalar servidores MCP en agentes como Claude Code, Gemini CLI o Copilot es ya una práctica habitual entre developers.
WebMCP toma una ruta diferente. En lugar de vivir en un servidor, vive en el navegador. Las tools se registran en el contexto de la pestaña donde el usuario está navegando, aprovechando su sesión, sus credenciales y su interfaz.
Esto tiene implicaciones importantes:
- El agente trabaja dentro de la misma sesión que el usuario, sin necesidad de tokens adicionales ni APIs de backend.
- El usuario puede ver y confirmar lo que el agente hace (human-in-the-loop).
- La lógica del frontend se reutiliza, no hay que duplicar nada en un servidor aparte.
Pero también tiene limitaciones claras: no funciona en modo headless (sin navegador visible), no hay forma de que un agente descubra qué tools ofrece un sitio sin visitarlo primero, y la superficie de la API todavía tiene agujeros. Más adelante hablamos de eso.
La forma más justa de ver la relación entre ambos es como herramientas complementarias. MCP para lo que ocurre en el backend y en segundo plano. WebMCP para lo que ocurre dentro de la pestaña del navegador, cara a cara con el usuario. Para entender cómo encajan estas piezas con A2A, ACP y otros estándares, consulta nuestra guía de los protocolos de IA generativa para programar.
Cómo funciona: la API de navigator.modelContext ¶
El núcleo técnico de WebMCP es una extensión del objeto Navigator del navegador. Aparece una nueva propiedad llamada navigator.modelContext que permite registrar y gestionar tools desde JavaScript.
En el borrador del W3C Community Group, las operaciones principales se han ido depurando. En su versión de mayo de 2026 quedan así:
registerTool(tool, options): añade una tool. Falla si el nombre ya existe o si el esquema de entrada no es válido. El segundo argumento permite pasar unAbortSignalpara gestionar la baja.
⚠️ Si has visto código antiguo con
provideContext()oclearContext(), esos métodos se han retirado. El patrón actual usaAbortControllerpara registrar y retirar tools de forma granular.unregisterTool()tampoco existe.
Cada tool tiene una estructura clara: un nombre, una descripción en lenguaje natural, un esquema JSON de entrada (inputSchema) y un callback execute que devuelve cualquier valor que tenga sentido para el agente (objeto, array, string, número o booleano).
Y hay un detalle de diseño que marca la diferencia: el mecanismo requestUserInteraction que apareció en versiones tempranas del borrador. Cuando el agente invoca una tool imperativa que necesita confirmación del usuario (una compra, una reserva, un envío), el callback puede pausar la ejecución y pedir al usuario que confirme antes de continuar.
En la vía declarativa, el equivalente moderno es omitir el atributo toolautosubmit: el navegador se encarga de pausar el submit y de mostrar feedback visual con :tool-submit-active. Y para tools imperativas que no mutan estado, el campo annotations: { readOnlyHint: true } le indica al agente que puede ejecutarlas sin riesgo.
Esto no es un “nice to have”. Es la pieza que hace viable usar agentes en flujos donde hay dinero o datos sensibles de por medio.
🛡️ WebMCP no quiere que el agente actúe sin supervisión. El diseño incluye varios mecanismos para que el humano tenga la última palabra cuando sea necesario.
Dos caminos para implementar: declarativo e imperativo ¶
WebMCP ofrece dos vías para exponer tools al agente, y cada una tiene su momento.
La vía imperativa (JavaScript) ¶
Es la más potente. Registras tools con navigator.modelContext.registerTool(), defines el esquema de entrada con JSON Schema y proporcionas un callback que se ejecuta cuando el agente invoca la herramienta.
Este es un ejemplo de una tool que busca vuelos y otra que permite reservar con confirmación del usuario, ya con el patrón actual:
// Verificar si WebMCP está disponible
if (!("modelContext" in navigator)) {
console.warn("WebMCP no está disponible en este navegador.");
}
// Controller para gestionar el ciclo de vida de ambas tools
const searchController = new AbortController();
const bookController = new AbortController();
// Tool de búsqueda: read-only
navigator.modelContext.registerTool({
name: "search_flights",
description: "Search flights by origin, destination, and date (YYYY-MM-DD).",
inputSchema: {
type: "object",
properties: {
origin: { type: "string", description: "IATA code, e.g. MAD" },
destination: { type: "string", description: "IATA code, e.g. LHR" },
date: { type: "string", description: "Date in YYYY-MM-DD" }
},
required: ["origin", "destination", "date"]
},
async execute(input) {
// Llamada real a tu backend o API de vuelos
const response = await fetch("/api/search-flights", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(input)
});
return await response.json();
},
annotations: { readOnlyHint: true }
}, { signal: searchController.signal });
// Tool de reserva: necesita confirmación humana
navigator.modelContext.registerTool({
name: "book_flight",
description: "Book a flight by flightId. Requires user confirmation.",
inputSchema: {
type: "object",
properties: {
flightId: { type: "string", description: "Flight ID from search results" }
},
required: ["flightId"]
},
async execute(input, client) {
// Pedir confirmación al usuario antes de reservar
const confirmed = await client.requestUserInteraction(async () => {
return window.confirm(`¿Confirmas la reserva del vuelo ${input.flightId}?`);
});
if (!confirmed) return { status: "cancelled" };
const response = await fetch("/api/book-flight", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ flightId: input.flightId })
});
return await response.json();
}
}, { signal: bookController.signal });
// Cuando la página o el componente se desmonta:
// searchController.abort();
// bookController.abort();
Fíjate en cómo el AbortSignal se convierte en el único punto de control del ciclo de vida. Las tools viven mientras tu componente esté montado y desaparecen del registro en cuanto llamas a abort().
La vía declarativa (formularios HTML) ¶
Esta es la vía rápida. Si tu web ya tiene formularios bien estructurados, puedes añadir atributos especiales para que el navegador los exponga como tools al agente.
Los atributos clave son toolname, tooldescription, toolparamdescription y toolautosubmit. Un formulario de reserva de restaurante quedaría así:
<form id="bookingForm"
toolname="book_table"
tooldescription="Book a table. Collect name, date, time, and party size.">
<label>
Name:
<input name="name" toolparamdescription="Full name (min 2 chars)" required />
</label>
<label>
Date:
<input name="date" type="date" toolparamdescription="Date in YYYY-MM-DD" required />
</label>
<label>
Party size:
<input name="partySize" type="number" min="1" max="12"
toolparamdescription="Number of guests (1-12)" required />
</label>
<button type="submit">Submit</button>
</form>
En este caso hemos omitido toolautosubmit porque una reserva es una acción que conviene que el usuario confirme con un clic. Si fuese una búsqueda en lugar de una reserva, lo habríamos activado.
Y en el JavaScript del formulario puedes detectar si el envío viene de un agente para devolver datos estructurados:
form.addEventListener("submit", (e) => {
e.preventDefault();
const payload = Object.fromEntries(new FormData(form).entries());
const result = {
ok: true,
confirmation: `Reserva para ${payload.name} el ${payload.date} (${payload.partySize} personas).`
};
// Si el formulario lo envía un agente, devolver respuesta estructurada
if (e.agentInvoked) {
e.respondWith(Promise.resolve(result));
}
});
⚡ Si ya tienes formularios HTML bien hechos, la vía declarativa puede ser tu primer paso hacia WebMCP. Poco esfuerzo, resultado inmediato.
Cómo probarlo hoy ¶
Esto sigue siendo experimental, pero el flujo de instalación se ha simplificado bastante con respecto a febrero.
1. Instala una versión reciente de Chrome o Edge ¶
Necesitas un navegador Chromium con versión 146.0.7672.0 o superior. Si quieres anticiparte al Origin Trial que se confirmará en Chrome 149, puedes usar Chrome Canary y mantenerlo actualizado.
2. Activa el flag de WebMCP ¶
Abre chrome://flags/#enable-webmcp-testing (o el equivalente en Edge: edge://flags/#enable-webmcp-testing), ponlo a Enabled y reinicia el navegador.
3. Instala el inspector desde la Chrome Web Store ¶
La extensión Model Context Tool Inspector ya está publicada oficialmente. Te permite:
- Ver qué tools tiene registradas la página actual.
- Invocarlas manualmente con JSON de entrada.
- Chatear con un agente que por defecto usa
gemini-3-flash-preview, para probar tus tools en lenguaje natural.
4. Juega con las demos oficiales ¶
En el repositorio webmcp-tools de GoogleChromeLabs tienes ahora tres demos completas:
- Pizza Maker (imperativa).
- Travel demo en React (imperativa).
- Le Petit Bistro (declarativa).
Son el mejor punto de partida para ver WebMCP en acción con código real.
Ejemplo de implementación con webmcp-starter ¶
Desglosamos completo el código WebMCP en la demo Midnight Eats: 8 tools imperativas + 1 declarativa (form checkout). Análisis de arquitectura, integración con el navegador y flujo de trabajo de principio a fin.
1. Qué hace este código con WebMCP ¶
La demo Midnight Eats es una app de food delivery (estilo Glovo, Uber Eats) que expone 9 tools al navegador para que un agente de IA pueda operar la app sin tocar el DOM directamente. El agente descubre las tools, las invoca con parámetros estructurados, y recibe respuestas JSON. La UI se actualiza como efecto colateral de la ejecución.
Dos mecanismos coexisten:
Vía imperativa (JavaScript): 8 tools registradas con navigator.modelContext.registerTool(). Cada una define nombre, descripción en lenguaje natural, JSON Schema de entrada y un callback execute().
search_restaurants— buscar restaurantesget_menu— obtener menú de un restauranteadd_to_cart/remove_from_cart— gestión del carritoget_cart/clear_cart— lectura y reseteo del carritoapply_promo_code— aplicar código promocionalget_order_status— consultar estado del pedido
Vía declarativa (HTML Form): 1 tool definida como formulario HTML anotado con toolname, tooldescription y toolparamdescription. El navegador la convierte en una tool invocable.
checkout— completar el pedido con dirección, propina y método de pago
La detección es condicional: todo el bloque imperativo se envuelve en if ('modelContext' in navigator). Si el navegador no soporta WebMCP, la app funciona normalmente para humanos: las tools simplemente no se registran. Esto es progressive enhancement puro.
2. Arquitectura: tres capas ¶
La app se organiza internamente en tres capas diferenciadas. Las tools WebMCP no contienen lógica de negocio: son adaptadores finos que llaman a las mismas funciones que la UI humana.
Capa 1 — Datos y lógica de negocio
Toda la lógica vive en JavaScript puro, sin dependencia de WebMCP:
RESTAURANTS: array con 6 restaurantes conid,name,cuisine,menu.PROMO_CODES: objeto con códigos válidos (WELCOME20,FREEDELIVERY,SAVE5).state: objeto global concart,promo,order,currentView, etc.- Funciones de negocio:
addToCart(),removeFromCart(),clearCart(),getCartTotal(),applyPromo().
Estas funciones mutan el estado y calculan totales. No saben nada de WebMCP ni de agentes.
Capa 2 — UI y rendering
Funciones que leen el estado y generan HTML: renderRestaurants(), renderMenu(), updateCartUI(), showView(), showMenu(), showOrderConfirmation().
Las tools WebMCP las llaman como efecto colateral: get_menu ejecuta showMenu() para que la UI navegue visualmente al restaurante, además de devolver el JSON al agente.
Capa 3 — Adaptadores WebMCP
Los 8 registerTool() + el form anotado. Cada tool valida la entrada, llama a funciones de la capa 1, dispara actualizaciones de la capa 2 y devuelve JSON estructurado.
Esta separación es exactamente lo que recomiendan las fuentes oficiales para SPAs que quieran adoptar WebMCP: aislar la lógica en servicios reutilizables para que las tools no dependan de detalles de UI.
3. La vía imperativa: estructura de cada tool ¶
Cada tool sigue la misma estructura de campos obligatorios:
const controller = new AbortController();
navigator.modelContext.registerTool({
name: "nombre_de_la_tool",
description: "Texto en lenguaje natural para el agente. " +
"Explica QUÉ hace, CUÁNDO usarla y QUÉ necesita.",
inputSchema: {
type: "object",
properties: {
param1: { type: "string", description: "..." }
},
required: ["param1"]
},
execute: ({ param1 }) => {
// ... lógica ...
return { success: true, data: param1 };
},
annotations: { readOnlyHint: true }
}, { signal: controller.signal });
El formato de respuesta puede ser un objeto plano, un string, un número o cualquier cosa que tenga sentido. El agente parsea lo que devuelvas.
Algunas decisiones de diseño que se repiten en el código:
- Enums en
inputSchema:get_menuusaenumcon los IDs de restaurantes, restringiendo al agente a valores válidos a nivel de schema. Es más robusto que depender solo de la descripción. - Descripciones que enumeran opciones: la
descriptiondeapply_promo_codeincluye los códigos válidos directamente. Si el agente falla, el error también los enumera. Se autocorrige solo. readOnlyHint:get_cartyget_order_statuslo declaran comotrue. Le indica al agente que puede llamarlas sin riesgo de mutar estado.
4. La vía declarativa: el formulario de checkout ¶
El navegador interpreta el formulario anotado como una tool invocable. El agente puede rellenar los campos y disparar el submit sin manipular el DOM.
<form
toolname="checkout"
tooldescription="Place a food delivery order and complete checkout.
Requires a delivery address. Use this tool AFTER items have been
added to the cart using the add_to_cart tool."
>
<input name="delivery_address" required
toolparamdescription="Full street delivery address including
apartment or unit number" />
<textarea name="delivery_instructions"
toolparamdescription="Optional delivery instructions for the
driver such as gate codes or drop-off preferences"></textarea>
<select name="tip_amount" required
toolparamdescription="Dollar tip amount for the delivery driver">
<option value="0">No tip</option>
<option value="3">$3.00</option>
<option value="5" selected>$5.00</option>
<option value="8">$8.00</option>
<option value="10">$10.00</option>
</select>
<select name="payment_method" required
toolparamdescription="Payment method to charge. Choose from
saved cards or cash on delivery.">
<option value="visa_4242">Visa ···4242</option>
<option value="mastercard_8888">MC ···8888</option>
<option value="cash">Cash on delivery</option>
</select>
<button type="submit">Place Order</button>
</form>
Fíjate en que el formulario no tiene toolautosubmit. Es checkout: el navegador parará el envío para que el usuario confirme con un clic en el botón. Si fuese un buscador de restaurantes, le habríamos puesto toolautosubmit para que el agente lo enviase sin pausa.
El submit handler usa dos propiedades WebMCP del SubmitEvent:
form.addEventListener('submit', (e) => {
e.preventDefault();
// Validación: ¿hay items en el carrito?
if (state.cart.length === 0) {
if (e.agentInvoked) {
e.respondWith(Promise.resolve({
success: false,
error: "Cart is empty. Add items first."
}));
}
return;
}
// Construir objeto de orden
const order = {
id: 'ME-' + Math.random().toString(36).substring(2, 8).toUpperCase(),
items: state.cart.map(c => ({
name: c.item.name, qty: c.qty,
price: c.item.price, restaurant: c.restaurant.name
})),
total: totals.total + parseFloat(data.tip_amount || 0),
status: "confirmed",
placed_at: new Date().toISOString()
};
// Actualizar UI (efecto colateral)
showOrderConfirmation(order);
// Si lo invocó el agente, devolver JSON estructurado
if (e.agentInvoked) {
e.respondWith(Promise.resolve({
success: true,
message: `Order ${order.id} placed`,
order
}));
}
});
e.agentInvoked es un booleano que indica si el submit lo disparó un agente (true) o un humano (false/undefined). El mismo formulario sirve para ambos casos con la misma lógica.
e.respondWith(Promise) devuelve un resultado estructurado al agente. Sin esto, el agente no recibiría feedback de éxito o error. El patrón está inspirado en Service Workers (FetchEvent.respondWith).
5. Eventos WebMCP y feedback visual ¶
El código escucha dos eventos que el navegador dispara cuando un agente interactúa con las tools:
// Se dispara cuando el agente activa una tool
window.addEventListener('toolactivated', ({ toolName }) => {
agentLog(`🤖 Agent activated: "${toolName}"`);
});
// Se dispara cuando el agente cancela la invocación
window.addEventListener('toolcancel', ({ toolName }) => {
agentLog(`❌ Agent cancelled: "${toolName}"`);
});
Y las pseudo-clases CSS cierran el loop de human-in-the-loop:
/* Se activa cuando el agente está operando el formulario */
form:tool-form-active {
outline: var(--orange) dashed 2px !important;
outline-offset: 4px;
}
/* Se activa cuando el agente está a punto de hacer submit */
button:tool-submit-active {
outline: var(--green) dashed 2px !important;
outline-offset: 2px;
}
El humano que observa la pantalla ve exactamente cuándo un agente está operando el formulario y puede intervenir si algo no cuadra.
6. Flujo completo de un pedido ¶
Así encadena un agente las 9 tools para completar un pedido. Cada paso es una invocación independiente: el agente decide la secuencia basándose en las descripciones de las tools.
1. 🔍 search_restaurants query: "japanese" → restaurant IDs
↓ el agente usa el ID
2. 📋 get_menu restaurant_id: "koji_ramen" → items + precios
↓ el agente elige items
3. 🛒 add_to_cart item_id: "tonkotsu", qty: 2 → confirma added
↓ opcionalmente aplica promo
4. 🏷️ apply_promo_code code: "WELCOME20" → descuento aplicado
↓ verifica antes de pagar
5. ✅ get_cart (sin params) → snapshot completo
↓ rellena form y submit
6. 📝 checkout (form) delivery_address + tip + pay → order ID + ETA
↓ opcionalmente consulta
7. 📦 get_order_status (sin params) → estado actual
La cadena de datos fluye así: cada tool devuelve IDs que el siguiente paso necesita. search_restaurants devuelve restaurant_id, que get_menu consume para devolver item_id, que add_to_cart usa para poblar el carrito que checkout finaliza.
Actualización de mayo de 2026: lo que ha cambiado en la API ¶
El 18 de mayo de 2026, el equipo de Chrome publicó la segunda tanda fuerte de cambios sobre WebMCP. Hay novedades que afectan a cómo escribes las tools, cómo se gestiona su ciclo de vida y a partir de cuándo vas a poder probarlo fuera de un flag de Chrome.
Resumen rápido antes de meternos en harina:
- Origin Trial confirmado en Chrome 149. Hasta ahora solo había modo flag para desarrollo local. Pronto llegará el primer hueco para usarlo en producción acotada.
- API simplificada.
unregisterTool(),provideContext()yclearContext()se han ido. En su lugar, el patrón oficial esAbortControllerpara registrar y retirar tools. - Nueva Permissions Policy
tools. Por defecto valeself. Si quieres exponer tools desde un iframe cross-origin, vas a tener que añadirallow="tools"al iframe. toolautosubmitpara formularios. Un atributo que decide si el agente puede enviar el formulario sin esperar acción humana. Es la pieza clave para la confianza en flujos críticos.- Solo se soportan Tools. Las primitivas Resources y Prompts del MCP de backend no forman parte de WebMCP por ahora.
- Inspector en Chrome Web Store. La extensión Model Context Tool Inspector ya está publicada oficialmente y usa
gemini-3-flash-previewpara hablar contigo en lenguaje natural.
🔑 La idea de fondo no cambia: una web que expone acciones estructuradas a agentes. Lo que cambia es cómo se escribe ese contrato y cómo se gestiona mientras la página vive.
El nuevo ciclo de vida con AbortController ¶
Antes podías llamar a clearContext() para borrar todas las tools de golpe, o gestionar el alta y baja con un puñado de métodos. Esa API ha desaparecido. Ahora cada registerTool() admite un segundo argumento con un AbortSignal, y abortar ese signal es la única vía oficial para quitar la tool del registro.
El patrón típico queda así:
// Crear un controller específico para esta tool
const controller = new AbortController();
navigator.modelContext.registerTool({
name: "get_user_preferences",
description: "Retrieves the user's saved preferences.",
inputSchema: { type: "object", properties: {} },
execute() {
const prefs = localStorage.getItem("user_prefs");
return prefs ? JSON.parse(prefs) : { theme: "light" };
},
// El hint le dice al agente que esta tool no muta estado
annotations: { readOnlyHint: true }
}, { signal: controller.signal });
// Desregistrar la tool (por ejemplo, al desmontar el componente)
controller.abort();
Si trabajas con React, Vue o Svelte, esto encaja bien con el ciclo de vida del componente. En el onMount registras las tools del contexto actual con su controller. En el onUnmount haces controller.abort() y todo queda limpio.
Es un patrón más alineado con el resto de APIs modernas del navegador, donde AbortController ya gobierna fetch, eventos del DOM y muchas más cosas.
toolautosubmit: el control de confianza para formularios ¶
Esta es probablemente la novedad más interesante del lado declarativo. Cuando defines un formulario como tool y le pones el atributo toolautosubmit, el navegador deja que el agente complete y envíe el formulario sin pausar para que el usuario confirme.
Cuando lo omites, el navegador para la ejecución antes del submit, marca el botón con la pseudo-clase :tool-submit-active y espera la acción humana.
<form toolname="search_flights"
tooldescription="Search flights by origin, destination and date"
toolautosubmit>
<!-- Búsqueda: operación inocua y reversible -->
<label>Origen <input name="origin" required></label>
<label>Destino <input name="destination" required></label>
<label>Fecha <input type="date" name="date" required></label>
<button type="submit">Buscar</button>
</form>
<form toolname="confirm_purchase"
tooldescription="Place the final order with the selected payment method">
<!-- Sin toolautosubmit: el usuario tiene que pulsar el botón final -->
<label>Dirección <input name="address" required></label>
<label>Tarjeta <input name="card" required></label>
<button type="submit">Pagar</button>
</form>
La guía oficial es bastante clara sobre cuándo activarlo:
Activa toolautosubmit cuando:
- Es una operación de solo lectura: búsquedas, filtros, consultas de estado.
- La acción es reversible: añadir al carrito, aplicar un cupón, guardar un borrador, cambiar opciones temporales de layout.
Omítelo cuando:
- Es destructiva o irreversible (borrar registros, resetear configuraciones).
- Hay dinero o transacciones de por medio (checkout, transferencias, suscripciones).
- Comunica con otros usuarios reales (envío de mensajes, publicación pública).
- Toca ajustes sensibles de cuenta (cambio de contraseña, permisos, datos de facturación).
🛡️ Resumen para grabarlo a fuego: si la acción se puede deshacer en dos clics, deja que el agente la complete. Si no, obliga a que un humano pulse el botón.
toolparamdescription en cualquier campo, con orden de resolución claro ¶
Antes solo se mencionaba en formularios. Ahora la guía detalla el orden de resolución que sigue el navegador cuando genera la descripción de cada parámetro:
- El atributo
toolparamdescriptionsi está presente en elinput,select,textareaofieldset. - El
textContentdel<label>asociado (saltando descendientes labelables). - El
aria-descriptioncomo último recurso.
Para grupos de campos relacionados (como un grupo de radio buttons), el toolparamdescription va en el <fieldset> padre y aplica al grupo completo.
<form toolname="schedule_demo" tooldescription="Schedule a product demo">
<fieldset toolparamdescription="Preferred meeting format">
<legend>Formato</legend>
<label><input type="radio" name="format" value="video"> Videollamada</label>
<label><input type="radio" name="format" value="onsite"> Presencial</label>
<label><input type="radio" name="format" value="phone"> Teléfono</label>
</fieldset>
</form>
La nueva Permissions Policy tools ¶
WebMCP vive ahora detrás de una Permissions Policy. Por defecto vale self, lo que significa que el sitio principal puede registrar tools y exponerlas, pero los iframes de origen cruzado no.
Si tienes una arquitectura de microfrontends donde cargas widgets de otros dominios, vas a tener que añadir allow="tools" al iframe correspondiente para que sus tools sean visibles al agente.
<!-- Iframe cross-origin con WebMCP habilitado -->
<iframe src="https://widget.example.com/booking" allow="tools"></iframe>
Es una decisión sensata desde el punto de vista de seguridad: por defecto, ningún script de terceros puede colar tools en tu página solo por estar embebido.
Las nuevas demos oficiales que merece la pena revisar ¶
El repositorio webmcp-tools se ha actualizado con tres demos completas, cada una pensada para un escenario distinto:
- WebMCP Pizza Maker (vía imperativa): caso clásico de configurador con muchas opciones que el agente puede recorrer paso a paso.
- Travel demo en React (vía imperativa): muestra cómo encajar WebMCP en una SPA con estado complejo y enrutado.
- Le Petit Bistro (vía declarativa): caso prácticamente sin JavaScript de orquestación, basado en formularios HTML bien anotados.
Si vienes del ejemplo de Midnight Eats que veremos más adelante en este post, te recomiendo abrir Le Petit Bistro y comparar. Verás cuánta lógica te ahorras cuando los formularios ya están bien construidos.
Inspector en la Chrome Web Store ¶
La extensión Model Context Tool Inspector ya está publicada oficialmente. Se llama exactamente así, Model Context Tool Inspector, y la puedes instalar desde la Chrome Web Store.
Te da tres cosas útiles:
- Vista de las tools registradas en la página actual, con su nombre, descripción y esquema.
- Invocación manual de cualquier tool con JSON de entrada, para probar sin necesidad de un agente real.
- Chat en lenguaje natural contra un agente que por defecto usa
gemini-3-flash-preview. Esto es separado de la integración Gemini in Chrome (gemini-3-auto-browse), así que no las confundas.
Si estás construyendo tools para tu propia web, esta extensión es ahora la forma más directa de validar que el agente las entiende. La descripción que escribas en tooldescription es lo que el modelo ve. Si suena ambigua, lo notarás aquí antes que en producción.
Solo Tools: nada de Resources ni Prompts (por ahora) ¶
Pequeña aclaración importante. El protocolo MCP original tiene tres primitivas: Tools, Resources y Prompts. WebMCP, en su versión actual, solo soporta Tools. Si vienes del mundo MCP de backend y estabas pensando en exponer recursos legibles o prompts predefinidos, todavía no es el momento.
Esto puede cambiar. El borrador del W3C deja la puerta abierta, pero hoy lo único que vive en navigator.modelContext son tools.
Buenas prácticas oficiales que conviene fijar ¶
La guía publicada incluye una serie de recomendaciones que merece la pena interiorizar antes de empezar a sembrar tools por tu aplicación:
- Nombra con verbos específicos.
create-eventes mejor questart-event-creation-process. Los nombres largos generan ambigüedad. - Acepta entrada en crudo. No pidas al agente que calcule precios, sumas o porcentajes. Tu código lo hace mejor.
- Tools atómicas y componibles. Cada tool debe hacer una cosa. Evita la tentación de meter flujos enteros en una sola tool.
- No fuerces flujos al agente. Frases como “no llames a B después de A” en la descripción son ruido. Deja que el modelo decida.
- Registra y retira según el contexto. Si tu app tiene rutas, vincula las tools al
AbortControllerde cada ruta. - Errores descriptivos y recuperables. Si una tool falla, devuelve un mensaje que permita al agente reintentar con datos correctos.
- Marca como
readOnlyHintlo que no muta. Las tools de lectura pura son seguras de invocar y el agente necesita saberlo.
💡 Si solo te llevas una idea de toda esta actualización: el patrón mental ya no es “registro tools globales y luego limpio”. Es “cada parte de mi app expone sus tools mientras está viva, y las retira con
AbortControllercuando deja de estar viva”.
Con esto fresco, sigamos con la base de WebMCP. Lo que viene a continuación es el cuerpo del post original, con la idea y los ejemplos que ya estaban en febrero. Cuando veas provideContext() o clearContext() en código antiguo de la red, recuerda: sustitúyelo por el patrón de AbortController que acabas de ver arriba.
Lo que todavía no está resuelto ¶
Sería injusto hablar de WebMCP sin poner encima de la mesa sus agujeros. Y los tiene, bastantes.
No hay descubrimiento de tools sin visitar la página. Un agente no puede saber qué ofrece un sitio hasta que navega a él. No existe (aún) algo como un manifiesto o un .well-known/webmcp.json que permita indexar las capacidades de un sitio. Esto limita mucho los escenarios de automatización a gran escala.
No funciona en modo headless. Las tools viven en el contexto de una pestaña visible. Si tu caso de uso requiere ejecución sin interfaz gráfica, WebMCP no es tu herramienta. Al menos no hoy.
El riesgo de abuso es real. En foros como Hacker News se ha debatido qué pasa cuando agentes ejecutan acciones de forma masiva. ¿Quién paga la factura del backend? ¿Cómo limitas el uso? Las anotaciones de seguridad del borrador son orientativas, no hay enforcement fuerte.
Las SPAs necesitan refactorización. Si tu aplicación tiene la lógica acoplada al estado de los componentes de React, Vue o Angular, exponer tools útiles va a requerir separar esa lógica en una capa de servicios reutilizable. No es trivial en aplicaciones grandes.
Sin Resources ni Prompts. Solo Tools. Si vienes de MCP de backend pensando en exponer un catálogo de recursos o prompts, hoy no es el momento.
⚠️ WebMCP es una apuesta de futuro, no una solución de presente. Pruébalo, experimenta con él, pero no lo metas en producción sin tener muy claro el alcance. Todavía no.
Qué significa esto para los developers ¶
Si trabajas construyendo aplicaciones web, WebMCP te pide que empieces a pensar en tus interfaces de una forma nueva. No solo como algo que un humano ve y usa, sino como algo que un agente puede entender e invocar. Es una de las competencias clave que necesitan los programadores en la era de los agentes de IA.
Esto no significa reescribir todo. De hecho, si tu aplicación está bien diseñada, es probable que ya tengas medio camino hecho. Un formulario con campos bien nombrados, un API REST con endpoints claros, una separación razonable entre lógica y presentación… todo eso es terreno fértil para WebMCP.
Lo que sí cambia es la mentalidad. Hasta ahora diseñábamos pensando en un humano que lee, interpreta y decide. Ahora hay que añadir un segundo “usuario” que no ve colores, no entiende layouts y no hace scroll. Pero que es muy bueno leyendo JSON Schema y ejecutando callbacks.
Tres preguntas para empezar:
- ¿Qué acciones de tu aplicación podrían exponerse como tools? Piensa en los formularios de búsqueda, los flujos de reserva, los paneles de configuración. Cualquier acción estructurada con entradas claras y salidas definidas es candidata.
- ¿Tu lógica de negocio vive en el frontend o en el backend? Si todo está en componentes de UI, vas a necesitar extraerlo a funciones o servicios que las tools puedan llamar sin depender del estado visual. Es un buen ejercicio de arquitectura con o sin WebMCP.
- ¿Dónde necesitas al humano en el proceso? No todo debe ser automático. Una búsqueda puede ser libre. Una compra necesita confirmación. Un borrado de datos necesita doble confirmación. Identifica esos puntos y diseña tus tools en consecuencia: con
toolautosubmitpara lo seguro, sin él para lo crítico.
La ruta de migración si ya usas MCP ¶
Si ya tienes tools expuestas a través de MCP en el servidor, la migración no es un “todo o nada”. Las fuentes oficiales coinciden en un enfoque progresivo:
- Haz inventario de tus tools MCP actuales. El contrato fundamental (nombre, descripción, JSON Schema de entrada) es el mismo en ambos mundos.
- Decide qué vive en cada sitio. Tools que necesitan la sesión del usuario y confirmación visual van a WebMCP. Tools que funcionan sin navegador o necesitan ejecución autónoma se quedan en MCP. Y si quieres que devuelvan interfaces interactivas dentro del chat, las MCP Apps con frameworks como mcp-use son el camino.
- Empieza por los formularios. Si tienes formularios HTML bien estructurados, añadir atributos declarativos es el cambio de menor coste. “Progressive enhancement” puro.
- Separa la lógica de la UI. Si tu frontend es una SPA con estado acoplado, este es el momento de extraer servicios reutilizables. Tus tools WebMCP los necesitarán.
- Adopta el patrón
AbortControllerdesde el día uno. Vincula cada tool al ciclo de vida del componente o ruta que la expone. Te ahorrarás dolores futuros. - Valida con el inspector. La extensión Model Context Tool Inspector está ya en la Chrome Web Store. Úsala para verificar que tus tools se registran bien y que el agente las invoca como esperas.
Quién está detrás y qué peso tiene ¶
El anuncio oficial de febrero de 2026 salió desde Chrome for Developers. La actualización del 18 de mayo de 2026 vino firmada por Alexandra Klepper en el mismo canal. El borrador del W3C Community Group tiene como editores a ingenieros de Google y Microsoft. Eso da peso, pero hay matices.
No es un estándar del W3C. No está en la “Standards Track”. Es un borrador de grupo comunitario, que es el nivel más bajo de formalización dentro del ecosistema W3C. Puede evolucionar hacia algo más sólido o puede quedarse en el camino.
No hay señales públicas de Firefox o Safari aún. Eso no significa que no estén mirando, pero significa que hoy esto es territorio Chromium (Chrome y Edge).
La cobertura mediática ha sido constante. InfoWorld publicó un resumen en febrero. La comunidad de DEV Community reaccionó desde el primer día. Y en WeAreDevelopers hay un vídeo donde los propios autores del borrador explican la propuesta.
Lo que viene ¶
WebMCP todavía es un boceto con bordes difusos. Pero el trazo de fondo es claro: la web necesita una forma nativa de comunicarse con agentes de IA, y el enfoque de “simular lo que haría un humano” tiene los días contados.
Lo más interesante de esta propuesta no es la API en sí. Es el cambio de perspectiva. Durante años hemos construido webs pensando en que las usarían personas. Luego llegaron los bots de scraping y los motores de búsqueda, y aprendimos a hacer SEO. Después vinieron las APIs REST y GraphQL, y aprendimos a separar frontend de backend.
Ahora llegan los agentes de IA. Y la web tiene que adaptarse una vez más.
La diferencia es que esta vez no se trata de optimizar para un crawler o de diseñar endpoints elegantes. Se trata de que tu interfaz web pueda mantener una conversación con un agente, decirle qué sabe hacer, aceptar peticiones y devolver resultados. Es una evolución natural, aunque el camino todavía esté lleno de baches.
Si eres de los que disfrutan probando cosas antes de que estén listas, este es tu momento. Con Chrome 149 a la vuelta de la esquina y el Origin Trial confirmado, ya no hay excusa: instala la extensión del Chrome Web Store, monta un formulario con toolautosubmit y toolparamdescription, y mira cómo un agente lo invoca sin tocar el DOM.
Y si quieres que sea tu agente de IA quien escriba ese código siguiendo el patrón actual de AbortController, toolautosubmit y compañía, el equipo de Chrome ya lo tiene empaquetado: dentro de Modern Web Guidance hay una skill oficial específica para webmcp que enseña a Claude Code, GitHub Copilot CLI o Antigravity a exponer tools imperativas, marcar formularios como agentic-friendly y gestionar la autorización del usuario. Una instrucción de instalación y tu agente deja de inventarse la API.
Y si prefieres esperar a que la cosa madure, anota esto en tu libreta de las ideas (en la Moleskine, si puede ser): los agentes van a ser ciudadanos de primera en la web. La pregunta no es si tu aplicación tendrá que hablar con ellos, sino cuándo.
Referencias ¶
- Anuncio de la actualización de mayo 2026 en Chrome for Developers por Alexandra Klepper.
- Borrador W3C Community Group de WebMCP.
- Repositorio webmcp-tools con las demos oficiales.
- Extensión Model Context Tool Inspector en Chrome Web Store.
- Repo oficial WebMCP en GitHub.
- Guía de mejores prácticas de Chrome.
- Estado de implementación en Chrome.
- Modern Web Guidance de Google para WebMCP.
Experimenta. Rompe cosas. Y cuando algo no funcione, lee el error desde el principio, no desde el final.
12 recursos para developers cada domingo en tu bandeja de entrada
Además de una skill práctica bien explicada, trucos para mejorar tu futuro profesional y una pizquita de humor útil para el resto de la semana. Gratis.