WebMCP: el joystick de tu web para los agentes

angular

El soporte experimental de Angular 22 para dar a los agentes de IA controles directos sobre tu UI, más allá del scraping o el screenshot, con la mirada puesta en la AX.

7 min de lectura

TL;DR

MCP (Model Context Protocol) es el estándar con el que un agente de IA descubre y usa herramientas externas. WebMCP lleva esa idea al contexto de la web, o sea al navegador. Una web puede registrar sus propias tools para que el agente del usuario (una extensión o el navegador directamente) las descubra y las llame. Angular 22 trae una API experimental para declarar esas tools como providers dentro del framework. No estás ante una simple entrada donde se explica el concepto, si usas Chrome y tienes activado el flag, deberías poder ver una etiqueta de webmcp en la header de la página. Una IA podría buscar información que viva en este blog y llevarte a ella. En esta entrada explico cómo podemos explotarlo paso a paso.

Advertencia

Tanto la especificación de WebMCP como la API de Angular están en fase experimental. La sintaxis puede cambiar y hoy el soporte se limita a Google Chrome. Tómalo como un vistazo hacia el futuro, no como algo que llevar a producción.

Qué es WebMCP

La versión de MCP que quizá conozcas es la de HTTP (servidor) o stdin (local). WebMCP es lo que da la vuelta a esto y, en lugar de un servidor, permite que sea la propia página la que publique sus herramientas en tiempo de ejecución, a través de un objeto que el navegador inyecta (document.modelContext). Hasta hace poco la definición se almacenaba en navigator.modelContext, pero el 21 de julio de 2026 se movió a document porque las tools pertenecen a una página concreta, no al navegador entero. Chrome ya deprecó la ubicación antigua aunque el origin trial sigue sirviéndola, así que si tu código es de antes de esa fecha, toca migrarlo (o mantener un fallback del tipo document.modelContext ?? navigator.modelContext).

Cuando ese objeto existe, un agente puede leer las tools que la página ha registrado y ejecutarlas. Lo interesante que aporta WebMCP es su contraste contra la operativa más tradicional. Hoy una IA que quiere interactuar con tu web o monta un motor de scraping tipo Playwright para leer el DOM, o directamente va a capturas de pantalla e infiere dónde clicar por píxeles (así funciona, por ejemplo, la extensión de Claude para el navegador). Con esto ya no hace falta nada de eso ya que contamos con acciones directas ("rellena este formulario con los datos XYZ") y es la IA quien las usa según lo que le pida el usuario. En teoría esto también ahorra tokens ya que en vez de mandarle el DOM entero o una imagen para que interprete la pantalla, le das la herramienta directamente para interactuar con tu interfaz.

El soporte de Angular

Angular, en su versión 22, permite el registro de tools WebMCP en su sistema de providers, con dos piezas principales:

  • provideExperimentalWebMcpTools([...]): Un provider que registra un array de tools al arrancar la app (disponible en todas las páginas de la web).
  • WebMcpToolDescriptor: El tipo que describe una tool: nombre, descripción, esquema de entrada y la función que la ejecuta.

Lo mejor es que el registro funciona de forma segura en SSR. Este blog se prerenderiza en servidor, y la API de Angular ya contempla ese caso.

Anatomía de una tool

Una tool es un objeto que satisface WebMcpToolDescriptor. Este es, esencialmente, el buscador de contenido estático que dispone este blog (search_docs):

mcp/tools/search-docs.tool.ts
export function docsSearchTool(): WebMcpToolDescriptor<typeof searchSchema> {
  return {
    name: 'search_docs',
    description:
      'Searches the blog articles and returns the domain-less route ' +
      'where the information lives, with deep links to the relevant sections.',
    inputSchema: searchSchema,
    execute: (args) => {
      // Validación mínima de argumentos
      const query = typeof args?.query === 'string' ? args.query : '';
      const limit = typeof args?.limit === 'number' ? args.limit : 5;
 
      // Articles representa una estructura con el contenido del blog
      const results = searchDocs(articles, query, limit);
      return { content: [{ type: 'text', text: buildPayload(query, results) }] };
    },
  };
}

