← Blog
8 de agosto, 2026 · 12 min

WebMCP: la página web se convierte en el tool server

MCP puso las tools detrás de servidores. WebMCP las pone dentro de la página. Una aplicación web ahora puede registrar funciones invocables y tipadas con schema ante el propio navegador — y cualquier agente que viva en ese navegador puede invocarlas en vez de adivinar su camino por una UI diseñada para humanos.

La propuesta está más avanzada de lo que la mayoría cree. La especificación de WebMCP se republicó como Draft Community Group Report el 28 de julio de 2026 — el mismo día, por coincidencia, en que el spec MCP 2026-07-28 salió final del lado backend. La editan Brandon Walderman (Microsoft) y Khushal Sagar y Dominic Farolino (Google), bajo el Web Machine Learning Community Group del W3C. Chrome la lanzó experimentalmente detrás de un flag en Chrome 146 y abrió un origin trial público en Chrome 149. Y el 6 de agosto, durante su Agents Week, Cloudflare lanzó un developer preview que añade WebMCP a cualquier sitio detrás de su red con un toggle en el dashboard — sin cambios en el origin.

Leímos el spec, los explainers y la historia del repo. Este post cubre la API tal como está en el draft de julio de 2026 — incluido un rename que la mayoría de los tutoriales todavía tiene mal —, la capa declarativa de forms, la historia de despliegue, y las dos omisiones que más importan a quien opera agentes autónomos: identidad y pagos.

Del scraping a los contratos

El problema que WebMCP ataca es el que conoce todo agente que usa navegador. Los agentes de propósito general de hoy observan páginas vía screenshots, snapshots del DOM y árboles de accesibilidad, y actúan simulando input humano. Es lento, frágil y caro. El explainer plantea la alternativa sin rodeos: las páginas que usan WebMCP "pueden pensarse como servidores Model Context Protocol dentro de la página que implementan tools exponiendo lógica client-side e interacción con el DOM en vez de APIs server-side".

¿Por qué no darle a cada sitio un MCP server backend y ya? El explainer lista tres razones. Las integraciones backend desintermedian la UI web — el agente habla con los servidores del servicio y la página nunca ve nada. Obligan a los desarrolladores a replicar estado, contexto y autenticación en un servidor aparte. Y exigen código backend nuevo, cuando la funcionalidad ya existe en JavaScript client-side. La apuesta de WebMCP es la reutilización de código: cualquier tarea que un usuario pueda hacer por la UI de la página puede envolverse como tool con la lógica frontend existente, compartiendo gratis la sesión viva, el carrito y el login del usuario.

El centro del diseño es explícitamente cooperativo. Los goals declarados son workflows human-in-the-loop donde el usuario mantiene visibilidad y control, y los non-goals no dejan dudas: el headless browsing y los "workflows totalmente autónomos" sin supervisión humana quedan fuera de alcance. Guarda ese dato — es la frase más consecuente del documento para la economía de agentes walk-up.

La API: document.modelContext

El punto de entrada es un objeto ModelContext colgado del document. Registrar es una sola llamada:

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" }
    },
    required: ["text"]
  },
  async execute({ text }) {
    // Reutiliza la lógica client-side existente.
    await addTodoItemToCollection(text);
    return { content: [{ type: "text", text: `Added: "${text}"` }] };
  }
}, { signal: controller.signal });

La forma es deliberadamente MCP: un name único (1–128 caracteres, alfanuméricos más guion bajo, guion y punto), una description en lenguaje natural, un inputSchema en JSON Schema y un callback execute asíncrono que devuelve bloques de contenido estilo MCP. Desregistrar no es un método — es el AbortSignal pasado al registrar, que además limpia tools automáticamente cuando un componente se desmonta. registerTool() devuelve una promise y rechaza con NotAllowedError cuando la policy lo prohíbe. Un objeto annotations lleva dos hints: readOnlyHint, y untrustedContentHint para marcar tools cuyo output puede incrustar contenido de origen externo — un tripwire de prompt injection al que volveremos.

