WebMCP Tutorial: Setup, Tools, and Deployment
A practical WebMCP tutorial: detect support, register safe tools, test calls, handle drift, and deploy with guardrails. Works in agents that support page tools.

You searched for a WebMCP tutorial. Good. Here’s the honest state: WebMCP is real, works in some agents and frameworks right now, and is in origin trials in major browsers. It’s early, so you need feature detection and pragmatic fallbacks. By the end of this guide, you’ll have working tools on your site, a plan to test them, and guardrails for production.
See the current support for agents, browsers, and frameworks on the public WebMCP ecosystem tracker.
TL;DR
- WebMCP exposes in-page tools for agents to call instead of scraping—register with
document.modelContext ?? navigator.modelContextand small JSON results. - Start with 2–4 high-signal tools: search, add_to_cart, start_checkout, and contact_support. Put preconditions and side effects in descriptions.
- Gate sensitive actions with explicit, in-page user confirmation before executing. Never pass secrets or payment data through tool params.
- Test in an environment that actually calls page tools: ChatGPT desktop “site tools”, Stagehand, or Vercel’s agent-browser. Keep fallbacks for agents that only read the DOM.
- Production hardening: version your configs, log calls, and watch for UI drift. If you don’t want to build infra, Agent Layer automates these pieces and gives you a free audit.
What WebMCP is (and isn’t)
- WebMCP lets a web page register tools (name, description, JSON Schema input, async execute) that an AI agent in the browser can discover and call. Tools run in the page, in the user’s current session. No backend round-trips or extra API keys for the agent.
- WebMCP is not Anthropic’s MCP. MCP runs tools on backend servers over stdio/HTTP. WebMCP runs in the page. If you’re comparing, see what is the difference between MCP and WebMCP.
- Support is uneven. Some agents work today (e.g., ChatGPT desktop “site tools”, ChatGPT Work). Some frameworks work (Stagehand, Vercel agent-browser, Browser Use). Browsers are in origin trials. Track specifics on the ecosystem support page.
If your goal is “agents can reliably execute key flows on my site,” WebMCP is the most direct path. DOM scraping and vision-based clicking are fragile; if you need background on why, read why DOM scraping and vision models are dead for agentic web workflows.
Minimum viable WebMCP toolset
Ship a small, high-leverage set first. For e‑commerce:
- search_products(q)
- add_to_cart(product_id, quantity)
- start_checkout()
- get_cart()
For SaaS:
- find_plan(slug)
- start_trial(plan_id)
- update_account_email(new_email) [sensitive ⇒ confirmation]
Descriptions should state when to use the tool, what it needs, and what it changes. Agents choose tools from descriptions—not names alone.
Feature detection and a first tool
This example registers a read-only tool to get the current cart. It uses feature detection for both current and older addresses.
// Put this at the end of your page, after cart state is available.
(function registerWebMCP() {
const mc: any = (document as any).modelContext ?? (navigator as any).modelContext;
if (!mc) return; // No WebMCP available; page still works normally.
mc.registerTool({
name: "get_cart",
description: "Use to read the current cart. Returns line items with id, title, price, quantity, subtotal.",
inputSchema: { type: "object", properties: {}, additionalProperties: false },
execute: async () => {
// Example: adapt to your cart state/store
const items = window.myCart?.items || [];
const out = items.map((it: any) => ({
id: String(it.id),
title: String(it.title),
price: Number(it.price),
quantity: Number(it.quantity),
subtotal: Number(it.price) * Number(it.quantity)
}));
return { item_count: out.length, currency: window.myCart?.currency || "USD", items: out };
}
});
})();
- The result is small and JSON-serialisable, as required.
- No secrets or tokens returned. Keep it descriptive, not exhaustive.
A write tool with guardrails: add_to_cart
This pattern gates write actions behind an explicit, visible user confirmation in the page. Agents can request the action, but the user must confirm.
(function registerAddToCart() {
const mc: any = (document as any).modelContext ?? (navigator as any).modelContext;
if (!mc) return;
// Minimal inline confirmation UI
function confirmAction(message: string): Promise<boolean> {
return new Promise((resolve) => {
const box = document.createElement("div");
box.style.cssText = "position:fixed;bottom:16px;right:16px;background:#111;color:#fff;padding:12px;border-radius:8px;z-index:99999;";
box.innerHTML = `${message} <button id="ok">Confirm</button> <button id="no">Cancel</button>`;
document.body.appendChild(box);
box.querySelector("#ok")!.addEventListener("click", () => { box.remove(); resolve(true); });
box.querySelector("#no")!.addEventListener("click", () => { box.remove(); resolve(false); });
});
}
mc.registerTool({
name: "add_to_cart",
description: "Use to add a specific product to the cart when the user has chosen an item and quantity.",
inputSchema: {
type: "object",
required: ["product_id", "quantity"],
properties: {
product_id: { type: "string", description: "Internal product ID visible in page state." },
quantity: { type: "integer", minimum: 1, maximum: 20 }
},
additionalProperties: false
},
execute: async (params: { product_id: string; quantity: number }) => {
const { product_id, quantity } = params;
// Preconditions you enforce in UI/state
const product = window.catalog?.find((p: any) => String(p.id) === product_id);
if (!product) return { ok: false, error: "unknown_product" };
if (!product.inStock) return { ok: false, error: "out_of_stock" };
const ok = await confirmAction(`Add ${quantity} × ${product.title} to cart?`);
if (!ok) return { ok: false, error: "user_declined" };
// Perform the action using your existing cart functions
await window.cartApi.add(product.id, quantity);
return { ok: true, item_id: String(product.id), quantity };
}
});
})();
- The tool states its preconditions so agents only call it with context.
- The user confirms before you mutate state. For checkout or account changes, keep this pattern.
Search with friendly schema and small results
Agents do better with clear descriptions and small, relevant returns.
(function registerSearchProducts() {
const mc: any = (document as any).modelContext ?? (navigator as any).modelContext;
if (!mc) return;
mc.registerTool({
name: "search_products",
description: "Use to find products by keyword. Returns up to 10 results with id, title, price, and url.",
inputSchema: {
type: "object",
required: ["q"],
properties: { q: { type: "string", minLength: 2 } },
additionalProperties: false
},
execute: async ({ q }: { q: string }) => {
const results = await window.searchApi.search(q); // Use your site’s search
const top = results.slice(0, 10).map((r: any) => ({
id: String(r.id),
title: String(r.title),
price: Number(r.price),
url: String(r.url)
}));
return { count: top.length, results: top };
}
});
})();
End-to-end flow
This diagram shows a simple sequence where an agent asks the page for cart state, searches, and adds to the cart with a user confirmation.
Where it runs today
Based on hands-on verification:
- Agents that call page tools today: ChatGPT desktop app (native “site tools”), ChatGPT Work.
- Frameworks that can run a browser and call WebMCP tools: Stagehand, Vercel agent-browser, Browser Use.
- Browsers: Chrome and Edge are in origin trials; Brave has it behind a flag; Firefox and Safari do not support it.
The list changes. Check the ecosystem tracker for up-to-date, vendor-verified status.
If you want more detail on Chrome’s current behavior and practical dev setup, read WebMCP in Chrome: what works today and how to build for it.
Local development and testing
You can ship WebMCP tools without any external service. The work is:
- Add your
registerToolcode to the pages that own the state (product, cart, account). Feature-detectdocument.modelContext ?? navigator.modelContext. - Open a testing agent that actually calls tools:
- ChatGPT desktop on macOS/Windows: “site tools” are on by default.
- Stagehand or Vercel agent-browser in a local Chrome they launch.
- Exercise real intents:
- “Find a blue hoodie under $50 and add medium to cart.”
- “What’s in my cart? Remove the duplicate.” (Implement remove_from_cart similarly.)
- Validate small, JSON-serialisable results and confirm user prompts for write actions.
If you want a structured checklist for coverage, use the WebMCP form coverage checklist. For automating verification, see WebMCP for testing: how to verify your site works with agents.
Production hardening
WebMCP itself is a thin interface. Production needs basics you may already have for regular UI work:
- Drift resistance: When selectors or components change, tools that rely on them break.
- Observability: Which agent called what tool, how often, and with what errors.
- Versioning and rollback: You want to change tool schemas and bindings safely.
- Guardrails: Explicit user confirmation for sensitive actions; rate control for tools that can spam orders/emails.
- Intent tests: A set of natural-language prompts mapped to expected tool usage.
You can build this in-house. Or, if you want this managed and integrated, Agent Layer’s platform adds:
- One script to detect page templates and define tools per template.
- Versioned configs with safe rollout and rollback.
- Health checks that catch drift and suggest updated selectors.
- Analytics for every tool call: agent, success/error, duration.
- Guardrails for sensitive actions, including payments and account changes.
- Test scenarios to validate that real intents pick the tools you expect.
Even if you don’t use the platform, you can run the free agent-readiness audit to see what to fix first.
Example: start_checkout with strict confirmation
Keep the result small, but be explicit about side effects in the description and require a user click.
(function registerStartCheckout() {
const mc: any = (document as any).modelContext ?? (navigator as any).modelContext;
if (!mc) return;
function confirm(message: string): Promise<boolean> {
return new Promise((resolve) => {
const d = document.createElement("dialog");
d.innerHTML = `<p>${message}</p><form method="dialog"><button value="ok">Start</button><button value="no">Cancel</button></form>`;
document.body.appendChild(d);
(d as HTMLDialogElement).showModal();
d.addEventListener("close", () => { const ok = (d as any).returnValue === "ok"; d.remove(); resolve(ok); });
});
}
mc.registerTool({
name: "start_checkout",
description: "Use to move the user from cart to the first checkout step after they confirm.",
inputSchema: { type: "object", properties: {}, additionalProperties: false },
execute: async () => {
const ok = await confirm("Proceed to checkout now?");
if (!ok) return { ok: false, error: "user_declined" };
window.location.href = "/checkout"; // Or your router transition
return { ok: true, redirected: true };
}
});
})();
Tool design guidelines that work
- Be precise in descriptions. Include “when to use,” “what it needs,” and “what it changes.”
- Keep inputs minimal and strongly typed via JSON Schema. Avoid optional fields that change semantics.
- Return small, task-focused JSON. Don’t dump entire models.
- Make preconditions explicit and fail fast with stable error codes.
- Confirm sensitive actions visibly in the page. Don’t confirm via agent text.
- Never accept or emit secrets, tokens, or payment data in tool params or results.
Here’s a quick reference you can copy into your issue tracker:
| Concern | Pattern |
|---|---|
| Feature detection | document.modelContext ?? navigator.modelContext |
| Tool naming | snake_case, action-oriented |
| Read tools | No confirmation, small summaries |
| Write tools | Explicit in-page user confirmation |
| Errors | Short codes like user_declined, out_of_stock |
| Results | Small, JSON-serialisable, describe outcome |
What breaks in production
- Missing feature detection. Some agents still check
navigator.modelContext. If you only register ondocument, nothing works. - Overly vague descriptions. Agents won’t pick your tool if they can’t tell when to use it.
- Huge results. Models get lost; token windows aren’t the bottleneck—relevance is. Trim to essentials.
- No confirmation on sensitive actions. You’ll ship something risky and then disable tools entirely after the first scare.
- UI drift. Component or selector changes break tool bindings if you reach into the DOM or app store without an abstraction.
- Testing only in one agent. Production agents differ. Use at least one consumer agent (e.g., ChatGPT desktop) and one framework runner (e.g., Vercel agent-browser or Stagehand).
- Assuming browser support. WebMCP is in origin trials in Chrome and Edge, behind flags in Brave, and not in Firefox/Safari. Always check the ecosystem status.
Deploying incrementally
- Phase 1: Read-only tools on core pages (get_cart, get_product, get_account). Zero risk, immediate value for agents that want context.
- Phase 2: Low-risk writes with confirmation (add_to_cart, start_checkout). Keep the dialogue simple and obvious to the user.
- Phase 3: Account flows with stricter confirmation and maybe 2-step UI (update_email, cancel_subscription). Consider rate limits.
- Phase 4: Observability and drift protection. If you don’t have internal tooling, Agent Layer adds health checks, analytics, and versioned configs.
For concrete commerce examples and what revenue flows teams are actually trying, see agentic commerce for Shopify and the step-by-step WebMCP for Shopify guide.
FAQ
- Can I ship without a backend change? Yes. Tools run in the page context, using the user’s existing session.
- Does this help “SEO”? There’s no evidence that WebMCP affects Google rankings. It’s for agents that execute flows, not classic search. If you care about agent discoverability, read the rise of Agent Engine Optimization.
- Which agent should I test first? If you want something off-the-shelf, ChatGPT desktop “site tools” works today. For code-first tests, Stagehand or Vercel agent-browser.
- How do I gate payments? Keep payments entirely in your checkout UI. The tool only transitions the user to that screen after explicit confirmation.
Try it
Add the three code blocks above to your product and cart pages, then validate with an agent that supports page tools. If you want a fast read on gaps, run the free agent-readiness audit. To track when your target agents and browsers support WebMCP, bookmark the ecosystem tracker.

