WebMCP
AI no longer needs to guess, or to go through long processing, to understand what's happening inside a web page. It now has a unified interface through WebMCP that reads the context precisely.
What is WebMCP, and why?
When you ask an AI AGENT or a CLAUDE EXTENSION to carry out a certain task on a page — like filling in a data form or getting data... etc — it relies on taking screenshots or scraping the DOM data, then analysing and processing it, and you may lose all of that with any update to the page! That wastes a lot of time and increases TOKENS consumption, because these tools work by reading the entire page.
With WebMCP available, there's now a direct and explicit communication channel between the AI model and the page: the developer adds their page's tools in document.modelContext, for the Agent to read them directly instead of guessing.
Comparing Server MCP and WebMCP
Unlike traditional MCP, which mainly works inside the Server (Backend) to carry out tasks (Function Calls) when the Agent requests them, its reach stays confined to the server environment. It has no direct access to the current web page the user is browsing.
The comparison does not at all mean that one is better than the other, or that one will replace the other. It's a comparison to clarify the Separation of Concerns.
The ideal, and only, option for complex tasks that need high processing power, access to huge Databases, dealing with File Systems, or running heavy background operations that the Client shouldn't see or carry the load of processing locally.
Designed to specialise in the browser context, it excels at direct tasks that interact with the current interface, like reading the DOM, interacting with inputs (Forms), accessing LocalStorage, and making use of the Active Session.
WebMCP features
- A unified JavaScript standard: works directly inside the browser.
- Automatic Auth: tools work inside the user's session, so there's no need for API Keys or Auth Headers.
- Control over sharing between sites: when registering, you set which sites are allowed to call your tools.
So why do we still need buttons?
Looking at the future, this might cross your mind: if we can now fully control the page through a protocol like WebMCP, and have the Agent run any JS code easily, why don't we change the UI to be simpler by hiding all the details from the page and showing just one piece of content, one screen / one element... and the only control is a text or voice command to the Agent: show this, search for that... etc.
But many disagree with this vision, for the following reasons:
- 1. If the Agent is missing for any reason, we'll lose control of the page, or it'll be hard to control.
- 2. Having the elements, and their order, helps Screen Readers and serves people of determination.
- 3. Humans learn and explore by seeing the page and its details, so when faced with a blank, silent screen, it'll be hard to discover the features the page offers.
- 4. Sometimes instant interaction with the mouse or the keyboard is way faster than writing a whole text, for some things.
- 5. WebMCP will face a big challenge from organisations and browser companies if it's adopted as a replacement for the traditional UI, because the whole basis of using the browser is the Open Web experience and freedom of movement.
Accessibility and WebMCP
There's a critique, Issue #91, that asks a fundamental question: "Why create a new, separate system for AI when the Accessibility Tree already provides programmatic maps of the page? And why don't we develop the Accessibility Tree instead of inventing WebMCP?"
Summary of the critique
- First: we already have a tree the Browser builds automatically, complete and consistent with the DOM, so we can make use of this feature and connect the Agent to it, instead of building WebMCP with different methods, tools and code — which will become a problem if the page gets updated without updating these tools, unlike the Accessibility Tree, which syncs automatically.
- Second: if we rely on developing the Agent to interact with the Accessibility Tree, people will care about writing ARIA tags, and this will serve two sides at the same time: first, people of determination, and second, the use of the AI Agent. Instead, now we have another way to describe the page, which is WebMCP, working in parallel, with the possibility that one of them falls out of use in the future.
- Third: describing the page's elements and turning them into structured data like this (JSON Schema), writing their inputs and setting their types — that's pure server work, not the UI's job or responsibility.
Answering the critique
To answer the direct question in the critique: yes, there are use cases that neither the Accessibility Tree nor the Backend APIs can handle effectively:
-
First: why not rely on the Accessibility Tree
- Limits of what it sees: because it only expresses the UI (button, div), and it's limited to the values of the element itself (an input value, for example). It doesn't deal with things like a canvas, browser storage, or state inside the code itself (Redux/React).
- How it gets done: yeah, the Agent can do a certain action through the Accessibility Tree, for example it'll recognise the payment button and click it. But the execution will be in steps: click, wait for the page to come back, look for the next button — and any change in the page makes the sequence even harder. Unlike WebMCP, which calls a ready function like
checkoutCart()that runs directly. - The cost with big data: in an app like Google Sheets or Figma, for the Agent to reach 500 cells in the table, it'll read 500 DOM elements one by one — slow, and heavy on resources. Unlike WebMCP, which gives a tool like
queryGridData(filter)that returns the data structured, straight from the table's memory, without touching the DOM.
-
Second: why not rely on the Backend
- The data isn't on the server in the first place: the data in the page lives in the current session and was never sent to the server, so any API call will work on the server's saved copy, which doesn't have the local edits.
- And even if you want to get it there: you'll need a constant sync with every new value added in the front: read the live values, serialize, send, and the Agent waits for the response — all that for something the page's own function does in one call.
Best practices
A. Security and privacy
-
Self-XSS
Through a simple script in the console, the function responsible for the tool can be run many times in a row, causing a high cost, or on the other side a big load on the server in a short time (going over the Rate Limit).
One of the existing solutions for this kind is using throttle or debounce to control how many times the tool runs in one second... etc.
But the Backend stays the most important line of defence against this behaviour, by blocking any requests that go over the allowed limit and sending
429 Too Many Requests. -
Session Cleanup
In (SPA) apps the page isn't reloaded on log out, so the registered tools stay active unless they're cancelled.
A possible scenario: when someone logs out of your site without unregistering their tools, these tools may stay available to whoever uses the browser after them, which could leak information or show them tools that aren't right for them.
So take care of the clean up after every session, and unregister the tools using
controller.abort().
B. Number of tools
Avoid creating lots of tools without need. Yes, there's no specific limit on the number of tools you can use, but every registered tool (its name, its description and its Schema) consumes the model's Tokens, which increases the response time (Latency) and the cost.
C. Leave the order to the Agent
D. Text instead of numbers
Use clear, meaningful text values instead of codes or vague numbers:
shippingId: 1shippingMethod: "express"E. Leave the calculations to JavaScript
Don't force the Agent to do calculations or convert Time Zones.
For example: if the function needs a date in a certain format, don't ask the Agent to convert the format. Accept the date as it was sent, then convert it yourself with simple JavaScript code before using it. And if the format isn't understood, return a clear message explaining the accepted formats.
F. Let the Agent fix itself
When a tool fails or goes over the usage limits (Rate Limit), don't return a vague error like just Error; return a message that explains the problem, so the Agent can correct its inputs or show it to the user.
async execute({ date }) {
const res = await fetch("/api/flights?date=" + date);
if (res.status === 429) {
// ❌ return "Error 429";
return "Too many searches. Wait a minute, or use the search form on the page.";
}
return JSON.stringify(await res.json());
}
The code and usage
1. Checking availability
if (document.modelContext) {
console.log('WebMCP is supported');
} else {
console.log('WebMCP is not supported in this browser');
}
2. Using registerTool
await document.modelContext.registerTool({
name: "add-todo",
description: "Add a new item to the todo list",
inputSchema: {
type: "object",
properties: { text: { type: "string" } }
},
execute({ text }) {
addTodo(text); // calling a function that already exists
return "Added: " + text; // sent to the Agent
}
});
3. Annotations
Annotations are added when registering the tool, inside registerTool, and they're hints that help the Agent deal with the tools more accurately.
annotations: {
readOnlyHint: true, // only reads, changes nothing
consequentialHint: false, // real-world or irreversible, e.g. a payment
untrustedContentHint: false // output may contain untrusted content
}
4. Sharing tools with other sites
To make the tool available to another origin, add exposedTo after defining the tool.
{ exposedTo: ["https://trusted-partner.example"] }
And to enable WebMCP inside an iframe from another origin, use allow="tools".
<iframe src="https://widget.example" allow="tools"></iframe>
5. Unregistering the tool
Pass a signal when registering, then use abort() to unregister the tool.
const controller = new AbortController();
await document.modelContext.registerTool(tool, { signal: controller.signal });
controller.abort();
6. The Declarative way: turning a form into a tool
Without JavaScript: you add attributes on an existing <form>.
<form toolname="sign-up" tooldescription="Create a new account"> <input name="firstName" toolparamdescription="The user's first name"> <input name="lastName" toolparamdescription="The user's last name"> <input type="email" name="email" toolparamdescription="The user's email address"> <button>Sign up</button> </form>
7. Events
You can tell if the submit event was done by the Agent using event.agentInvoked, and use respondWith() to return a result or reply to it.
form.addEventListener('submit', (e) => {
if (!e.agentInvoked) return; // a normal submit by the user
e.respondWith(searchCars(new FormData(form)));
});
Use toolchange to know when a tool gets registered or cancelled.
document.modelContext.addEventListener("toolchange", async () => {
const currentTools = await document.modelContext.getTools();
updateAgentToolRegistry(currentTools);
});
Use toolactivated to know when the Agent fills in the form, before it's sent.
document.modelContext.addEventListener("toolactivated", () => {
form.scrollIntoView();
});
Use toolcanceled to know when the Agent cancels the call.
document.modelContext.addEventListener("toolcanceled", () => {
form.reset();
});
Styling with CSS
And for styling while the Agent is working: :tool-form-active for the form, and :tool-submit-active for the submit button in it.
form:tool-form-active { outline: 2px solid orange; }
button:tool-submit-active { opacity: 0.6; }
Sources: WebMCP explainer · Declarative API
Getting ready for (Production)
From the User's side
-
Browser availability: Chrome 149 and Edge 150 or newer, and Brave, and also the ChatGPT Desktop app.
As for Firefox and Safari, they don't support it right now. -
Enabling the WebMCP flag: write
chrome://flags/#enable-webmcp-testingin the URL and enable it.
Note: if the site is registered in the Origin Trial, the tools will work without any flags. -
An Agent that calls the tools: WebMCP only shows the tools, and it needs an Agent inside the browser to use them.
The easiest way to try it right now is the Model Context Tool Inspector extension, which is a side panel that shows the tools, and a chat to write a certain prompt in.
And there are other extensions, like WebMCP Inspector. -
From other AI tools: you can use Chrome DevTools for Agents with Claude Code or Gemini CLI or Cursor or Codex.
Note: the ChatGPT Desktop app supports WebMCP directly.
From the Developer's side
The Origin Trial lets your site's visitors use WebMCP without enabling any flags.
-
1. Register your site's origin (like
https://example.com) on the Origin Trial page for Chrome and Edge.
Every registration will give you a token. - 2. Add the token in the
<head>of every page that has tools:
<meta http-equiv="origin-trial" content="YOUR_TOKEN">
References
The official repository of the WebMCP protocol on GitHub:
https://github.com/webmachinelearning/webmcp
WebMCP documentation from Chrome for Developers: