Skip to main content

What Is WebMCP and How Does It Work

Short answer

WebMCP is a proposed web standard that lets a web page describe its features as tools, each with a name, a description and a JSON Schema for its input. An AI agent in the visitor's browser can then call those tools instead of guessing which button to click. The page registers tools in JavaScript with document.modelContext.registerTool(). As of 20 October 2026 the spec is a draft from the W3C Web Machine Learning Community Group, not a W3C standard, and the only browser I found documentation for is Chrome, which offers it as an origin trial and a flag.

Tested withWebMCP draft Community Group Report, 20 October 2026Chrome for Developers WebMCP docs, fetched 20 October 2026Node.js 22.16 (example check only)Checked 20 Oct 2026

Where it stands today​

WebMCP is moving fast, and older write-ups disagree with each other. These are the facts as of today, each with its date.

ItemStatusDate and source
SpecDraft Community Group Report. It says it is not a W3C Standard and is not on the Standards Track.Dated 20 October 2026 in the draft spec
Chrome early previewAnnounced for prototyping through the early preview program.10 February 2026, Chrome blog
Chrome origin trialAvailable from Chrome 149.Chrome docs, last updated 7 October 2026, WebMCP overview
Local testingSet the flag chrome://flags/#enable-webmcp-testing to Enabled, then relaunch Chrome.Chrome docs, same page
Where the API livesdocument.modelContext. The older navigator.modelContext was removed.Chromium commit 4a9fee9 dated 9 July 2026. The Angular issue 68947 says it was deprecated in Chrome 150.
Declarative APIDocumented by Chrome. It is not in the draft spec text.Chrome docs, Declarative API, last updated 25 September 2026
Older examples use the wrong name

The proposal page on the spec site still shows window.navigator.modelContext.provideContext() and unregisterTool(). That is the 2025 design. Current Chrome and the 20 October 2026 draft use document.modelContext, registerTool(), getTools() and executeTool(), and there's no unregisterTool(). Don't copy code from the proposal page.

How it works​

Today an agent that wants to book a flight on your site usually looks at the page's HTML or a screenshot, works out which field is the departure date, and clicks through. Each step is a guess. WebMCP lets your page declare the action once, with a name, a description and the inputs it expects. The agent calls the tool directly, and the page's own code runs it.

The spec describes a page with WebMCP as something like an MCP server that runs its tools in client-side script instead of on a backend. The tools run in the visitor's browser, in the page's own context. So they can use the page's state and the visitor's signed-in session, which is why the security guide matters before you ship anything. The spec also doesn't fix how a browser agent presents the tools to the model. The browser might turn them into MCP messages, function calls or something else.

What a tool contains​

Each tool is a plain object you pass to registerTool():

  • name: 1 to 128 ASCII letters, digits, _, - or .. Registering a name that's already taken fails.
  • description: what the tool does and when to use it. An empty string is rejected. The agent reads this text to choose a tool, so it matters as much as the code.
  • inputSchema: a JSON Schema object that describes the input. The spec requires that it can be serialized to JSON.
  • execute: an async function that receives the input and returns a JSON-serializable value. It gets an AbortSignal as its second argument.
  • annotations (optional): readOnlyHint, untrustedContentHint, consequentialHint and debugging. They're hints that help the agent and the browser decide how to treat a tool. They aren't a security control.

The Chrome docs say a page doesn't need to call getTools() or executeTool() to expose its tools. Those two methods are for JavaScript agents that run inside the page, such as an embedded chat widget, and for test harnesses.

Worked example: a to-do page with two tools​

This module registers an add_todo tool and a list_todos tool. The page passes in its own todos array and a render function, so an agent's change shows up on screen straight away. The example is in docs/guides-examples/what-is-webmcp/page/tools.js.

tools.js
// Registers two to-do tools on the current page. `modelContext` is
// `document.modelContext`, `todos` is the array the page renders, and
// `onChange` redraws the page after the agent changes it.
export async function registerTodoTools(modelContext, todos, onChange) {
const controller = new AbortController();

await modelContext.registerTool(
{
name: 'add_todo',
description: 'Add an item to the to-do list on this page.',
inputSchema: {
type: 'object',
properties: {
text: { type: 'string', description: 'What the to-do item says' },
},
required: ['text'],
},
annotations: { readOnlyHint: false, consequentialHint: false },
execute: async ({ text }) => {
const item = typeof text === 'string' ? text.trim() : '';
if (item === '') {
throw new Error('text must be a non-empty string');
}
todos.push(item);
onChange();
return `Added to-do: ${item}`;
},
},
{ signal: controller.signal },
);

await modelContext.registerTool(
{
name: 'list_todos',
description: 'Return every to-do item currently on this page.',
inputSchema: { type: 'object', properties: {} },
annotations: { readOnlyHint: true, untrustedContentHint: true },
execute: async () => [...todos],
},
{ signal: controller.signal },
);

return controller;
}

