WebMCP Explained: Giving Browser AI Agents Tools Instead of Guesswork
WebMCP lets a web page hand browser AI agents real tools: how to register them, annotate risk, test in Chrome, handle security, and where support is in 2026.
This article is published in English.
Sources: Meet WebMCP: MCP’s Browser Cousin That Makes AI Agents More Accurate
Ask an AI agent to book a flight on a website and watch what happens. It opens the page and starts feeling around. Which element is the date picker? Which dropdown holds the destination? Which button needs two clicks because a modal is covering it? Sometimes the agent gets through. Sometimes it clicks the wrong thing, fills a field with junk or stalls at checkout because the layout changed after the model was trained.
That's how most browser-based agents operate today. They scrape the DOM, work out each element's purpose from its label and where it sits, and then fake the clicks and keystrokes a person would produce. The technique is called actuation, and it looks great in a demo and falls apart in practice. Change one CSS class or move a button, and an agent that worked yesterday goes off the rails.
WebMCP is a response to that. If you know the Model Context Protocol (MCP) on the backend, the idea is easy to state: take the notion of tools and move it into the browser, so it lives on the pages you build.
Why looking at the DOM isn't enough
Agents currently reach a service by one of two routes:
- Backend integration. The service registers tools with an AI platform, through an MCP server, OpenAPI or some proprietary API, and the AI talks straight to the server without touching the browser.
- Browser actuation. The agent opens the page like a human and guesses which elements to click or fill.
Actuation is expensive and easy to get wrong. Every step can be misread, especially in complex, layered interfaces like modern single-page apps.
WebMCP adds a third route, which is neither a backend integration nor blind clicking. The site itself declares what it can do. Instead of an agent guessing what the Checkout button does, the developer states what checkout does, what input it needs and what it returns.
What WebMCP is
WebMCP is a proposed web standard from the Web Machine Learning Community Group at the W3C. The spec defines a JavaScript API plus annotations for HTML form elements so an agent knows how to use the page's features without guessing.
Compare it with backend MCP. A page that implements WebMCP behaves like an MCP server whose tools run as client-side script. Where you'd normally stand up a separate server to expose a function, you can register that function from the JavaScript already running on the page.
Three pieces make up the design:
- Discovery: a standard way for pages to register tools such as
checkoutorsearch_productswith an agent. - JSON Schema: explicit definitions of expected inputs and outputs, which reduces hallucination and misunderstanding.
- State: a shared picture of the page's current context, so the agent knows what it can act on right now.
One more detail: tools still run visibly on the page. When an agent calls an add_to_cart tool, the result shows up in the UI instead of happening silently. That matters for trust, because users can see what's done for them and the experience you designed isn't bypassed.
Registering WebMCP on a site
Adding it to an existing site isn't a rebuild. It's an extra communication layer sitting on a backend that already works. The steps:
1. Enable the environment. Since the standard is only proposed, turn it on by hand for experiments. In Chrome, open chrome://flags/#enable-webmcp-testing, set it to Enabled and restart the browser. For something closer to production, sign up for the WebMCP origin trial that begins in Chrome 149, so real visitors can use the feature without touching flags.
2. Pick tools worth exposing. This step is easy to underrate. Don't expose every function just because you can. Think about which actions people would genuinely want an agent's help with, usually those with one clear purpose: searching, filtering, submitting a form, checking out. Avoid dozens of tools on one page, since each registered tool consumes context-window space and a long menu muddles the agent's choice.
3. Choose the imperative or declarative API. The imperative API registers tools with plain JavaScript through registerTool and suits more involved logic such as state management, navigation or chaining actions. The declarative API puts annotations directly on a standard HTML <form>, and the tool gets built for you, which fits simple form-driven cases. React and Angular projects have framework-native options. React offers the usewebmcp package, whose useWebMCP hook ties a tool's lifecycle to a component's mount and unmount. Angular has experimental support that can turn Signal Forms into tools.
4. Make the inputSchema detailed. This decides how well an agent understands the tool. Write the description in plain natural language and not internal shorthand, and define every property with its type. For a closed set of values, use enum so the agent is less likely to send something invalid.
5. Set annotations to match real risk. Each tool needs an honest label:
readOnlyHint: truefor a tool that just reads and leaves everything unchanged.consequentialHint: truefor an action with real effects, which should prompt the user for confirmation first.untrustedContentHint: truewhen the output includes content from other users, such as reviews or comments, which might hide an instruction.
6. Wire execute to an existing endpoint. The execute function can simply call the API route you already have, using fetch(). A Laravel route works fine. There's no separate WebMCP backend. You're building a frontend bridge to business logic that's already proven in production.
7. Test it. Add the Chrome extension called Model Context Tool Inspector (Chrome Web Store), load your page and see which tools register. You can also talk to an agent from there to confirm that your tool is called and its schema reads clearly.
8. Treat it as progressive enhancement. Browser support is limited, so ordinary button clicks must keep working for visitors whose browsers lack WebMCP. It adds a path and doesn't replace the old one.
Example: an order status tool
Take an online store built on Laravel with an order status page. The normal flow has a user log in, open My Orders, choose a date range and read a list of orders with shipping status. An agent using actuation would have to find the right dropdown and submit button and then parse a results table out of raw HTML, which breaks as soon as the markup shifts.
With WebMCP a single tool wraps the endpoint that already exists:
await document.modelContext.registerTool({
name: 'get_order_status',
description: 'Look up orders within a given timeframe. Returns order number, shipping status, and current location.',
inputSchema: {
type: 'object',
properties: {
timeframe: {
type: 'string',
enum: ['today', 'yesterday', 'last_7_days', 'last_30_days', 'last_6_months'],
description: 'Timeframe for the order lookup.'
}
},
required: ['timeframe']
},
annotations: {
readOnlyHint: true,
consequentialHint: false,
untrustedContentHint: false
},
execute: async ({ timeframe }) => {
const response = await fetch(`/api/orders/status?range=${timeframe}`, {
headers: { 'Accept': 'application/json' }
});
const data = await response.json();
return JSON.stringify(data);
}
});
Three details stand out. The inputSchema spares the agent from guessing the format, because it knows which values timeframe accepts. The readOnlyHint: true annotation marks the tool as free of side effects, so no confirmation is required. And execute just calls an existing Laravel route, so nothing is rebuilt.
Checkout is more sensitive, since money moves and an order is placed. That needs a different signal:
await document.modelContext.registerTool({
name: 'checkout_cart',
description: 'Completes checkout for the currently logged-in user\'s cart.',
inputSchema: {
type: 'object',
properties: {
paymentMethod: { type: 'string', description: 'Payment method selected by the user' }
},
required: ['paymentMethod']
},
annotations: {
readOnlyHint: false,
consequentialHint: true,
untrustedContentHint: false
},
execute: async ({ paymentMethod }) => {
const response = await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payment_method: paymentMethod })
});
return await response.text();
}
});
With consequentialHint: true, the browser or agent knows to show a confirmation dialog before running. Even if the agent presses the button, the final call stays with the person.
To list the tools registered on a page:
const tools = await document.modelContext.getTools();
console.log(tools);
And to trigger one by hand for testing:
const [tool] = await document.modelContext.getTools();
const result = await document.modelContext.executeTool(tool, '{"timeframe": "last_7_days"}');
A full round trip
Here's the sequence when you chat with an agent that uses the get_order_status tool.
- You type something like "find my orders from last week" to an agent with the store's page open, in plain language.
- The agent runs discovery by calling
getTools()on the page. - The page returns its tool list with schemas, including
get_order_statuswith its description and input format. - The agent matches your request against the descriptions. A clear description helps it choose the right tool at once.
- The agent calls
executeTool()with arguments built from the conversation, such as{timeframe: 'last_7_days'}. - The page's
executefunction calls the same Laravel endpoint throughfetch(), just as if you'd clicked a button. - The backend answers with JSON, and the tool hands it back to the agent.
- The agent phrases the result in natural language and shows it, while the whole thing stays visible in the page UI.
Why is this better than actuation?
- It's lighter on context. The agent reads a compact schema, not thousands of lines of markup, so responses are faster and cheaper.
- Results stay consistent. The tool calls your actual function, so recoloring a button or moving an element doesn't break it.
- People stay in control. High-risk actions marked with
consequentialHint: truestill need a confirmation, so an agent can't check out unprompted. - It's easier to audit. Every interaction goes through an explicit tool, so you can log exactly what an agent did for a user, which is far harder when it's just clicking around.
Security
Because the tools live on your pages, security sits nearer the surface than with backend MCP, which usually runs isolated on its own server. The spec has several protections:
- Origin isolation. WebMCP runs only in origin-isolated documents. If a page enables
document.domain, for instance through theOrigin-Agent-Cluster: ?0header, WebMCP switches off. - Permissions Policy. Registering tools is gated by the
toolspolicy, which defaults toself, so cross-origin iframes can't register tools unless you allow it withallow="tools". - Origin exposure. To make a tool reachable from another origin, list that origin in the
exposedTooption. Nothing is exposed automatically. - Three annotation hints.
readOnlyHint,consequentialHintanduntrustedContentHintare more than labels. They signal whether an agent may run a tool without confirmation, or should treat its output carefully because it holds untrusted content like user reviews, which could carry a prompt injection.
One honest caveat: isolation between tabs is still maturing. If an agent works across two tabs, nothing enforces a boundary that stops sensitive context leaking from one to the other. For high-trust flows such as banking, watch this area before relying on the feature.
Where browser support stands
As of mid-2026 it's early:
- The W3C Web Machine Learning Community Group formally accepted the spec in September 2025.
- Chrome has an origin trial from version 149, and native support in Chrome and Edge is targeted for the second half of 2026.
- For local experiments, the
chrome://flags/#enable-webmcp-testingflag works without joining the trial. - The Model Context Tool Inspector extension shows which tools a page registers and can simulate an agent conversation.
The proposal can still change, so don't stake a production feature on it. Use progressive enhancement. Where the browser supports WebMCP, agents get a more precise experience, and where it doesn't, the manual flow works as before.
Current limits
- No headless browsing. The API targets local browser workflows with a person in the loop, not unsupervised automation.
- Overhead on complex interfaces. An app with intricate state management will probably need refactoring so tools reflect the real app state.
- Discovery needs a visit. Clients know a site has tools only by visiting the page. There's no global index like a sitemap for tools yet.
- No resources or prompts yet. Two other primitives from full MCP haven't reached WebMCP. If an agent must read documents or pull structured data from elsewhere, you still need a separate MCP server.
Where to start
WebMCP complements backend MCP and doesn't replace it. Backend MCP remains right for data and logic that has to live on a server, while WebMCP suits the frontend interaction layer: complex forms, multi-step navigation and actions tied to whatever UI state is on screen.
A safe way in:
- Turn on the local flag and register one simple tool, ideally read-only like a product search.
- Use
annotationsproperly from day one. Don't postponereadOnlyHintandconsequentialHint, because they're the security foundation that determines how far an agent can be trusted with your tool. - Follow the Web Machine Learning Community Group's repository on GitHub, since community discussion keeps shaping the spec.
WebMCP is far from mature, but the direction is plain. The web is getting an explicit language for talking to agents, a clear contract between developer and agent in place of DOM guessing. For anyone used to tools and schemas from backend MCP, the shift will feel familiar. The contract just lives in the browser now.