WebMCP Explained: How Browser AI Agents Use Website Tools (With registerTool Examples)
What WebMCP is, how document.modelContext.registerTool works, which browsers support it in 2026, and how to design safe, useful tools for browser AI agents.

AI agents in the browser mostly work the way a person does: they read the screen, find a button and click it. That is slow, and it breaks whenever a layout changes. WebMCP gives a website a better option. The page describes what it can do as tools, each with a name, a plain-language description, a JSON schema for its input and a JavaScript function, and the browser hands those tools to its built-in agent. The agent calls the function; the page does the work with the code it already has.
WebMCP in 30 seconds
- What: a JavaScript API,
document.modelContext, for registering tools that a browser's agent can call, plus a proposed declarative form for HTML forms. - Who: the W3C Web Machine Learning Community Group, with editors from Microsoft and Google. It is a Draft Community Group Report, not yet a W3C Standard.
- Where: Chrome (origin trial from Chrome 149, or the
chrome://flags/#enable-webmcp-testingflag), Edge (origin trial from Edge 150), ChatGPT desktop, and Brave's Leo (experimental). Firefox and Safari have open standards-position requests. - Why it matters: tools run in the page with the user's existing session, so the agent gets structured, permissioned access without screen scraping or separate credentials.
How WebMCP works
- The page registers tools. Usually once at load, or when the page reaches a state where a tool makes sense (for example, after sign-in).
- The browser offers them to its agent. The agent sees each tool's name, description and input schema, the same building blocks as MCP tools.
- The agent calls a tool. The browser runs the tool's
executefunction in the page, with the page's cookies, state and code. - The result goes back to the agent, usually as text or JSON, and the page can update what the user sees.
Agents and inspection tools can list a page's tools with getTools(), run one with executeTool(), and listen for a
toolchange event when the set changes.
Registering a tool: a complete example
Feature-detect first. The current draft exposes the API on document; earlier drafts, and polyfills written against them, used navigator.modelContext.
const modelContext = document.modelContext ?? navigator.modelContext;
if (modelContext) {
const controller = new AbortController();
await modelContext.registerTool({
name: "search_products",
title: "Search products",
description: "Search the catalog by keyword and return matching products with price and stock.",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "Words to search for, e.g. 'trail running shoes'." },
max_results: { type: "integer", minimum: 1, maximum: 20, default: 5 }
},
required: ["query"]
},
annotations: { readOnlyHint: true },
async execute({ query, max_results = 5 }, { signal }) {
const url = "/api/search?q=" + encodeURIComponent(query) + "&limit=" + max_results;
const response = await fetch(url, { signal });
if (!response.ok) {
return "Search failed with HTTP " + response.status + ". Try a shorter query.";
}
return JSON.stringify(await response.json());
}
}, { signal: controller.signal });
// When the tool no longer applies (for example, on sign-out):
// controller.abort();
}
A few details worth knowing:
- Unregistering is an
AbortSignal. Pass{ signal }as the second argument and abort it to remove the tool. One signal can remove a whole set. executereceives the arguments and an options object with asignalthat fires if the agent cancels the call.- Return something the model can read. Plain text or a JSON string works well. Return errors as explanations the agent can act on, not as silent failures.
- Cross-origin frames are off by default. Tool access is governed by the
toolspermissions policy, which defaults to the page's own origin; an iframe needsallow="tools", andexposedToshares a tool with specific trusted origins.
Annotations: telling the agent what a tool does
| Annotation | Set it when | Effect |
|---|---|---|
readOnlyHint | The tool changes nothing | Helps the agent decide it can call the tool without asking first |
consequentialHint | The action is high-stakes or hard to undo: bookings, payments, sending messages | The browser or agent can ask the user to confirm first |
untrustedContentHint | The result contains text you did not write: reviews, comments, social posts, emails | Labels that text as untrusted so the agent treats it as data, not instructions |
debugging | The tool exists for development | Marks it as a debugging tool |
The declarative API: tools from HTML forms
Not every feature is a JavaScript function. A proposed declarative API turns an ordinary <form> into a tool with a few
attributes, and the browser derives the input schema from the form's fields:
<form toolname="search_flights" tooldescription="Search flights between two airports on one date.">
<input name="from" required toolparamdescription="Departure airport code, e.g. LHR">
<input name="to" required toolparamdescription="Arrival airport code, e.g. JFK">
<input name="date" type="date" required>
<button type="submit">Search</button>
</form>
Without the toolautosubmit attribute, the agent fills the form and the user checks it and presses submit. A submit
handler can tell an agent submission apart through SubmitEvent.agentInvoked and answer the agent with
respondWith(). This part is still an explainer: Chromium implements a loose version for testing, and the exact rules
are not yet in the specification. One practical caution: if your form is a framework-controlled component (React state, for
example), check that agent-filled values reach your state before relying on it.
Designing tools agents use well
Chrome's WebMCP guidance and our own experience running the same tools over MCP agree on most of this:
- One job per tool, with no overlap between tools. Two tools that could both answer a request make the agent guess.
- Name with precise verbs.
create_eventcreates immediately;start_event_creationopens a form. The name should say which. - Describe what the tool does and when to use it, in positive terms. The description is a prompt; keep it factual, because models repeat it.
- Accept raw input. Take "11:00 to 15:00" as a string rather than asking the model to compute minutes. Use enums with self-explanatory values.
- Validate strictly in code, loosely in the schema. Schema constraints are hints; enforce rules in
execute. - Return errors the model can fix, such as "trend_id must be an integer" or "wait a minute, rate limited", and keep results small.
- Register tools only where they work, and remove them when the page state no longer supports them.
- Update the page when a tool finishes, so the user can see what the agent did.
Security: the session is the power
A WebMCP tool runs with everything the page can do, including the user's signed-in session. Treat each tool as an API endpoint that an LLM, which can be manipulated by text it reads, will call:
- Prefer read-only tools; mark anything that spends money, sends messages or deletes data with
consequentialHintand confirm it in your UI. - Mark third-party text with
untrustedContentHint. Indirect prompt injection through reviews, comments and posts is the main risk. - Never put secrets in page code. If a tool needs a third-party API key, call your own server and keep the key there.
- Expose tools to other origins only with
exposedTo, and only to origins you would share that data with. - Keep server-side authorization as it is. The agent is the user, so the user's permissions are the ceiling.
How to test a WebMCP site
- Turn on
chrome://flags/#enable-webmcp-testingand relaunch Chrome. - Install the Model Context Tool Inspector extension to list a page's tools and call them by hand, then try them with a real agent.
- Write evaluations, not just unit tests: a set of user requests with the tool calls and answers you expect.
- For production visitors on Chrome and Edge, register your origin for the WebMCP origin trial and serve its token.
A real example
TrendsAGI registers its trend-intelligence tools with WebMCP: signed-in users' agents can list rising topics, check a trend's trajectory, read its audience insight and pull recommendations, all read-only and with the user's own session. Read how we built it, see the setup page, or compare the approach with a server in WebMCP vs MCP.
Sources
- WebMCP specification draft (W3C Web Machine Learning Community Group)
- WebMCP browser and agent implementation status
- WebMCP declarative API explainer
- Chrome for Developers: WebMCP
- Chrome for Developers: WebMCP best practices
- Chrome for Developers: WebMCP tool security
- Chrome for Developers: join the WebMCP origin trial