What it is, and why WebMCP (the use case)
In-browser AI agents act on websites by guessing at the DOM — brittle selectors, scraping, silent failures, no way to verify what happened. WebMCP fixes that at the platform level: the page declares tools, the agent calls them. But it only matters if sites actually implement it, and hand-wiring agent tools for every page of every site does not scale.
Cartwright is an open-source (MIT) engine that scaffolds complete stores — design system, database, cart, checkout, admin, i18n — with one command. During the challenge window we made the engine WebMCP-native: webshop templates now scaffold with the surface ON (npx create-cartwright my-shop --template coffee → a store whose every page registers typed, page-contextual tools via document.modelContext the moment an agent-capable browser opens it). Not one agent-ready site — a generator of them. Shopify has shown storefront-scale WebMCP for its hosted platform; this is the same idea for the self-hosted, open-source world: the whole engine is MIT, and every scaffold owns its stack.
WebMCP leverage — the depth of the surface
13 tools on the demo shop, three registration styles, one shared core:
- Site-wide (imperative):
search_products(reduced, bounded rows — no checkout endpoints or internal fields ever enter the browser surface),get_cart(verification-rich returns: line handles, stock ceilings, structured money), same-originnavigate. - Contextual, per route — progressive disclosure (the shape proposed in the tool-collections discussion, webmcp#255): an agent only ever sees the collection that makes sense on the page it is on. The product page registers
add_current_product_to_cartwith the page's live variants as natural-language enum values ("Whole beans, 250 g" — not internal ids), prices and stock in the descriptor. The cart page registersupdate_cart_item_quantity/remove_cart_item(line ids enumerated in the schema) /go_to_checkout. The catalogue page registerslist_visible_products(exactly what the human sees, zero network) andfilter_products(schema server-derived from the live categories). - Declarative forms: search, contact and newsletter carry
toolname/tooldescription/toolparamdescriptionattributes — the form itself is the tool, answered viaSubmitEvent.respondWith(preventDefault-first).toolautosubmitonly on read-only search; the human confirms communication. Agent activity is visible::tool-form-activestyling highlights the form the agent is filling. - Design-pack tools: the homepage brew calculator is also
calculate_brew_ratio— the same math module serves the human's widget and the agent's tool, so the two can never disagree. Any design pack can ship tools (DesignPack.webMcpToolBindings); the safety tests aggregate them all.
The engine also answers the frameworks meta-issue (webmcp#199) in shipped, test-pinned code: execute() reads state freshly at execution time (never captured props); effect dependencies are serialized props, so re-renders never thrash the registry; every mount owns an AbortSignal and cleanup runs before the next route's registrations (abort-then-register, the current-spec-safe order — our e2e fake rejects duplicate names, and a soft-navigation spec proves the swap inside one document); one rejecting registration cannot drop the tools after it.
One governed tool registry, two transports: the same operations back the in-page WebMCP tools for browsing agents and a server-side MCP endpoint (/api/mcp) for headless agents — same session, same state in the browser; same scopes and audit trail on the server. Beneath the callable layer sits the readable and discoverable one: llms.txt with capability truth, JSON-LD on every citable page, content negotiation (the homepage serves markdown to agents that ask), an ARD catalog, OpenAPI — and on the payable side the engine carries protocol-pluralistic commerce rails (ACP endpoints and UCP identity-linking on the same engine), so the merchant doesn't have to bet. Readable, discoverable, callable, payable — one engine.
Execution — a complete product, tested like one
This is a production Next.js 16 App Router application deployed on Vercel: a real store with a live database, working cart and checkout, an admin, and i18n — not a mock. The WebMCP layer is held to the same bar:
- ~100 unit tests across the registrar, the per-route mounts, the declarative forms, the pack tool, and the safety moat (below).
- A Playwright e2e suite installs a faithful fake
document.modelContext(current spec semantics: duplicate-name rejection, pre-aborted-signal rejection) and walks home → catalogue → product → cart → checkout, including one real add-to-cart round-trip against the database and a soft-navigation leg that proves route teardown inside one document. - Evaluation-driven, with the Chrome team's own harness: we ran GoogleChromeLabs/webmcp-tools'
webmcp-evals(smoke mode) against the live demo — 12/12 steps green across brew-ratio, cart reads, catalogue listing/filtering, search, a real add-to-cart and the checkout handoff (runner[email protected], repo commitd39eae4, 2026-08-27). The run's three genuine findings (a prefetch loop on the empty-cart page, non-canonical URLs in two tool returns, Danish parameter names on an English store) were fixed the same day — the eval harness caught real bugs, which is the point of running it. - Byte-identity discipline: with the flag off, no registrar mounts, no
tool*attribute renders, the HTML is byte-identical — pinned by tests. - The live surface is smoke-monitored: the store's deployment gate asserts
/en/webmcp-checkand the pack tool on every run.
Potential impact — who this is for
Every small store that will never hand-write agent tools. The economics only work at the engine level: implement WebMCP once, correctly, with tests — and every scaffolded site inherits it. The demo is a real storefront a judge can buy from (demo checkout), running the exact code a scaffold produces. And the scaffold proves it in a first minute: npx create-cartwright myshop --template coffee && cd myshop && npm run dev seeds the demo's own nine-product catalogue — images, stock, attributes, and real variants on one product (an agent must handle both shapes) — so the tools have something true to act on with no config and no API keys. The same engine runs a second live vertical (eyewear, different design pack, Danish locale) — the surface is engine-level, not bespoke to one demo.
Creativity & ambition — the line we drew
The collaboration model is explicit: the agent gets the errands, the human keeps the decisions.
- Every cart mutation returns the fresh cart, so the agent verifies instead of assumes; an ambiguous mid-request failure says so and routes the agent through
get_cartbefore any retry. - Communication forms never autosubmit — the agent fills, the human sees the copper glow on the form, the human confirms.
- The purchase is deliberately out of the agent's hands: a test-enforced safety moat holds the entire browser surface — across the layout, every per-route mount, and every registered design pack — to the cart/catalogue tool families. No order-placing tool exists in the browser.
go_to_checkoutopens the page; the checkout form is annotated for no one. Graceful handoff, in the commerce-protocol sense: the agent escorts the human to the door it cannot open. /en/webmcp-checkdocuments the shop's own agent surface — generated from the same constants the moat test verifies, so the page structurally cannot lie — with an intent-first explorer ("I want to… → the tool + a copyable example") and the Chrome team's polyfill as fallback so it demonstrates in any browser.- And the agent-experience layer is measured, not asserted: every change to the store's agent surface (WebMCP, MCP, llms.txt, discovery files) ships through tests + live smoke, and the store publishes machine-readable pricing, auth and capability truth alongside the tools.
Prior work vs. this submission (per the rules)
The engine — storefront, cart, checkout, admin, server-side MCP/REST APIs — pre-exists the challenge, as does a four-tool WebMCP experiment from June 2026 (v0.25.0: global search/add/get-cart/navigate behind a flag). The entire WebMCP surface submitted here was designed and built inside the submission window (Aug 27 – Sep 3, 2026): the shared registration core, contextual per-route tools, declarative form annotations, catalogue tools with server-derived schemas, design-pack tools with registry-aggregated safety tests, the moat, the e2e suite, the eval run, /webmcp-check, and the WebMCP-native scaffold default.
Public, timestamped evidence (the repo publishes snapshot syncs + release tags):
- Tag boundary:
v0.49.0(Aug 24, pre-window baseline) →v0.50.0/v0.51.0(Aug 27, in-window release). - Pre-window snapshot: https://github.com/Teloz1870/cartwright-template/tree/v0.49.0
- In-window snapshot and dated GitHub Release: https://github.com/Teloz1870/cartwright-template/tree/v0.51.0 and https://github.com/Teloz1870/cartwright-template/releases/tag/v0.51.0
CHANGELOG.md's dated v0.50.x/v0.51.0 blocks anddocs/webmcp.md's day-by-day timeline. (The public mirror intentionally publishes each sanitised snapshot as a root commit, so GitHub's compare view has no common ancestor; the two tagged trees above are the auditable boundary.)- npm:
create-cartwright2.7.15, 2.8.0 and 2.8.1 were all published Aug 27 (public registry timestamps). - Sep 3 (deadline day, in-window): engine
v0.54.0— the coffee scaffold now seeds the live demo's nine-product catalogue with variants, and the README leads with "Try the agent tools in 60 seconds" — published to npm the same day.
(OpenAI's challenge brief: "build a new agent-native web app, or add WebMCP support to an app you already run" — this is deliberately the second shape, documented.)
Built With
- mcp
- next.js
- prisma
- react
- stripe
- typescript
- vercel
- webmcp
Log in or sign up for Devpost to join the conversation.