A continuación vamos a explicar qué responsabilidad tiene cada campo de la definición de una tool:

  • name es el identificador con el que el agente invoca la tool.
  • description es lo único que el agente usa para decidir cuándo usarla.
  • inputSchema es un JSON Schema que describe los argumentos de entrada. En este caso un query obligatorio y un limit opcional.
  • execute recibe esos argumentos y devuelve el resultado en el formato que espera MCP: { content: [{ type: 'text', text }] }. En nuestro caso, un JSON serializado con las rutas donde vive la información.

Como JSON Schema plano, el inputSchema tendría la siguiente pinta:

inputSchema de search_docs
{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "description": "Natural language query about the blog's documentation.",
      "minLength": 1
    },
    "limit": {
      "type": "integer",
      "description": "Maximum number of articles to return (1-20). Defaults to 5.",
      "minimum": 1,
      "maximum": 20
    }
  },
  "required": ["query"]
}

Registrar las tools

El siguiente paso natural sería inyectar las tools en la config de la aplicación:

app.config.ts
import { provideExperimentalWebMcpTools } from '@angular/core';
// ...resto de imports de la app
import { docsSearchTool } from '@mcp/tools';
 
export const appConfig: ApplicationConfig = {
  providers: [
    // ...resto de providers de la app
    provideExperimentalWebMcpTools([docsSearchTool()]),
  ],
};

Al ir en app.config.ts, la tool queda disponible globalmente. Da igual en qué página de la web esté el usuario, search_docs está siempre registrada.

Nota

Un matiz de tipos que conviene conocer: si registraras una segunda tool con un inputSchema distinto, necesitaría su propia llamada a provideExperimentalWebMcpTools, y no meterla en el mismo array.

// ❌
provideExperimentalWebMcpTools([docsSearchTool(), otraTool()]),
 
// ✅
provideExperimentalWebMcpTools([docsSearchTool()]),
provideExperimentalWebMcpTools([otraTool()]),

Esto es un comportamiento un poco raro y seguramente cambie cuando la especificación sea estable.

Tools que no solo leen contenido

Hasta aquí la tool "lee" contenido de la web. Pero WebMCP también deja que un agente actúe sobre la UI. Angular 22 lleva esa idea a los signal forms al declarar un form() con la opción experimentalWebMcpTool (el propio formulario se publica como tool). El agente completa los campos y ejecuta submit(), pasando por las mismas validaciones que un humano.

webmcp-form.component.ts
protected readonly contactForm = form(
  this.model,
  (path) => {
    required(path.name, { message: 'El nombre es obligatorio' });
    required(path.email, { message: 'El email es obligatorio' });
    email(path.email, { message: 'Email no válido' });
  },
  {
    experimentalWebMcpTool: {
      name: 'fill_contact_form',
      description:
        'Fills and submits the contact form on this page. Provide name (min 2 chars), a ' +
        'valid email, an optional role, a message (min 10 chars)...',
    },
  },
);

El contrato es el mismo que una tool normal, name y una description que le dice al agente cuándo usarla. La diferencia es que no escribes tú el execute. provideExperimentalWebMcpForms() conecta el formulario a la tool y permite todo esto. Utiliza "rellena el formulario de contacto con datos de ejemplo" y mira cómo se completan los campos.

Dónde está el límite

WebMCP es una ventana a un futuro donde las webs no solo tienen UI para ser utilizadas por humanos sino que también para agentes de IA. Lo bueno de lo que hemos visto es que su integración en Angular es muy sencilla (un descriptor y un provider) y que dentro de las tools podemos usar la misma inyección de dependencias que en el resto de la web. Como prueba, la de esta web donde te encuentras leyendo necesita solo unas pocas líneas para que una IA sea capaz de buscar en su contenido y procesar un formulario. Al final creo que se está abriendo una nueva dimensión a lo que siempre hemos conocido por UX, allanando el camino hacia el AX.

© 2026Roberto Pérez Llanos