WebMCP: the web page becomes the tool server
MCP put tools behind servers. WebMCP puts them inside the page. A web application can now register callable, schema-typed functions with the browser itself — and any agent sitting in that browser can invoke them instead of guessing its way through a UI built for humans.
The proposal is further along than most people realize. The WebMCP specification was republished as a Draft Community Group Report on July 28, 2026 — the same day, coincidentally, that the MCP 2026-07-28 spec went final on the backend side. It is edited by Brandon Walderman (Microsoft) and Khushal Sagar and Dominic Farolino (Google), under the W3C Web Machine Learning Community Group. Chrome shipped it experimentally behind a flag in Chrome 146 and opened a public origin trial in Chrome 149. And on August 6, during its Agents Week, Cloudflare launched a developer preview that retrofits WebMCP onto any site behind its network with a dashboard toggle — no origin changes at all.
We read the spec, the explainers, and the repo history. This post covers the API as it actually stands in the July 2026 draft — including a rename that most tutorials still get wrong — the declarative form layer, the deployment story, and the two omissions that matter most to anyone running autonomous agents: identity and payments.
From scraping to contracts
The problem WebMCP attacks is the one every browser-using agent knows. Today's general-purpose agents observe pages through screenshots, DOM snapshots, and accessibility trees, then act by simulating human input. It is slow, brittle, and expensive. The explainer frames the alternative bluntly: pages that use WebMCP "can be thought of as in-page Model Context Protocol servers that implement tools exposing client-side logic and DOM interaction rather than server-side APIs."
Why not just give every site a backend MCP server? The explainer lists three reasons. Backend integrations disintermediate the web UI — the agent talks to the service's servers and the page never sees any of it. They force developers to replicate state, context, and authentication on a separate server. And they demand new backend code, while the functionality already exists in client-side JavaScript. WebMCP's bet is code reuse: any task a user can do through the page's UI can be wrapped as a tool with the page's existing frontend logic, sharing the user's live session, cart, and login for free.
The design center is explicitly cooperative. The stated goals are human-in-the-loop workflows where users keep visibility and control, and the non-goals are unambiguous: headless browsing and "fully autonomous workflows" without human oversight are out of scope. Hold that thought — it is the most consequential sentence in the document for the walk-up agent economy.
The API: document.modelContext
The entry point is a ModelContext object hanging off the document. Registration is one call:
const controller = new AbortController();
await document.modelContext.registerTool({
name: "add-todo",
description: "Add a new item to the user's active todo list",
inputSchema: {
type: "object",
properties: {
text: { type: "string", description: "The text content" }
},
required: ["text"]
},
async execute({ text }) {
// Reuse existing client-side application logic.
await addTodoItemToCollection(text);
return { content: [{ type: "text", text: `Added: "${text}"` }] };
}
}, { signal: controller.signal });
The shape is deliberately MCP-shaped: a unique name (1–128 characters, alphanumerics plus underscore, hyphen, and period), a natural-language description, a JSON Schema inputSchema, and an async execute callback returning MCP-style content blocks. Unregistration is not a method — it is the AbortSignal passed at registration time, which also auto-cleans tools when a component unmounts. registerTool() returns a promise and rejects with NotAllowedError when policy forbids it. An annotations object carries two hints: readOnlyHint, and untrustedContentHint to flag tools whose output may embed externally sourced content — a prompt-injection tripwire we will come back to.
navigator.modelContext. The Community Group moved the getter to Document in PR #184 (merged May 27, 2026) because tools belong to a specific page, not the browsing context. Chromium has deprecated the navigator surface as of Chrome 150. During the transition, feature-detect both: document.modelContext || navigator.modelContext. The earlier bulk-registration call provideContext() is gone from the spec too — issue #101 showed it could silently overwrite previously registered tools, bypassing registerTool()'s duplicate-name protection.
Access control is native web machinery rather than anything MCP-flavored. The whole API is SecureContext-only and gated behind a tools Permissions Policy whose default allowlist is ['self']: top-level documents and same-origin iframes get it by default, and a cross-origin iframe — say, an embedded chat agent — must be delegated explicitly with allow="tools". Tool visibility has its own second axis: by default a registered tool is visible only to the page itself, same-origin documents in the tree, and the browser's built-in agent, but the exposedTo registration option can share specific tools with specific origins. A toolchange event fires on ModelContext as tools come and go, and a getTools() method — spec'd on July 21 — lets author-provided agents enumerate what is available, each entry carrying its owner's origin and window. The corresponding executeTool() for in-page agents is still marked TODO in the explainer, which tells you how actively this surface is moving: the repo shows commits landing through August 3, 2026, with roughly 2,950 stars and 113 open issues and PRs.
The declarative layer: forms as tools
The second half of the proposal needs no JavaScript at all. The declarative API explainer adds attributes to plain HTML forms, and the browser compiles the form into a tool:
<form toolname="search-cars"
tooldescription="Perform a car make/model search">
<input type=text name="make"
toolparamdescription="The vehicle's make (e.g., BMW)" required>
<input type=text name="model"
toolparamdescription="The vehicle's model (e.g., 330i)" required>
<button type=submit>Search</button>
</form>
The browser synthesizes the JSON Schema from the form controls — name attributes become properties, required becomes required, and the exact reduction of things like min, step, and <select> options into schema constraints is still being worked out, with Chromium implementing a loose version to test in the trial. The consent geometry is encoded in one boolean attribute: without toolautosubmit, the agent fills the form but the browser focuses the submit button and a human must click it. New CSS pseudo-classes :tool-form-active and :tool-submit-active exist precisely so sites can highlight "the agent filled this out, please review." With the attribute, the agent submits on the user's behalf. That is a permission model expressed in markup.
Getting the response back to the agent is the interesting part. SubmitEvent grows an agentInvoked flag and a respondWith() method, so script can intercept an agent-driven submission, skip navigation, and pipe a structured result straight back. For forms that do navigate, the draft floated using the first <script type="application/ld+json"> block on the destination page as the tool response — cross-document responses remain an open debate in issue #135. Cancellation is handled: resetting the form or mutating its tool attributes cancels any in-flight invocation, with toolactivated and toolcanceled events surfacing the lifecycle to the page.
Where it runs today
Chrome is the reference implementation. The DevTrial sits behind chrome://flags/#enable-webmcp-testing; the origin trial opened in Chrome 149 for production experimentation. Chrome's documentation lists three classes of consumers — Gemini in Chrome, Chrome extensions, and third-party agents driving the browser — and DevTools gained experimental support for inspecting registered tools, invoking them manually, and validating schemas. The documentation is equally clear about the boundary: tool calls execute in page JavaScript, so "a browser tab or a webview must be opened." No tab, no tools, no headless execution.
Cloudflare's August 6 preview is the more strategically interesting deployment because it requires zero developer work. Flip a toggle in the dashboard and its edge injects, via HTMLRewriter, a single module script — /.webmcp/bridge.js — into every HTML response. The bridge registers "packs" of tools against document.modelContext. Two packs exist at launch: Content Credentials, which exposes scan_images_c2pa and inspect_image_c2pa for reading C2PA provenance metadata from images on the page, and Site MCP Server, which discovers a site's existing MCP server and proxies its tools into the page over same-origin requests — with the visitor's session attached. Cloudflare's BrowserRun remote browser consumes the same tools from the other side. One infrastructure provider now sits on both ends of the handshake, which is the same edge-chokepoint pattern we traced in x402 edge enforcement.
The security section reads like a warning label
To the editors' credit, the spec's security and privacy section does not undersell the risks. It names tool metadata and tool outputs as prompt-injection vectors — a malicious page can embed instructions in a description or a return value, which is exactly why untrustedContentHint exists. It concedes plainly that "there is no guarantee that a WebMCP tool's declared intent matches its actual behavior": a tool named get-prices can do anything its execute callback wants. It flags over-parameterization as a privacy attack — a schema with optional age, location, and health parameters invites the agent to volunteer personal context the user never typed into the site. And it worries about agents carrying authenticated state across origins and about tools leaking private-browsing activity.
What the spec does not yet have is a per-call consent mechanism. Elicitation-style user prompting is an open question (issues #165 and #50), and the ModelContextClient interface that would formalize the agent side was removed from the draft for now. The trust model today is: the page trusts the browser to mediate, the agent trusts the page's descriptions, and the human trusts the agent's judgment about when to ask. Every tool executes with the visitor's cookies, storage, and login on that origin. For the interactive, human-supervised sessions WebMCP targets, that inherited-session model is the feature. It is also the reason the standard cannot simply be extended to unattended agents without a real identity layer underneath.
The autonomous gap
Read as infrastructure for the agentic web, WebMCP has a precise shape: it makes pages callable for agents that are already inside the user's browser, and it deliberately stops there. Three boundaries define the gap.
First, autonomy is a non-goal by charter. The spec is built for a human watching a tab, not for a fleet of headless workers. Yet the pressure is already visible in the repo: the service workers explainer proposes letting agents discover and invoke tools on sites the user does not have open, via background workers — which is, functionally, the first step from cooperative browsing toward the unattended execution the main spec disclaims.
Second, there is no agent identity primitive. A WebMCP tool cannot ask which agent is calling, on whose behalf, under what delegation. The tool sees a browser-mediated call wearing the visitor's session. Contrast that with Web Bot Auth, where agents sign HTTP requests with published keys precisely so origins can distinguish and price them. The two models will have to meet: a page exposing a high-value tool to "the built-in agent" today has no way to distinguish Gemini acting for a logged-in human from an automation framework driving the same Chrome profile.
Third — and most relevant to this blog — there is no payment primitive. The explainer's own commerce scenarios walk right up to the line: the print-shop example ends with the tool "automatically navigating the browser tab to the secure checkout page where Jen can complete the order with a single click." The tool can fill the cart but not settle. Nothing in the tool result format can express "this call costs $0.002" or carry a settlement receipt. In Cloudflare's four-verbs framing from Agents Week — readable, discoverable, callable, payable — WebMCP is the callable verb, and payable is a different product (Wallets and the Monetization Gateway, which we covered in last week's roundup). The seam between those two verbs is where an HTTP 402 and an x402 settlement naturally slot in, and nobody has standardized that junction inside the browser yet.
What it means for LLM4Agents
LLM4Agents operates on the other side of WebMCP's design boundary: our customers run exactly the headless, autonomous agents the spec declares out of scope. That cuts two ways.
The threat is a repeat of the walled-garden dynamic. If the browser becomes the privileged place where sites expose structured capabilities — and the consuming agent is Gemini in Chrome riding the user's existing sessions — then a whole class of interactions never leaves the browser, never hits an API, and never emits the 402 that a walk-up agent could pay. Cloudflare deploying WebMCP by default-adjacent toggle across its network accelerates that: the tool surface of the web grows fastest where our agents cannot stand.
The opportunity is that WebMCP normalizes the tool contract we already sell. The Site MCP Server pack is the tell: Cloudflare's bridge does not invent new capabilities, it proxies a site's backend MCP server into the page. The canonical architecture that emerges is one tool definition projected onto two surfaces — MCP over HTTP for headless agents, WebMCP for in-browser ones. Every site that adopts that pattern has, by construction, an MCP endpoint our gateway's agents can call, meter, and pay for via x402. And the schemas are portable in both directions: a page's inputSchema is the same JSON Schema our MCP tools publish. WebMCP grows the population of tool-shaped capabilities on the web; per-call settlement for the headless half of their consumers is precisely our lane. Where MCP Apps pushed server UI into MCP hosts, WebMCP pushes MCP tools into pages — the two specs are converging on the same claim from opposite ends: the interface and the tool contract are becoming the same artifact.
Staying on the frontier
Concrete moves, in order. First, ship WebMCP on our own properties: register tools on the LLM4Agents dashboard (balance queries, key rotation, usage reports) via document.modelContext, feature-detecting both surfaces — it is a weekend of work against the origin trial and makes the dashboard operable by our customers' browser agents. Second, adopt the dual-projection pattern in our SDK guidance: one tool definition, emitted as both an MCP server tool and a WebMCP registration, so operators using our gateway get both surfaces from one schema. Third, prototype the missing junction: a WebMCP tool whose execute hits a 402-protected endpoint through our gateway and resolves the payment with the x402 buyer stack, returning the receipt in the tool result — the browser-side complement to our buyer-stack coverage, and a concrete proposal to bring to the Community Group's elicitation discussion (issue #165), since a payment approval is exactly the user-prompting case the spec has not designed yet. Fourth, track the service-workers explainer closely; if background tool invocation lands, WebMCP stops being browser-session-bound and starts to overlap our headless territory — we want to be early there, not surprised. Fifth, watch getTools() — an enumerable, origin-attributed tool directory inside every page is a discovery signal our routing layer should eventually ingest alongside registry and Bazaar data.
Build agents that can call — and pay
One gateway, 345+ models, per-call stablecoin settlement over x402. The tool contract is standardizing; the payment rail is ready today.
Register your agent