API / Auth / MCP Hard

WebMCP: site tools for in-browser AI agents

What WebMCP (the document.modelContext browser API) is, how it differs from a remote MCP server, a minimal registerTool example, mistakes, and how to verify.

Updated:

What it is

WebMCP is a browser JavaScript API from a W3C Web Machine Learning Community Group draft (authors from Microsoft and Google). A page registers “tools” — functions with a name, a description and a JSON Schema for their input — via document.modelContext.registerTool(). The browser’s AI agent (or an agent in an iframe or extension) calls these functions directly instead of clicking through the DOM.

Tool code runs in the page itself, under the user’s session: the same cookies, the same app state. WebMCP shares vocabulary with MCP (tools, inputSchema), but it is not the MCP wire protocol: WebMCP has no server endpoint, no transport and no URL to connect to.

Don’t confuse it with a remote MCP server (the Streamable HTTP / SSE transport at a path like /mcp) — that is a separate mechanism, discovered via an MCP Server Card.

Why it matters for AI agents

An agent that drives a site through screenshots and clicks is slow and brittle: the layout changes and the flow breaks. WebMCP gives it an explicit contract: “these are the actions available here, with these parameters”. Benefits:

  • Reliability — a function call instead of guessing which button to press.
  • No separate backend for agents — the tool reuses your client code and the user’s authorization.
  • User in the loop — the result shows up in the UI they already have open.

Status as of October 2026: origin trial in Chrome 149 and Edge 150 (local development via the about:flags#enable-webmcp-testing flag), supported in ChatGPT Desktop, experimental in Brave; Firefox and Safari have no position yet. The declarative <form> variant was removed from the spec on October 8, 2026 — the imperative API remains.

Minimal working example

<script type="module">
  if ('modelContext' in document) {
    const controller = new AbortController();

    await document.modelContext.registerTool({
      name: 'add-to-cart',
      description: 'Adds a product to the cart by SKU',
      inputSchema: {
        type: 'object',
        properties: {
          sku: { type: 'string', description: 'Product SKU' },
          qty: { type: 'integer', minimum: 1, description: 'Quantity' },
        },
        required: ['sku'],
      },
      async execute({ sku, qty = 1 }) {
        // Same function as the "Add to cart" button: checks, session, UI update
        const item = await addToCart(sku, qty);
        return { content: [{ type: 'text', text: `In cart: ${item.title} × ${qty}` }] };
      },
    }, { signal: controller.signal });

    // controller.abort() unregisters the tool — e.g. once it no longer applies
  }
</script>

The API is available only in a secure context (HTTPS). Agents in a cross-origin iframe see the tools only with allow="tools" on the iframe and an explicit origin list in the exposedTo option at registration. Changes to the tool set fire a toolchange event.

Right vs wrong

RightWrong
A few tools, each with a single responsibilityDozens of catch-all tools that eat the model’s context
Input, authorization and preconditions checked inside executeTrusting the agent’s arguments — a schema is not a safeguard
The UI updates after a call just as it would after a clickThe action happens “invisibly”, the UI shows stale state
Tools registered and removed with app state (AbortSignal)Every tool always registered, even when it doesn’t apply
A 'modelContext' in document check before callingErrors in browsers without WebMCP

Common mistakes

  • Confusing WebMCP with a remote MCP server — a /mcp endpoint and the SSE transport have nothing to do with WebMCP.
  • The old navigator.modelContext API — in the current spec the object lives on document.
  • Declarative <form> tools — removed from the spec, don’t build on them.
  • No checks in execute — an agent can pass anything; validate it like user input.
  • A page served over HTTP — outside a secure context document.modelContext is unavailable.

How to verify

The webmcp check in the scanner is informational (weight 0, doesn’t affect the score) and isn’t run yet: tools are registered from JavaScript, and the scanner doesn’t execute page scripts. A cheap static signal is possible — a modelContext.registerTool call in the page’s scripts — but it only shows the code exists, not that the tools work.

Manually:

  1. Chrome 149+ with the about:flags#enable-webmcp-testing flag (or an origin trial on your domain).
  2. Open the page over HTTPS and run 'modelContext' in document in the DevTools console — it should be true.
  3. Per the spec, await document.modelContext.getTools() returns the tools registered on the page — yours should be in the list.

Sources