Web APIs, todayLab · Alex Harto

WebMCP

The page tells the AI agent what it can do, instead of letting it guess clicks.

In your browser: checking…Reviewed 1 Oct 2026

Each tool has a name, a description, a JSON input schema and a function. You register it with document.modelContext.registerTool() or, with no JavaScript, by marking up a form with toolname and tooldescription. A browser agent or an extension discovers and runs them.

It is a Google and Microsoft proposal in the W3C Web Machine Learning Community Group, in origin trial in Chrome (since 149) and Edge (since 150). Mozilla is neutral and WebKit opposes it. The API changed a lot this year: it used to be navigator.modelContext, deprecated since Chrome 150.

What it is for

  • Letting an assistant fill an order or a booking without breaking the UI
  • Exposing a catalogue’s search and filters
  • Automating web-app tasks with the user present

Demo

A to-do list that offers itself to agents: four tools (one of them is the form). On the right, the console acts as the agent: it lists the page’s tools and runs them the way an assistant would.

The app

    Agent console ·

    Browser support

    Limited availability
    FeatureDesktopMobile
    ChromeEdgeFirefoxSafariChrome AndroidFirefox AndroidSafari iOS
    document.modelContext149trial1Chrome: 149 trial150trial2Edge: 150 trial—3Firefox: No—4Safari: No—Chrome: No—Firefox: No—Safari: No
    Forms (toolname…)149trial5Chrome: 149 trial150trialEdge: 150 trial—Firefox: No—Safari: No—Chrome: No—Firefox: No—Safari: No
    1. 1“WebMCP” origin trial since 149; locally, chrome://flags/#enable-webmcp-testing. The old navigator.modelContext is deprecated since 150.
    2. 2Origin trial since Edge 150, until 30 March 2027.
    3. 3Mozilla position: neutral.
    4. 4WebKit position: oppose.
    5. 5Part of the same origin trial.

    Compatibility generated on every deploy from MDN browser-compat-data 8.1.3 (24 Sep 2026) · web-features 3.40.0 · checked by hand: 1 Oct 2026

    To try it: chrome://flags/#enable-webmcp-testing and the Model Context Tool Inspector extension, or an origin-trial token for your domain.

    Minimal code

    <!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>

    What’s new

    1. The draft adds annotations (consequentialHint, untrustedContentHint) and the toolactivated and toolcancel events.
    2. executeTool() takes its input as an object: passing it as a JSON string is deprecated from Chrome 155.
    3. Edge 150 opens its origin trial, until 30 March 2027.
    4. “WebMCP” origin trial in Chrome from 149.
    5. The draft moves the API from navigator to document.modelContext; Chrome deprecates the old one in 150.
    6. provideContext, clearContext and unregisterTool are removed: abort the registration’s AbortSignal to remove a tool.

    Keep in mind

    1. executeTool(tool, input): the input is an object, but Chrome wanted it as a JSON string up to 154. If it fails with “Failed to parse input”, retry with JSON.stringify().
    2. execute() must always return something serialisable (a string or an object): returning undefined counts as a failure.
    3. Secure contexts only. A cross-origin iframe needs allow="tools".
    4. There is no consent model: mark consequential tools with consequentialHint so the agent asks for confirmation.

    Further reading

    Sources