What Is WebMCP and Why Your Website Needs It
The way AI agents interact with websites is changing. Until recently an agent that wanted to book a flight or search a catalog on your site had to read the accessibility tree or a screenshot, guess which button did what, click, wait and repeat. WebMCP, a W3C proposal co-edited by engineers from Google and Microsoft, gives websites a standard way to expose their functionality as structured tools that an agent can call directly, in the user's own browser session.
In February this was a Chrome flag and a draft. Since August it is something an agent will use: OpenAI's ChatGPT desktop browser and Codex call WebMCP tools on pages that offer them, Shopify switched tools on for every Liquid storefront, and Chrome and Edge run origin trials. WebKit has formally opposed the proposal and Mozilla is neutral, so this is not a done deal either.
What WebMCP is
WebMCP (Web Model Context Protocol) is a browser API, incubated in the W3C Web Machine Learning Community Group as a Draft Community Group Report. It lets a page register tools: named functions with a description, a JSON Schema for their input, and an
execute
callback. An agent running in or alongside the browser reads those definitions and calls the tools instead of driving the page through its UI. The proposal came from Microsoft's Edge team in August 2025, and Google's Chrome team co-edits it.
The name invites a misreading, so a clarification from one of its authors, Patrick Brosset: the browser does not become an MCP server. WebMCP covers the primitives layer, the tool definitions, and leaves the protocol plumbing to the browser and the agent. In other words, you write JavaScript functions and describe them; you never speak MCP yourself.
Why WebMCP matters
A typical browser-use session today looks like this: the agent takes a snapshot of the page, asks a model which element to click, clicks it, waits for the page to settle, and repeats, often dozens of times for a single task. Each round trip costs tokens and can fail on a moved button or a late-loading modal. From your server's point of view the traffic is indistinguishable from a scraper.
With WebMCP the same task is one call. A shop that registers a
search_products
tool receives a structured request and returns structured results, and the agent never touches the filter dropdowns. You decide which functions exist and what they accept, and everything runs in the visitor's own session with the same cookies and the same authorization your buttons already use.
ONE STRUCTURED CALL
A tool call replaces a loop of snapshots, clicks and waits, and returns data the agent can use directly.
YOU DEFINE THE SURFACE
Only the functions you register exist for the agent. Nothing else on the page becomes a tool by accident.
SAME SESSION, SAME CHECKS
Tools run in the user's tab with the user's login, so your existing authentication and validation apply.
As Christian Heilmann put it when the Chrome preview landed: "agents have become first-class citizens of the world wide web." Instead of fighting the web's infrastructure, agents can work with it, and the site owner keeps control over what is exposed.
Two APIs: declarative and imperative
WebMCP offers two ways to expose tools. The declarative API annotates HTML forms; the imperative API registers tools from JavaScript. You can use one or both.
The declarative API: attributes on forms
The declarative approach is the fastest way in. You add a few attributes to an existing form and the browser turns it into a tool definition that agents can discover and fill in. No JavaScript required.
<form
id="search-flights"
toolname="searchFlights"
tooldescription="Search for available flights by origin, destination, and date"
toolautosubmit="true"
>
<label for="origin">From</label>
<input
type="text"
id="origin"
name="origin"
required
toolparamdescription="Departure airport code (e.g. AMS, JFK, LHR)"
/>
<label for="destination">To</label>
<input
type="text"
id="destination"
name="destination"
required
toolparamdescription="Arrival airport code (e.g. CDG, SFO, NRT)"
/>
<label for="date">Date</label>
<input
type="date"
id="date"
name="date"
required
toolparamdescription="Departure date in YYYY-MM-DD format"
/>
<button type="submit">Search Flights</button>
</form>
The attributes, as described in the declarative API explainer:
-
toolname: the identifier of the tool (for examplesearchFlights) -
tooldescription: a plain-language explanation of what the tool does, which the agent uses to decide when to call it -
toolparamdescription: a description per input, so the agent knows what value to supply -
toolautosubmit: optional, lets the agent submit the form after filling it in
The imperative API: registering tools from JavaScript
For anything beyond a form submission, the imperative API registers tools on document.modelContext. Each tool has a name, a description, an input schema, optional annotations and an
execute
callback. The getter moved from
navigator
to
document
in May 2026, because tools are scoped to a document and a window can outlive one; Chrome 150 deprecates the old location but keeps it as an alias, and OpenAI's browser exposes the new one.
if (typeof document.modelContext?.registerTool === "function") {
const controller = new AbortController();
await document.modelContext.registerTool(
{
name: "search_products",
description: "Search the product catalog by keyword, category and maximum price",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "Search keywords" },
category: {
type: "string",
description: "Product category filter",
enum: ["electronics", "clothing", "home", "sports"],
},
maxPrice: { type: "number", description: "Maximum price in EUR" },
},
required: ["query"],
additionalProperties: false,
},
annotations: { readOnlyHint: true },
execute: async ({ query, category, maxPrice }) => {
const params = new URLSearchParams({ q: query });
if (category) params.set("category", category);
if (maxPrice) params.set("max_price", String(maxPrice));
const res = await fetch(`/api/products?${params}`);
return { results: await res.json() };
},
},
{ signal: controller.signal }
);
// Later, for example when the component unmounts:
// controller.abort(); // unregisters the tool
}
Three details in that snippet matter. The feature check is mandatory, because outside the origin trials, the Chrome flag, Brave's experiment and the ChatGPT browser
document.modelContext
is undefined. Unregistering is done through an
AbortSignal
passed in the options, which is the only removal mechanism in the current spec. And registering a second tool with the same name rejects with an InvalidStateError, so keep names unique.
The same interface also exposes getTools(), which lists the tools registered on the page, and executeTool(), which runs one. Those are what an agent, an extension or a test harness uses to inspect and call your tools. The options object accepts an
exposedTo
list of origins, which controls which documents in the frame tree can see a tool.
Which API should you use?
| Aspect | Declarative API | Imperative API |
|---|---|---|
| Implementation | HTML attributes on forms | JavaScript registration |
| Best for | Search, contact, login, booking forms | Complex logic, multi-step workflows, API calls |
| JavaScript needed | No | Yes |
| Dynamic behaviour | Limited to form submission | Full async logic, API calls, state updates |
| Response format |
Form submit, optionally
respondWith()
|
Whatever execute
returns
|
| Effort | Minutes per form | Hours per tool |
In practice you will use both: declarative for the forms you already have, imperative for functionality that has no form.
Consent, confirmation and what the browser enforces
The spec is thin on user consent. What it does specify: the API is only available in secure contexts (HTTPS), access is gated behind a permissions-policy feature called
tools
with a default allowlist of 'self', tools can be scoped to origins with exposedTo, and each tool can carry a
readOnlyHint
annotation that tells the agent it changes nothing. A built-in confirmation dialog, or an API for a tool to ask the user a question mid-execution, does not exist.
Confirmation lives with the agent. OpenAI's implementation gives every tool invocation a safety review, applies its normal confirmation rules to consequential actions such as purchases, messages, deletions and permission changes, and shows users a "Site tools" panel with every tool definition and a log of what was called. Its documentation also states that "website-provided tool definitions and results are untrusted content", which is the right posture. The mirror image applies on your side: an agent call is a request from a browser you do not control, so it gets the same validation and authorization as a form post.
Discovery: what exists and what does not
Tools registered with either API are discoverable once an agent has the page open in a browser that supports WebMCP; that is what
getTools()
is for. This is the only discovery mechanism the spec defines.
Site-level discovery, a way for an agent to learn what your site offers before it opens a page, is an open discussion in the community group with no proposal in the spec. No browser or agent documents reading a manifest, and the Shopify and OpenAI deployments publish none. Our scanner used to award points for a file at /.well-known/webmcp.json; as of 27 August it no longer does, because there is nothing for such a file to conform to and nobody reads it. ChatGPT does not act on it. The consequence, which I cover in the
August post
, is that from outside a capable browser your tools are invisible.
Where WebMCP runs today
WebMCP is a Draft Community Group Report, not on the W3C standards track. Where things stand on 27 August 2026:
| Where | Status | Notes |
|---|---|---|
| Chrome | Origin trial from Chrome 149 |
Local testing via chrome://flags/#enable-webmcp-testing; Gemini in Chrome announced at I/O as a consumer, no date yet
|
| Edge | Origin trial, Edge 150 | Microsoft co-edits the spec |
| Brave | Experimental | Support in Leo AI chat |
| ChatGPT desktop app | Live since 25 August 2026 | Built-in browser, for ChatGPT Work and Codex, GPT-5.6 Sol and Terra |
| Firefox | Position: neutral | Mozilla's interest is in the declarative variant; no implementation |
| Safari | Position: oppose | WebKit cites privacy, security, API design and venue concerns; no implementation |
Two platforms did more for adoption than any browser. On 5 August Shopify switched WebMCP on for every Liquid storefront, ten tools from
search_catalog
to proceed_to_checkout, with nothing for merchants to install. On 6 August Cloudflare opened a developer preview that injects a bridge script at the edge and registers tools on
document.modelContext
for sites that flip a toggle. Google's own list of companies experimenting with WebMCP, from I/O 2026, includes Expedia, Booking.com, Shopify, Credit Karma, TurboTax, Redfin, Etsy, Instacart and Target.
What is still open
In February I wrote a timeline that ran through the browsers. That was the wrong frame. Adoption is being decided by platforms and agent vendors, and the browsers are following. What remains genuinely open:
- Standards track. The spec is still a Community Group report, and WebKit's opposition makes a move to the standards track harder.
- Safari. As long as WebKit opposes, Safari users have no WebMCP path. Expect agent vendors to keep their DOM-driven fallbacks for years.
-
API churn.
The getter moved once already;
getTools()andexecuteTool()were added in July and August. Feature-detect everything and keep the fallback shim. - Discovery. Until the spec has a site-level answer, agents only learn about your tools by visiting, which keeps search visibility in charge of who gets visited.
How to implement WebMCP today
You do not have to wait for broad browser support. The declarative API costs a few attributes, the imperative API a small module, and both are inert in browsers that lack the API. Step by step:
Step 1: annotate your existing forms
Take your most important forms (search, contact, booking, login) and add the attributes. Minutes per form:
<form
action="/search"
method="get"
toolname="searchProducts"
tooldescription="Search products by keyword. Returns matching products with prices and availability."
>
<label for="q">Search</label>
<input
type="search"
id="q"
name="q"
required
toolparamdescription="Search keywords, for example: wireless headphones"
/>
<button type="submit">Search</button>
</form>
Step 2: register imperative tools
For functionality without a form, such as checking stock, comparing products or calculating shipping, register tools from a module:
const mc = document.modelContext ?? navigator.modelContext; // shim while Chrome 150 keeps the alias
if (typeof mc?.registerTool === "function") {
await mc.registerTool({
name: "check_availability",
description: "Check whether a product is in stock at a store near a postal code",
inputSchema: {
type: "object",
properties: {
productId: { type: "string", description: "Product SKU or ID" },
postalCode: { type: "string", description: "Postal code for the store lookup" },
},
required: ["productId"],
additionalProperties: false,
},
annotations: { readOnlyHint: true },
execute: async ({ productId, postalCode }) => {
const res = await fetch(`/api/availability/${encodeURIComponent(productId)}?postal=${encodeURIComponent(postalCode ?? "")}`);
if (!res.ok) {
return { error: "Unknown product ID. Use the SKU shown on the product page." };
}
return await res.json();
},
});
}
Step 3: handle agent submissions differently
When an agent submits a form you probably want to return structured data instead of a redirect, and log the interaction separately. The declarative explainer's
SubmitEvent.agentInvoked
and
respondWith()
are for that:
document.getElementById("search-form").addEventListener("submit", (event) => {
if (!event.agentInvoked) {
return; // people get the normal navigation
}
event.preventDefault();
const formData = new FormData(event.target);
const results = performSearch(formData.get("q"));
event.respondWith({ results, total: results.length });
});
Step 4: test in a real agent
- Open the page in the ChatGPT desktop app (ChatGPT Work or Codex) and check the "Site tools" entry in the address bar; it lists every tool definition the page registered
-
In Chrome, enable
chrome://flags/#enable-webmcp-testingand install the Model Context Tool Inspector extension to list and call tools by hand - For production traffic, register for the Chrome origin trial (from Chrome 149) or the Edge one (Edge 150)
- Call every tool with wrong and missing inputs and check that the error messages help an agent recover
What implementing WebMCP gets you
An agent that finishes the task on your site instead of abandoning it halfway, on the agents that support WebMCP, which today means ChatGPT's desktop browser, Brave's experiment and whatever consumes the Chrome and Edge trials. I have not seen published conversion numbers, and I would distrust any that appear this early.
TASKS THAT COMPLETE
Search, availability and cart actions become one call each, with nothing to mis-click along the way.
AGENTS READ YOUR WORDS
The tool descriptions you write are what the agent believes your site can do. On Shopify, Shopify wrote them; everywhere else you do.
FEWER GUESSES ON YOUR PAGE
Agents that use tools stop brute-forcing forms, which is better for your logs and your rate limits.
A HEAD START ON THE FALLBACK
Sites without tools are still driven through the UI. Being callable is the difference between a task done and a task guessed.
Mobile-responsive sites won the mobile era. I expect agent-callable sites to do the same in the agent era, and the shops that got WebMCP from Shopify this month without lifting a finger are the first test of that claim.
Who should implement WebMCP?
- E-commerce: catalog search, product details, cart and checkout. On a stock Shopify Liquid theme you already have these; check what Shopify exposed on your behalf.
- Travel and hospitality: flight, hotel and rental search. Multi-step bookings work, but each step is a tool call on the page the agent is on, since there is no cross-page flow definition in the spec.
- SaaS platforms: account management, configuration, support tickets. Let agents perform administrative tasks through well-defined tools, with your existing permissions.
- Financial services: account lookups, transaction history, calculators. Mark read-only tools honestly and leave anything that moves money to the agent's confirmation flow.
- Healthcare: appointment scheduling, provider search, refill requests. Structured tools with clear input schemas reduce errors in workflows where a wrong click matters.
- Real estate: property search, mortgage calculators, viewing appointments.
- Content publishers: even read-only sites gain from the declarative API on their search form.
Start with your highest-traffic form. A search form with WebMCP attributes takes five minutes and makes your most important functionality callable.
WebMCP vs other agent protocols
| Protocol | Scope | Where it runs | Best for |
|---|---|---|---|
| WebMCP | Client-side tool exposure | In the browser (JavaScript) | Interactive websites, forms, SPAs |
| MCP | Server-side tool protocol | Backend servers | APIs, databases, backend services |
| A2A | Agent-to-agent communication | Between agents | Multi-agent orchestration |
| OpenAPI | API documentation | Backend servers | REST APIs, developer integrations |
| agents.json | Agent endpoint discovery | Static file | Listing available agent endpoints |
These protocols complement each other. WebMCP handles client-side browser interactions, MCP handles backend tool connections, A2A handles agent-to-agent coordination, and OpenAPI documents your REST APIs.
Best practices
-
Feature-detect, always.
document.modelContextis undefined almost everywhere; a bare call throws. -
Verb-based, unique names:
search_flights,book_hotel,submit_ticket. A duplicate name rejects the registration. - Write descriptions for a reader who has not seen your site. The description is the only thing the agent has when deciding whether to call the tool.
- Keep the list short. Every registered tool is context the agent has to read on every visit. Expose the tasks people actually come for.
- Accept raw user input and normalise it yourself: natural-language dates, flexible formats, common typos.
- Return errors an agent can act on, such as "Invalid airport code. Expected a 3-letter IATA code like AMS or JFK" instead of a bare 400.
-
Use
readOnlyHinttruthfully, and never as a way to skip a confirmation the user would want. - Reuse your existing endpoints and checks. A tool is a second front door to logic you already have. It must not become a side entrance around your authorization.
Getting started
You do not need to do everything at once. In order of return on effort:
- Add WebMCP attributes to your search form, the highest-impact and lowest-effort change
- Annotate your contact and login forms
- Register imperative, read-only tools for the lookups people ask about most: availability, pricing, order status
- Open your site in the ChatGPT desktop app and read what "Site tools" shows an agent
- Only then add tools that change state, and make sure each one runs the same checks as the button it replaces
Sources
- WebMCP specification (W3C Web Machine Learning Community Group draft, August 2026)
- WebMCP declarative API explainer
- WebMCP implementation status (updated 26 August 2026)
- Move the modelContext getter to Document (merged 27 May 2026)
- WebKit standards position on WebMCP: oppose (June 2026)
- Mozilla standards position on WebMCP: neutral (2026)
- Join the WebMCP origin trial (Chrome for Developers, June 2026)
- WebMCP developer guide (Chrome for Developers)
- 15 updates from Google I/O 2026 (Chrome for Developers, list of companies experimenting with WebMCP)
- WebMCP updates, clarifications, and next steps (Patrick Brosset, Microsoft, February 2026)
- WebMCP: a much needed way to make agents play with rather than against the web (Christian Heilmann, February 2026)
- Site tools, ChatGPT documentation (OpenAI, August 2026)
- WebMCP support for Liquid and Hydrogen storefronts (Shopify developer changelog, 5 August 2026)
- Give any website a WebMCP interface (Cloudflare, 6 August 2026)