There's a new visitor in your logs: the AI agent, acting on someone's behalf. Right now it "uses" your site by reading the DOM and guessing which button does what. WebMCP replaces the guessing with a contract — your page declares structured tools an in-browser agent can call directly.
It's a draft W3C standard (Google + Microsoft) that shipped as an early preview in Chrome 146. Here's how to add it, step by step, with copy-paste code.
The mental model (read this first)
A WebMCP tool is three things:
- a name
- a description the agent reads to decide when to call it
- an inputSchema describing its parameters
When the agent calls it, your code runs in the user's own tab, with their session and permissions, and returns a result. There are two ways to declare a tool — start with declarative.
Step 1 — Declarative: expose a form (the easy win)
If the action is already a <form> (search, subscribe, log in), add two attributes to the form and one to each input. It keeps working for humans; the browser synthesizes a tool from it.
<form
tool-name="search-products"
tool-description="Search the product catalog by keyword"
action="/search" method="get"
>
<input
name="query"
tool-param-description="Keywords to search for, e.g. 'running shoes'"
required
/>
<button type="submit">Search</button>
</form>
Because the tool lives in your HTML, it survives your build step and is trivial to verify. Make this your default: every important form gets tool-name and tool-description.
Step 2 — Imperative: register a tool in JS (for everything else)
For logic a form can't express, register a tool with JavaScript. Feature-detect first so non-WebMCP browsers are unaffected. The current entry point is document.modelContext (older previews used navigator.modelContext):
const mc = document.modelContext || navigator.modelContext;
if (mc) {
mc.registerTool({
name: "add-to-cart",
description: "Add a product to the cart by SKU.",
inputSchema: {
type: "object",
properties: {
sku: { type: "string", description: "Product SKU, e.g. 'SHOE-42'" },
quantity: { type: "integer", description: "How many to add" }
},
required: ["sku"],
additionalProperties: false
},
async execute({ sku, quantity = 1 }) {
const result = await addToCart(sku, quantity); // your existing app logic
return { content: [{ type: "text", text: JSON.stringify(result) }] };
}
});
}
The key move: execute calls the same function your UI already calls. You're exposing logic you already have, not building a second integration.
Step 3 — Return the right shape
Whatever execute does, return the MCP content-block shape so the agent gets a usable result:
return { content: [{ type: "text", text: JSON.stringify(data) }] };
Step 4 — Verify it
Two things worth knowing:
- Declarative tools are easy to confirm — they're right there in your HTML.
- Imperative tools aren't — they only exist after your JS runs, and in a minified bundle you can't eyeball them. Any static "is my site ready" check confirms your form-based tools but sees only a code reference for JS-registered ones. That's the nature of static analysis, not a flaw in your site.
Quick loop I use:
Generate correct snippets (both formats, with the feature-detection shim):
https://toolhq.dev/tool/webmcp-generator/Check your page — paste HTML or scan your URL; it also flags forms you could expose and hands you the attributes to add:
https://toolhq.dev/tool/webmcp-checker/For a true end-to-end test, open the page in a WebMCP-capable browser (Chrome 146+ with the flag) and have its agent call the tool.
Deeper walkthrough:
https://toolhq.dev/learn/make-your-website-webmcp-ready/
Best practices
- Name tools in kebab-case; write the description like you're briefing a teammate.
- Describe every parameter — vague inputs cause wrong calls.
- Least privilege: only expose actions the user could already perform; the tool runs with their session.
- Guard destructive actions (delete/pay/send) with confirmation; treat tool input as untrusted.
- Keep the human UI working — WebMCP augments your page, never replaces it.
Where WebMCP fits
Three layers, not one:
-
llms.txt→ tells an assistant what your site is and points at key pages. -
robots.txt→ decides who may crawl. - WebMCP → declares what an agent can do once it's there.
Search optimized your site for crawlers; this optimizes it for actors.
Wrap-up
WebMCP is early — the spec (especially the declarative attribute names) can still shift, so feature-detect and keep your human UI intact. But it's cheap to adopt: a couple of attributes on forms you already have, plus a thin registerTool wrapper around logic you already wrote.
Ten minutes. Start with one form.
Have you made anything agent-ready yet, or hit a rough edge in the spec? Compare notes in the comments.
Top comments (1)
The three-layer framing is useful. We added llms.txt plus a dedicated AI welcome guide, but discovery still is not execution. WebMCP is the missing action contract. I would add endpoint-level idempotency and rate limits to the checklist, because an in-browser confirmation does not prevent duplicate calls after an agent retries a request.