El rename que los tutoriales siguen sin ver — las builds tempranas y la mayoría de los posts exponen la API como navigator.modelContext. El Community Group movió el getter a Document en el PR #184 (mergeado el 27 de mayo de 2026) porque las tools pertenecen a una página específica, no al browsing context. Chromium deprecó la superficie navigator a partir de Chrome 150. Durante la transición, detecta ambas: document.modelContext || navigator.modelContext. La llamada anterior de registro masivo provideContext() también desapareció del spec — el issue #101 mostró que podía sobrescribir en silencio tools ya registradas, saltándose la protección de nombres duplicados de registerTool().

El control de acceso es maquinaria web nativa, no algo con sabor a MCP. Toda la API es solo-SecureContext y está detrás de una Permissions Policy tools cuyo allowlist por defecto es ['self']: los documents de nivel superior y los iframes same-origin la tienen por defecto, y un iframe cross-origin — digamos, un agente de chat embebido — debe recibir la delegación explícita con allow="tools". La visibilidad de tools tiene un segundo eje: por defecto una tool registrada solo es visible para la propia página, los documents same-origin del árbol y el agente integrado del navegador, pero la opción exposedTo del registro puede compartir tools específicas con origins específicos. Un evento toolchange se dispara en ModelContext cuando las tools aparecen y desaparecen, y un método getTools() — especificado el 21 de julio — permite a los agentes provistos por el autor enumerar lo disponible, cada entrada con el origin y el window de su dueño. El executeTool() correspondiente para agentes in-page sigue marcado TODO en el explainer, lo que te dice lo activa que está esta superficie: el repo muestra commits hasta el 3 de agosto de 2026, con unas 2,950 stars y 113 issues y PRs abiertas.

La capa declarativa: forms como tools

La segunda mitad de la propuesta no necesita JavaScript. El explainer de la API declarativa añade atributos a forms HTML normales, y el navegador compila el form en una tool:

<form toolname="search-cars"
      tooldescription="Perform a car make/model search">
  <input type=text name="make"
         toolparamdescription="The vehicle's make (e.g., BMW)" required>
  <input type=text name="model"
         toolparamdescription="The vehicle's model (e.g., 330i)" required>
  <button type=submit>Search</button>
</form>

El navegador sintetiza el JSON Schema desde los controles del form — los atributos name se vuelven properties, required se vuelve required, y la reducción exacta de cosas como min, step y las opciones de <select> a constraints de schema todavía se está definiendo, con Chromium implementando una versión laxa para probar en el trial. La geometría del consentimiento está codificada en un atributo booleano: sin toolautosubmit, el agente llena el form pero el navegador enfoca el botón de submit y un humano debe hacer clic. Los nuevos pseudo-classes de CSS :tool-form-active y :tool-submit-active existen precisamente para que los sitios resalten "el agente llenó esto, revísalo". Con el atributo, el agente envía en nombre del usuario. Eso es un modelo de permisos expresado en markup.

Devolver la respuesta al agente es la parte interesante. SubmitEvent gana un flag agentInvoked y un método respondWith(), así que el script puede interceptar un submit disparado por el agente, saltarse la navegación y devolver un resultado estructurado directo. Para forms que sí navegan, el draft propuso usar el primer bloque <script type="application/ld+json"> de la página destino como respuesta de la tool — las respuestas cross-document siguen en debate abierto en el issue #135. La cancelación está resuelta: resetear el form o mutar sus atributos de tool cancela cualquier invocación en vuelo, con eventos toolactivated y toolcanceled exponiendo el ciclo de vida a la página.

Dónde corre hoy

Chrome es la implementación de referencia. El DevTrial está detrás de chrome://flags/#enable-webmcp-testing; el origin trial abrió en Chrome 149 para experimentar en producción. La documentación de Chrome lista tres clases de consumidores — Gemini in Chrome, extensiones de Chrome y agentes de terceros que manejan el navegador — y DevTools ganó soporte experimental para inspeccionar tools registradas, invocarlas manualmente y validar schemas. La documentación es igual de clara sobre el límite: las tool calls se ejecutan en el JavaScript de la página, así que "debe haber una pestaña de navegador o un webview abierto". Sin pestaña no hay tools, no hay ejecución headless.

