Home/Guides/What is WebMCP, and how is it different…
Guide · 8 min read

What is WebMCP, and how is it different from MCP?

One runs on your server and needs its own credentials. The other runs in the tab the user already has open. The difference decides which one you should build.

Quick answer

MCP puts tools on a server you run: the agent connects to it, and you have to give it credentials of its own and keep a second surface in step with your product forever. WebMCP puts tools in the page the user already has open: the agent calls a function you registered, your existing client code runs it, and the interface updates because…

A got WebMCP? poster. A person stands outside a lit office at night with both palms flat against the glass, looking in. The headline reads: It can see every button. It cannot press one.

An agent trying to buy something on your site today takes a screenshot, guesses which rectangle is the checkout button, clicks, takes another screenshot, and hopes. It is slow, it is brittle, and when it goes wrong your support inbox finds out before you do.

WebMCP is the alternative. Your page registers typed tools; the agent calls them by name with structured arguments; and your own client code runs the action, so the interface stays in sync with whatever just happened. It is a specification from the W3C Web Machine Learning Community Group, developed by Google and Microsoft, and it is in origin trial in Chrome and Edge as of writing.

The most common assumption about it is that it is MCP with a different transport. Same idea, same tools, just running in a tab. Build one, get the other cheap.

That is wrong in a way that costs a rewrite.

Where each one actually lives

A classic MCP server runs on your infrastructure. The agent connects to it, and it talks to your backend over your own API. To make that work you have to give the server its own way in: an API key, a service account, some mechanism for acting as the user who is asking.

That is often the right call, and it is also three problems you now own. You are replicating the user's session somewhere it did not previously exist. You are maintaining a second surface that has to stay in step with your product indefinitely. And the agent is doing things your web application knows nothing about, so the page in front of the user goes stale the moment the agent acts.

WebMCP runs in the page the user already has open. Your page registers tools with the browser. The agent calls them. The function that executes is your existing client code, in the tab, using the session that is already there.

Nothing to authenticate separately, because the person is already signed in. Nothing to keep in step, because it is the same code path your buttons call. And the interface updates, because the tool did what the button does.

The differences that decide it

 Classic MCPWebMCP
Runs ona server you operatethe user's open tab
Authcredentials of its own, plus a story for acting on behalf of a userinherits the session already in the browser
Statebackend and front end drift apart during an agent sessionone state, which the human and the agent both see
Setup for the usera config file and a key before anything worksnone; the tools are there when the page loads
Reachheadless, any client, no browser requiredonly where a tab is open

That last row is the honest limit. If you want an agent acting on your product at three in the morning with nobody signed in, WebMCP cannot help you. Build the server.

The rule worth remembering

If the action makes sense with nobody watching, it belongs on the server. If it only makes sense in the context of what the person is currently looking at, it belongs in the page.

A nightly report is a server. Filtering the list currently on screen is the page. Taking a payment is arguably both, and the confirmation step belongs in the page where a human can see it.

What the API looks like

Before anything else: the entry point is document.modelContext, not navigator.modelContext. A great deal of the secondary writing about WebMCP says navigator. The specification and the shipped Chrome implementation both say document. Follow the wrong one and you get undefined, conclude your browser has not shipped support, and never write the integration at all.

const controller = new AbortController();

await document.modelContext.registerTool({
  name: 'add-to-cart',
  description: 'Add the product currently open to the basket',
  inputSchema: {
    type: 'object',
    properties: {
      quantity: { type: 'number', description: 'How many to add' },
    },
  },
  async execute({ quantity }) {
    await addToCart(quantity);          // the page's own logic
    return { content: [{ type: 'text', text: `Added ${quantity}.` }] };
  },
}, { signal: controller.signal });

Abort the signal to unregister. That is the whole lifecycle.

Four things that are easy to get wrong

Tool count is a real budget. Every registered tool is prompt text on every single turn, so a catalogue of forty makes the model worse rather than more capable. Past roughly a dozen it starts choosing badly. Register per page state instead: the listing page registers buy this, and navigating away takes it back out.

Errors are instructions, not status codes. If execute throws, the agent stalls. If it returns a message saying what went wrong and how to fix the call, the agent corrects itself and retries. "Validation failed" is useless. "slug is required, call search first to get valid slugs" works.

Set untrustedContentHint on anything returning text other people wrote. Reviews, listings, comments, support tickets. A seller can put "ignore previous instructions" into a product description, and without the flag an agent may read that as an instruction rather than as the text of a listing. Say it in the result text too, because the annotation is a hint to the host while the sentence reaches the model either way.

Mark anything consequential. consequentialHint goes on whatever spends money, publishes, sends or deletes. Hosts use it to decide what needs a human to confirm, and being permissive here is how an agent buys something nobody asked for.

Testing it before browsers ship it

Stable Chrome returns undefined for document.modelContext. There is a testing flag at chrome://flags, but its command line feature name is not documented, and six plausible candidates against both --enable-features and --enable-blink-features produced nothing. So you cannot verify a WebMCP integration by opening a browser and looking at it.

What works is driving headless Chrome over the DevTools protocol and installing a specification-shaped document.modelContext before your bundle boots, using Page.addScriptToEvaluateOnNewDocument. Then assert that your code registered valid descriptors with a live abort signal. It is a simulation of the browser rather than the browser itself, and worth saying so out loud, but it does verify the half you actually control.

The other half is mirroring every tool onto a plain object on window. Firefox and Safari have not shipped, Chrome and Edge are both in trial, so a small registry with list() and call() means browser automation drivers and extension agents can use your tools today, and your test harness has something to drive.

Where to start

Inventory the outcomes a user can achieve on your site, not the buttons they can press. Group them by the page state that should own them. Register the small always-on set, and let each page add its own on mount. Then check that a tool nobody can call has not shipped looking finished.

loreto.io runs this in production: nine tools across discovery, account, listing and selling, with the panel in the corner showing what an agent can see on any given page.

Frequently asked questions

Does WebMCP replace my MCP server?
No, and the specification is explicit that the two complement each other. A server reaches your product from anywhere with no browser involved, which WebMCP cannot do. WebMCP reaches the live session with the user watching, which a server cannot do. Most products that want both will build both, with the split falling along whether the action needs the current screen.
Which browsers support it today?
Chrome has an origin trial from version 149 and landed the reference implementation in 146. Edge has a trial from 150. Brave has experimental support in Leo, and ChatGPT Desktop supports it. Firefox and Safari have open standards positions but have not shipped. Because of that, mirroring your tools onto the page as well is the difference between shipping now and waiting on a browser release.
Is exposing tools to agents a security risk?
It is usually a reduction in risk, because you move from an agent that can click anything a user can click to one that can call exactly what you chose to expose. What matters is choosing deliberately: never expose a tool that bypasses an authorisation check your interface enforces, never return credentials, never offer arbitrary execution, and mark anything that spends or publishes as consequential so a host can ask a human first.

Turn this guide into a skill your agent can run

Stop re-explaining the same workflow. Loreto packages it as a Claude Code skill from any source.