WebMCP Tools for Agent-Ready Web Apps
Expose origin-bound browser tools with explicit permissions, lifecycle cleanup, semantic fallback, and human takeover.
WebMCP tools should expose the smallest useful verbs a web app can defend, not its entire DOM as an automation playground. The browser remains a human workspace, so origin, permission, lifecycle, and takeover must be part of every tool contract.
This tutorial turns a checkout demo into three bounded tools—inspect cart, apply approved coupon, and prepare order—without granting background purchase authority.
WebMCP tools begin with product verbs
A checkout page already contains dozens of controls, fields, and events, but an agent does not need a synthetic click for each one. It needs stable product verbs with narrow meaning: inspect cart reads named items and totals; apply approved coupon validates one code and returns a pricing delta; prepare order validates shipping and creates a reviewable summary without purchasing. WebMCP tools should model those contracts rather than mirror the page tree.
This distinction survives redesign. A button may move, a cart may become a drawer, and address entry may use a new component, while the tool's purpose remains stable. Define inputs, outputs, preconditions, side effects, error states, and user-visible consequences. If a verb cannot be explained without “whatever the current page does,” it is not ready to become an agent tool.
Agent-ready web apps benefit from a verb inventory written beside the ordinary interface. If a proposed tool has no human-visible equivalent, owner, or consequence description, it probably represents internal plumbing rather than a safe product capability.
Read WebMCP as an evolving browser proposal
The live WebMCP specification is the primary description of the browser-facing surface, while the upstream repository exposes issues and implementation context. The branch-qualified Bikeshed source makes exact definitions reviewable beside changes. Pin a commit or dated snapshot in prototypes because browser proposals can change before broad interoperability exists. Store that commit with the browser version and feature flag used by the compatibility fixture.
Treat every unsupported environment as normal. The app still needs ordinary semantic HTML, keyboard behavior, labels, validation, and documented APIs. WebMCP tools are progressive enhancement for an agent-capable browser, not a replacement for the human interface. Feature detection should decide whether to register, while the same application services enforce business policy on both tool and manual routes.
Track proposal revision, implementation flag, and fallback behavior as three separate facts. The browser-tool proposal can evolve while the page remains dependable, provided experimental registration never becomes the only route to a core task. Record the tested commit and exposed capability names in the fixture.
Bind registration to the active origin and document
A tool belongs to a particular origin, document, authenticated session, and application state; record all four when registering. If navigation changes the origin or replaces the document, the old registration must stop being callable. If the user signs out, an inspect-cart call should fail as unauthenticated rather than reading cached state. WebMCP tools should never float free of the page whose UI explains them.
Single-page applications complicate lifecycle without changing the principle. Route transitions may preserve the document but invalidate a page-scoped action. Register from an owner component, update only with a versioned contract, and unregister during cleanup. Attach a route or state predicate to every invocation so a delayed call cannot operate against a screen the user has left.
Browser tool registration should be reconstructed after navigation, authentication change, or document replacement. Origin-bound tools must fail with a neutral unavailable result when their original page context no longer exists.
Ask permission at the consequence boundary
Reading a visible cart is different from applying a price-changing coupon, and both differ from placing an order. Permissions should follow those consequences instead of collapsing into one “control this site” grant. The browser and app can allow low-risk inspection for the current tab, request explicit approval for a mutation, and always require a final human review for purchase. A prior grant should have a visible scope and revocation path.
The failure mode is permission fatigue caused by prompting for every harmless read. Its opposite is an overbroad session grant that hides meaningful effects. Group related low-risk operations under a clear purpose, then interrupt only when authority expands. WebMCP tools should return a proposed order with price, destination, payment label, and expiry; the ordinary UI owns the final confirmation control.
Human-controlled automation asks close to the irreversible step, not at initial page load. A permission to inspect a cart cannot silently expand into permission to apply discounts, reserve stock, or submit payment.
Make the human interface the shared source of truth
Tool and manual routes should call the same validation and state transition services. When apply-coupon succeeds, the price change appears immediately in the cart with an announcement and undo path. When it fails, the same field error and policy explanation appear whether the request came from a person or an agent. Hidden background state invites disagreement between what the agent reports and what the user sees.
Human takeover must be cheap. Focus should remain stable during read operations, and mutation requests should identify the affected region without stealing the keyboard. A visible activity strip can show the tool name, origin, proposed or completed state, and stop control. WebMCP tools earn trust when the person can understand, interrupt, and continue the same workflow without decoding an agent transcript.
Use the same domain command and validation result for clicks and tool invocations. That shared core keeps agent-ready web apps from developing an easier, less observable business path than the interface people use.
Return bounded data instead of page snapshots
Inspect-cart returns stable product IDs, display names, quantities, unit prices, currency, subtotal, applied discounts, and a cart version. It does not return account tokens, hidden DOM, analytics attributes, or every text node on the page. Inputs also carry the expected cart version so a mutation refuses stale assumptions. This is a product API shaped for the current browser context.
Keep response size and sensitivity bounded. Large tables should paginate through stable cursors, and private fields should follow the authenticated user's existing visibility. If the tool needs a record not represented on the current page, call an authorized application service rather than scraping it from a hidden component. The web app should know exactly which data leaves each invocation and be able to test that allowlist.
Return named fields with size limits, freshness, and redaction notes. WebMCP should expose enough structured context to complete the verb while refusing broad page snapshots that capture unrelated account or advertising data.
| Tool | Effect | Human control | Fallback |
|---|---|---|---|
| Inspect cart | Read | Visible activity | Cart page |
| Apply coupon | Price mutation | Undo + notice | Coupon form |
| Prepare order | Proposal | Review summary | Checkout |
| Purchase | External effect | Not registered | Confirm button |
Design retries and cancellation before automation
Read operations may retry under a short budget when the error is transient. Mutations need idempotency keys tied to their business lifecycle, not a generic request retry. Prepare-order can create the same review proposal twice without purchasing twice; place-order, if ever exposed, would require a distinct confirmation and durable receipt. Cancellation stops in-flight work when possible and always prevents a late result from changing abandoned UI.
WebMCP tools should report started, waiting-for-user, completed, cancelled, rejected, and indeterminate states. Indeterminate matters when a network interruption occurs after a server may have accepted an effect. The UI then reconciles by operation ID rather than guessing or inviting a second click. This is the difference between an agent-ready app and a brittle macro over clickable elements.
Retries need a stable invocation ID and a visible status. Human-controlled automation should surface pending, accepted, cancelled, and unknown outcomes so a person never repeats a consequential action merely because the assistant lost its response.
Test hostile timing and origin changes
Open two accounts in separate tabs, register the same tool names, navigate one tab, sign out the other, change the cart between read and mutation, revoke permission mid-call, abort during validation, and destroy the component before a late response. Every result should stay attached to the correct origin, tab, session, document, route, and cart version. Run the same contract with browser tool support disabled; the human checkout must remain complete.
The supporting patterns are covered by agent-ready API specifications, interaction state foundations, idempotency lifecycle contracts, and human escape hatches. Those articles provide durable service semantics beneath the browser registration surface. WebMCP becomes safer when it exposes an existing product contract rather than inventing a parallel one.
Simulate a cross-origin redirect, back-forward restoration, session expiry, and teardown during invocation. The tool must either finish under the original contract or stop cleanly; it cannot migrate authority into the next document. Preserve the stop reason in its audit receipt.
- 1Register
Bind tool to origin, session, and route.
- 2Request
Browser checks permission and activity.
- 3Validate
Application checks version and policy.
- 4Reveal
UI shows result and preserves takeover.
Publish a tool register people can challenge
Ship a register listing tool name, product purpose, origin scope, lifecycle owner, inputs, outputs, permissions, side effects, idempotency behavior, cancellation semantics, human fallback, retention, and audit event. Add examples for denied, stale, cancelled, and successful calls. A browser fixture should prove that old registrations disappear after navigation and that a purchase cannot occur without the ordinary confirmation route.
WebMCP tools make a web application agent-ready when they reduce ambiguity while preserving human agency. Start from stable verbs, bind them to active context, expose minimum data, separate permission tiers, and keep visible UI synchronized with every effect. The result is more robust than DOM automation and more humane than an invisible API because the person and agent operate on one inspectable product state.
Runnable artifact: The lifecycle fixture permits an invocation only for the expected origin, an active registration, and an explicit granted permission. Save it as webmcp-lifecycle-gate.test.mjs and run node webmcp-lifecycle-gate.test.mjs. Expected final line: PASS: browser tool lifecycle bounded.
import assert from "node:assert/strict";
const invoke=({origin,active,permission})=>origin==="https://shop.test"&&active&&permission==="granted"?"call":"deny";
assert.equal(invoke({origin:"https://shop.test",active:true,permission:"granted"}),"call");
assert.equal(invoke({origin:"https://evil.test",active:true,permission:"granted"}),"deny");
assert.equal(invoke({origin:"https://shop.test",active:false,permission:"granted"}),"deny");
console.log("PASS: browser tool lifecycle bounded");
The finished registration surface contains three verbs and one deliberate omission: purchase remains in the visible checkout. WebMCP tools read or prepare application state through the same services as the human interface, revalidate origin and version at invocation time, and leave every accepted change visible with a stop or undo path. This is enough capability to help without converting a browser tab into unattended commerce infrastructure.
Review the tool register with design, accessibility, security, and support rather than treating it as API-only work. Each group should be able to explain a denied call, an expired permission, a stale cart, a cancelled mutation, and a manual continuation from the same screen. Keep one feature-disabled fixture in CI and one full keyboard transcript in the release evidence. Revisit the surface when browser lifecycle rules, session architecture, product verbs, or effect policy changes.