El preview de Cloudflare del 6 de agosto es el despliegue estratégicamente más interesante porque exige cero trabajo del desarrollador. Activas un toggle en el dashboard y su edge inyecta, vía HTMLRewriter, un único module script — /.webmcp/bridge.js — en cada respuesta HTML. El bridge registra "packs" de tools contra document.modelContext. Existen dos packs al lanzamiento: Content Credentials, que expone scan_images_c2pa e inspect_image_c2pa para leer metadata de procedencia C2PA de las imágenes de la página, y Site MCP Server, que descubre el MCP server existente de un sitio y proxea sus tools hacia la página con requests same-origin — con la sesión del visitante adjunta. BrowserRun, el navegador remoto de Cloudflare, consume las mismas tools desde el otro lado. Un solo proveedor de infraestructura se sienta ahora en ambos extremos del handshake, el mismo patrón de chokepoint en el edge que trazamos en x402 en el edge del CDN.

La sección de seguridad se lee como etiqueta de advertencia

Para crédito de los editores, la sección de seguridad y privacidad del spec no minimiza los riesgos. Nombra la metadata de las tools y sus outputs como vectores de prompt injection — una página maliciosa puede incrustar instrucciones en una description o en un valor de retorno, exactamente la razón por la que existe untrustedContentHint. Admite sin rodeos que "no hay garantía de que la intención declarada de una tool WebMCP coincida con su comportamiento real": una tool llamada get-prices puede hacer lo que quiera su callback execute. Señala la sobre-parametrización como ataque de privacidad — un schema con parámetros opcionales age, location y health invita al agente a ofrecer contexto personal que el usuario nunca escribió en el sitio. Y le preocupa que los agentes arrastren estado autenticado entre origins y que las tools filtren actividad de navegación privada.