Three details in this code follow the spec:

  • The AbortController signal is how a tool is removed. The spec has no unregisterTool(). Call controller.abort() and both tools are unregistered.
  • add_todo throws an Error for empty input. A thrown error from execute becomes a rejected tool call, so the agent sees that the call didn't work.
  • list_todos is marked untrustedContentHint: true because it returns text that visitors typed, which another party could have written.

The page calls it only when the API exists. The Chrome docs use the same check:

if ('modelContext' in document) {
await registerTodoTools(document.modelContext, todos, render);
}

You can run the module's checks with bash docs/guides-examples/what-is-webmcp/test.sh. Those checks use a stub that follows the spec's rules, so they don't prove the page works in Chrome.

Two ways to register tools​

WebMCP has two APIs, and a page can use both:

APIUse it forExample
Imperative (registerTool())Anything that needs JavaScript: state, API calls, multi-step actionsThe to-do example above
Declarative (HTML attributes)A standard HTML form that the agent fills in and submitsA <form> with toolname and tooldescription attributes

With the declarative API, you add toolname and tooldescription to a <form>, and toolparamdescription to each field. The browser builds the tool's schema from the form. The form stays visible, so the user sees what the agent filled in. The Chrome docs say the form is submitted only when the user clicks Submit, unless you add toolautosubmit. The draft spec doesn't cover this API, so treat its details as Chrome-only for now.

Who can call a tool​

A tool registered in a page is visible to that page's own document and to same-origin documents in the same frame tree. Other origins get nothing by default.

Cross-origin iframes need two things. The parent must allow the iframe with allow="tools", because the tools Permissions Policy defaults to self. And the tool must list the other origin in its exposedTo option. A caller in another origin must also list the origin in fromOrigins when it calls getTools().

Common misconceptions​

"WebMCP is MCP in the browser." The two share the idea of tools with names, descriptions and schemas, but they are different things. MCP is a protocol between an AI app and a server. WebMCP is a browser API that a page uses. A site can offer both, which is covered in WebMCP vs MCP.

"It's a web standard, so every browser supports it." The spec is a draft that isn't on the W3C Standards Track. The only browser documentation I found is Chrome's, behind an origin trial and a flag.

"Tools make the page safer for agents." They make actions more predictable, but a tool runs with the visitor's session and whatever the page exposes. Annotations are hints. Read WebMCP security before you publish a tool that changes data or spends money.

Recent changes to watch​

  • Chrome 149: origin trial begins, with the API first shown as navigator.modelContext.
  • Chrome 150: navigator.modelContext is deprecated in favor of document.modelContext.
  • Chrome 153: unregistering a tool no longer cancels an execution that's already running. Tools that start long work still need to check their own signal.
  • Chrome 155: passing input as a JSON string to executeTool() is deprecated.
  • Chrome 156: the debugging annotation is available, and the window.ontoolactivated and window.ontoolcancel handlers are no longer supported.

These version numbers come from the Chrome docs and the Chromium commit. Check the Chrome docs before you rely on a version.

FAQ​

Is WebMCP a W3C standard?

Not yet. As of 20 October 2026 it is a Draft Community Group Report from the W3C Web Machine Learning Community Group. It is not a W3C Standard and is not on the Standards Track.

Which browsers support WebMCP?

The only browser documentation I found is Chrome's. Chrome offers it as an origin trial starting from Chrome 149, and you can turn it on for local testing with the chrome://flags/#enable-webmcp-testing flag.

Is WebMCP the same as navigator.modelContext?

No. The API was first shown as navigator.modelContext. It now lives at document.modelContext, and the older name has been removed from current Chromium builds.

Does WebMCP replace my website UI?

No. Tools run on the same page, and the visitor can see what the agent does. WebMCP is an extra way for agents to act, and the page keeps its normal interface.

Do I need a server to use WebMCP?

Not for the tools themselves. The page registers them in its own JavaScript, and they run in the visitor's browser. Your site still needs to be served over HTTPS for the API to be available.