WebMCP form coverage: a practical developer checklist
A field-tested checklist to achieve WebMCP form coverage across your site: what to expose as tools, JSON Schemas to use, guardrails, and test flows that agents can run today.

You searched for WebMCP form coverage because you want agents to complete your forms reliably—sign‑up, cart, checkout, support requests—without scraping your DOM. By the end of this guide you’ll have a concrete checklist, runnable code samples, and a test plan to reach confident form coverage with WebMCP.
TL;DR
- Map each high‑intent form (search, sign‑in, add‑to‑cart, checkout, contact) to a WebMCP tool with a precise JSON Schema and a clear description of preconditions and effects.
- Feature‑detect both
document.modelContextandnavigator.modelContext, and return small, JSON‑serialisable results. - Add guardrails for sensitive actions (payments, account changes): require an in‑page confirmation before
executemutates state. - Test with an agent that calls page tools today (ChatGPT desktop / ChatGPT Work), and track broader support on the public WebMCP ecosystem status.
- Use Agent Layer if you want health checks against UI drift, versioned tool configs, analytics on which agents call tools, and an automated audit across your forms.
What “form coverage” means for WebMCP
Form coverage means an AI agent can: discover the action, understand its inputs and constraints, perform it with the user’s current session, and verify the outcome. You don’t need to expose every input field; you need tools that encapsulate the user intent of the form.
A good first pass covers:
- Search or filter products/content
- Authentication (sign‑in) and account updates
- Cart operations (add, update qty, remove)
- Checkout start and confirm
- Support/contact or ticket create
With WebMCP, these become page tools with JSON‑Schema inputs rather than a series of DOM clicks. Tools run in the browser tab, with the user’s session—no extra backend needed.
If you’re comparing standards, see what WebMCP is and how it differs from MCP. Short version: WebMCP is in‑page for websites; MCP is backend servers over stdio/HTTP.
Ecosystem reality check
WebMCP is early but usable. Today, we’ve seen real calls from ChatGPT desktop and ChatGPT Work. Other agents and browsers vary: Chrome and Edge are in origin trials; Brave is behind a flag; Firefox and Safari don’t support it. Frameworks like Vercel agent‑browser and Stagehand work today; others are behind flags or not supported. The tracker changes—always verify current status at the public WebMCP support page.
The developer checklist
1) Inventory your intent surfaces
List the flows with user intent that matter for revenue and support:
- Discovery:
search_products,filter_catalog - Commerce:
add_to_cart,update_cart,start_checkout,confirm_order - Account:
sign_in,update_profile - Support:
create_ticket
For each, decide the minimum inputs you actually need. Keep schemas tight.
2) Register tools with feature detection
Always detect both current and older addresses. Keep results small and explicit.
// webmcp-tools.js
(function registerWebMCPTools() {
const mc = (typeof document !== 'undefined' && document.modelContext) ||
(typeof navigator !== 'undefined' && navigator.modelContext);
if (!mc) return; // No WebMCP support; page still works normally
// 1) Search products
mc.registerTool({
name: 'search_products',
description: 'Use to search the catalog. Requires a non-empty query. Returns up to 10 result summaries with URLs.',
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', minLength: 1 },
limit: { type: 'integer', minimum: 1, maximum: 10, default: 5 }
},
required: ['query'],
additionalProperties: false
},
execute: async ({ query, limit = 5 }) => {
// Use your existing in-page search API or fetch; no secrets involved
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}&limit=${limit}`);
const data = await res.json();
// Return a compact summary the agent can reason over
return {
ok: true,
count: Math.min(data.items.length, limit),
items: data.items.slice(0, limit).map(i => ({
id: i.id,
title: i.title,
price: i.price,
url: i.url
}))
};
}
});
// 2) Add to cart (non-sensitive but stateful)
mc.registerTool({
name: 'add_to_cart',
description: 'Add a product variant to the cart. Preconditions: variant must be in stock. Side effect: mutates cart state.',
inputSchema: {
type: 'object',
properties: {
variant_id: { type: 'string', minLength: 1 },
quantity: { type: 'integer', minimum: 1, default: 1 }
},
required: ['variant_id'],
additionalProperties: false
},
execute: async ({ variant_id, quantity = 1 }) => {
const res = await fetch('/cart/add', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ variant_id, quantity })
});
if (!res.ok) return { ok: false, error: 'add_failed' };
const cart = await res.json();
return { ok: true, cart_total_items: cart.total_items };
}
});
})();
Notes:
- Describe when to use the tool, required preconditions, and side effects. Agents choose based on descriptions.
- Keep return payloads compact and factual. Avoid dumping entire DOM or huge arrays.
3) Add guardrails for sensitive actions
Payment, account changes, and destructive actions should prompt the human for confirmation. Implement a lightweight in‑page check the agent cannot bypass.
// Guarded tool example: confirm order requires explicit user click
(function registerCheckoutGuard() {
const mc = document.modelContext ?? navigator.modelContext;
if (!mc) return;
// Simple in-page confirmation modal
function confirmAction(message) {
return new Promise(resolve => {
const ok = window.confirm(message); // Replace with your modal if you prefer
resolve(ok);
});
}
mc.registerTool({
name: 'confirm_order',
description: 'Create and confirm an order for the current cart. Sensitive: requires explicit user confirmation in page.',
inputSchema: {
type: 'object',
properties: {
shipping_method: { type: 'string', minLength: 1 },
payment_method_id: { type: 'string', minLength: 1 }
},
required: ['shipping_method', 'payment_method_id'],
additionalProperties: false
},
execute: async ({ shipping_method, payment_method_id }) => {
const agreed = await confirmAction('Place order now?');
if (!agreed) return { ok: false, error: 'user_declined' };
// Never pass raw payment tokens through tool params; use stored IDs only
const res = await fetch('/checkout/confirm', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ shipping_method, payment_method_id })
});
if (!res.ok) return { ok: false, error: 'confirm_failed' };
const order = await res.json();
return { ok: true, order_id: order.id, status: order.status };
}
});
})();
This pattern keeps secrets and raw payment data out of tool parameters and forces an explicit UX checkpoint before mutation.
4) Express the real schema of your form, not the DOM
Your checkout form might have 20 inputs, but an agent only needs the decision‑bearing fields. Keep schemas stable even if the DOM shuffles. Examples:
sign_in:{ email, password }update_profile:{ display_name, phone? }create_ticket:{ subject, body, priority? }
Avoid free‑form additionalProperties: true; it invites guesswork.
5) Return verifiable outcomes
Agents then decide next steps. Good responses:
{ ok: true, cart_total_items: 3 }afteradd_to_cart{ ok: true, results: [...], count: n }aftersearch_products{ ok: true, order_id: 'A123', status: 'placed' }afterconfirm_order
Bad responses:
- Huge HTML chunks
- “Success!” without machine‑readable fields
6) Keep descriptions crisp and directive
Describe: when to use; preconditions; side effects; limits. For example:
- “Use to start checkout. Preconditions: cart has at least one item. Side effect: navigates to checkout page.”
- “Use to update quantity of an existing cart line. Requires
line_idfrom a prioradd_to_cartorget_cartcall.”
7) Test with an agent that actually calls tools
As of now, ChatGPT desktop and ChatGPT Work call page tools in our own testing. Broader support is evolving—track at the ecosystem status page. For a systematic process to validate flows, see WebMCP for testing.
A basic manual test loop:
- Open your site in the ChatGPT desktop app webview.
- Ask it to “Search for ‘running shoes’, add the cheapest size 10 men’s to cart, and start checkout.”
- Watch for tool picks, inputs, and results.
- Iterate on descriptions and schemas until selections are reliable.
8) Instrument and observe
If you use Agent Layer, you get analytics per tool call (which agent, duration, success/error) and test scenarios that assert “intent X picks tool Y.” This reduces guesswork and catches regressions.
9) Plan for drift
DOMs change; your tools shouldn’t. Bind tools to your app logic, not fragile selectors. If a UI change breaks a binding, Agent Layer’s health checks suggest the new selector and let you roll back a config version.
For a step‑by‑step enablement flow, see How to enable WebMCP on your website.
Example: cart and checkout tool set
Below is a compact set that covers the cart funnel end‑to‑end.
(function cartAndCheckoutTools() {
const mc = document.modelContext ?? navigator.modelContext;
if (!mc) return;
mc.registerTool({
name: 'get_cart',
description: 'Read current cart summary. No side effects.',
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
execute: async () => {
const res = await fetch('/cart');
const cart = await res.json();
return {
ok: true,
total_items: cart.total_items,
lines: cart.lines.map(l => ({ line_id: l.id, title: l.title, qty: l.quantity, price: l.price }))
};
}
});
mc.registerTool({
name: 'update_cart_line',
description: 'Change quantity of a cart line. Requires a valid line id. Side effect: mutates cart.',
inputSchema: {
type: 'object',
properties: {
line_id: { type: 'string', minLength: 1 },
quantity: { type: 'integer', minimum: 0 }
},
required: ['line_id', 'quantity'],
additionalProperties: false
},
execute: async ({ line_id, quantity }) => {
const res = await fetch('/cart/update', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ line_id, quantity })
});
if (!res.ok) return { ok: false, error: 'update_failed' };
const cart = await res.json();
return { ok: true, total_items: cart.total_items };
}
});
mc.registerTool({
name: 'start_checkout',
description: 'Begin checkout for the current cart. Preconditions: cart has at least one item. Side effect: may navigate.',
inputSchema: { type: 'object', properties: {}, additionalProperties: false },
execute: async () => {
// Optionally navigate, but also return a machine-readable state
window.location.assign('/checkout');
return { ok: true, phase: 'checkout_started' };
}
});
})();
Flow of an agent calling a guarded action
The diagram shows how an agent discovers and calls a guarded tool with human confirmation.
Coverage checklist by funnel stage
| Stage | Tool name | Must accept | Must return | Guardrail |
|---|---|---|---|---|
| Discovery | search_products |
query, optional limit |
items[] {id,title,price,url}, count |
None |
| Cart | add_to_cart |
variant_id, optional quantity |
cart_total_items |
None |
| Cart | update_cart_line |
line_id, quantity |
total_items |
None |
| Checkout | start_checkout |
none | phase: 'checkout_started' |
None |
| Checkout | confirm_order |
shipping_method, payment_method_id |
order_id, status |
Explicit user confirmation |
| Account | sign_in |
email, password |
ok, user_id or error |
Consider confirmation if risky |
For commerce specifics (e.g., Shopify sections and events), see the practical setups in WebMCP for Shopify and the broader strategy in Agentic commerce for Shopify.
What you can do without Agent Layer
You can hand‑roll everything above: register tools, maintain schemas, and test in agents that support WebMCP. This works, especially for a small surface area.
Where people add Agent Layer is when the surface grows:
- Health checks catch when a UI change breaks a selector and propose a fix.
- Guardrails are standardized for sensitive flows.
- Versioned configs: ship, roll back, and A/B test tool definitions.
- Analytics: see which agents called what, how often, with which errors.
- Test scenarios: encode “intent → expected tool” and run them.
Common pitfalls
- Skipping feature detection: only checking
document.modelContextand missing agents that still look atnavigator.modelContext. - Vague descriptions: “Search the site” without limits or preconditions → agents guess.
- Oversharing: returning entire cart objects or HTML; keep results small and stable.
- No guardrails on sensitive actions: letting an agent confirm an order without a user click.
- Schema drift: tool schemas changing every time the DOM changes; keep schemas stable and decoupled from markup.
- Hidden required fields: form requires an anti‑bot token or hidden checkbox not represented in the tool → calls fail.
- Relying on scraping as a fallback: some agents will try, but it’s brittle. See why in Why DOM scraping and vision models are dead for agentic web workflows.
- Testing in the wrong environment: using an agent or browser that doesn’t support WebMCP yet. Check the ecosystem status first.
What breaks in production
- UI drift: class or structure changes break bindings that tools rely on. Health checks or alerts catch this early.
- State assumptions: agents call
start_checkoutwith an empty cart. State preconditions should be checked inexecutewith clear errors. - Rate limiting and bot challenges: CAPTCHAs or strict WAF rules can block in‑page calls, especially during checkout. Prefer first‑party in‑page APIs and keep flows human‑initiated when required.
- Partial rollouts: staging and prod diverge; a tool works in staging but not prod. Version configs and test both.
- Multistep ambiguity: multiple tools that could satisfy an intent (e.g.,
apply_coupon,update_cart_line,start_checkout) without clear descriptions. Disambiguate with “Use when …”.
Try it
Start by running the free agent‑readiness audit on your site. It flags missing WebMCP tools, unlabeled inputs, and other blockers, and suggests page‑by‑page tool definitions. Then test your high‑intent forms with an agent that calls tools today, and watch the ecosystem tracker as support broadens. When you’re ready to harden things—guardrails, drift protection, versioned configs—Agent Layer takes over the maintenance load.