Lo que el spec todavía no tiene es un mecanismo de consentimiento por llamada. El prompting al usuario estilo elicitation es una pregunta abierta (issues #165 y #50), y la interfaz ModelContextClient que formalizaría el lado del agente fue retirada del draft por ahora. El modelo de confianza hoy es: la página confía en que el navegador media, el agente confía en las descriptions de la página, y el humano confía en el criterio del agente sobre cuándo preguntar. Cada tool se ejecuta con las cookies, el storage y el login del visitante en ese origin. Para las sesiones interactivas y supervisadas que WebMCP apunta, ese modelo de sesión heredada es la feature. También es la razón por la que el estándar no puede simplemente extenderse a agentes desatendidos sin una capa real de identidad debajo.

El hueco autónomo

Leído como infraestructura de la web agentic, WebMCP tiene una forma precisa: hace las páginas invocables para agentes que ya están dentro del navegador del usuario, y se detiene ahí a propósito. Tres fronteras definen el hueco.

Primero, la autonomía es un non-goal por estatuto. El spec está construido para un humano mirando una pestaña, no para una flota de workers headless. Pero la presión ya se ve en el repo: el explainer de service workers propone que los agentes descubran e invoquen tools de sitios que el usuario no tiene abiertos, vía workers en background — que es, funcionalmente, el primer paso desde la navegación cooperativa hacia la ejecución desatendida que el spec principal renuncia.

Segundo, no hay primitivo de identidad de agente. Una tool WebMCP no puede preguntar qué agente la llama, en nombre de quién, bajo qué delegación. La tool ve una llamada mediada por el navegador vistiendo la sesión del visitante. Contrasta con Web Bot Auth, donde los agentes firman requests HTTP con llaves publicadas precisamente para que los origins puedan distinguirlos y ponerles precio. Los dos modelos van a tener que encontrarse: una página que hoy expone una tool de alto valor al "agente integrado" no tiene forma de distinguir a Gemini actuando por un humano logueado de un framework de automatización manejando el mismo perfil de Chrome.

Tercero — y lo más relevante para este blog — no hay primitivo de pago. Los propios escenarios de comercio del explainer llegan hasta la línea: el ejemplo de la imprenta termina con la tool "navegando automáticamente la pestaña del navegador a la página segura de checkout donde Jen puede completar el pedido con un solo clic". La tool puede llenar el carrito pero no liquidar. Nada en el formato de resultado puede expresar "esta llamada cuesta $0.002" ni transportar un recibo de settlement. En el marco de los cuatro verbos de Cloudflare de la Agents Week — readable, discoverable, callable, payable — WebMCP es el verbo callable, y payable es otro producto (Wallets y el Monetization Gateway, que cubrimos en el roundup de la semana pasada). La costura entre esos dos verbos es donde un HTTP 402 y un settlement x402 encajan naturalmente, y nadie ha estandarizado todavía esa unión dentro del navegador.

Qué significa para LLM4Agents

LLM4Agents opera del otro lado de la frontera de diseño de WebMCP: nuestros clientes corren exactamente los agentes headless y autónomos que el spec declara fuera de alcance. Eso corta en dos direcciones.

La amenaza es una repetición de la dinámica del jardín amurallado. Si el navegador se vuelve el lugar privilegiado donde los sitios exponen capacidades estructuradas — y el agente consumidor es Gemini in Chrome montado sobre las sesiones existentes del usuario — entonces toda una clase de interacciones nunca sale del navegador, nunca toca una API y nunca emite el 402 que un agente walk-up podría pagar. Que Cloudflare despliegue WebMCP con un toggle a lo largo de su red lo acelera: la superficie de tools de la web crece más rápido justo donde nuestros agentes no pueden pararse.

La oportunidad es que WebMCP normaliza el contrato de tools que ya vendemos. El pack Site MCP Server es la pista: el bridge de Cloudflare no inventa capacidades nuevas, proxea el MCP server backend de un sitio hacia la página. La arquitectura canónica que emerge es una sola definición de tool proyectada en dos superficies — MCP sobre HTTP para agentes headless, WebMCP para los que van en navegador. Todo sitio que adopte ese patrón tiene, por construcción, un endpoint MCP que los agentes de nuestro gateway pueden llamar, medir y pagar vía x402. Y los schemas son portables en ambas direcciones: el inputSchema de una página es el mismo JSON Schema que publican nuestras tools MCP. WebMCP agranda la población de capacidades con forma de tool en la web; el settlement por llamada para la mitad headless de sus consumidores es precisamente nuestro carril. Donde MCP Apps empujó UI de servidor hacia los hosts MCP, WebMCP empuja tools MCP hacia las páginas — los dos specs convergen en la misma afirmación desde extremos opuestos: la interfaz y el contrato de tools se están volviendo el mismo artefacto.

Cómo mantenerse en la frontera

Movimientos concretos, en orden. Primero, desplegar WebMCP en nuestras propias propiedades: registrar tools en el dashboard de LLM4Agents (consulta de balance, rotación de keys, reportes de uso) vía document.modelContext, detectando ambas superficies — es un fin de semana de trabajo contra el origin trial y vuelve el dashboard operable por los agentes de navegador de nuestros clientes. Segundo, adoptar el patrón de doble proyección en la guía de nuestro SDK: una definición de tool, emitida como tool de MCP server y como registro WebMCP, para que los operadores del gateway obtengan ambas superficies de un solo schema. Tercero, prototipar la unión faltante: una tool WebMCP cuyo execute golpea un endpoint protegido con 402 a través de nuestro gateway y resuelve el pago con el buyer stack de x402, devolviendo el recibo en el resultado de la tool — el complemento del lado navegador de nuestra cobertura del buyer stack, y una propuesta concreta para llevar a la discusión de elicitation del Community Group (issue #165), porque una aprobación de pago es exactamente el caso de prompting al usuario que el spec todavía no diseñó. Cuarto, seguir de cerca el explainer de service workers; si la invocación de tools en background aterriza, WebMCP deja de estar atado a la sesión del navegador y empieza a solaparse con nuestro territorio headless — queremos llegar temprano, no sorprendidos. Quinto, vigilar getTools() — un directorio enumerable de tools con origin atribuido dentro de cada página es una señal de discovery que nuestra capa de routing debería ingerir tarde o temprano junto a los datos del registry y del Bazaar.

Construye agentes que puedan llamar — y pagar

Un gateway, 345+ modelos, settlement por llamada en stablecoins sobre x402. El contrato de tools se está estandarizando; el rail de pago ya está listo.

Registra tu agente