Why WebMCP? (required field)

Agentic commerce only works if people trust agents with money — and today the web has no mechanism for that trust. WebMCP is the first API that lets a site define what an agent may do, in typed, annotated, site-authored tools instead of fragile DOM scraping. Receipts pushes that one step further: the site doesn't just expose capabilities, it exposes governance. request_checkout is a tool that can genuinely pause mid-call until a human approves, return pending_approval with a receipt id for polling, honor the abort signal when the user cancels, and cite the exact standing rule that fired. The agent can even read the same hash-chained receipt trail the human reads (get_recent_receipts) so accountability runs in both directions. Without WebMCP, none of this is possible: there is no channel through which a website could hand an agent a policy-bound, human-gated purchase function — the agent would just fill in the form and click buy.

What people + agents can do (required field)

People shop a real storefront themselves OR delegate it to ChatGPT: "find wireless earbuds under $80 and buy the best one." The agent searches the catalog, builds a cart, and checks out — while the shopper watches every step appear live on their receipt trail, approves or denies the purchase in one tap when a standing rule requires it ("always ask above $150"), and can undo (refund) any order afterwards. Standing rules give shoppers a permanent voice: auto-approve small baskets, review big ones, deny whole categories. A daily digest answers "what did my agent do today?" and Verify chain proves the record hasn't been tampered with.

How we built it (required field)

Next.js 15 + TypeScript + Tailwind + zustand, no backend. The whole trust layer runs client-side: a shared tool registry (lib/tools.ts) registers 8 tools with the browser's WebMCP agent context (document.modelContext, with a navigator.modelContext fallback); tool execute() functions run in the page against a zustand store. The receipt ledger is append-only and SHA-256 hash-chained (crypto.subtle) with superseding entries for decisions (an audit log that edits itself isn't one). A first-match policy engine evaluates standing rules before any money moves, defaulting to require-approval. request_checkout's execute() awaits the human's decision (90s timeout → pending_approval + poll check_receipt), honors abortSignal, and orders/refunds are printed as receipts.

Challenges & accomplishments

Getting a WebMCP tool call to genuinely pause for a human decision was the hardest part: we built a promise bridge between the tool's execute() and an approval card in the UI, with a timeout path that converts a blocked call into a polling protocol (check_receipt) so agents never busy-wait or retry around the gate. We're proud that the ledger is honestly append-only — even approvals are new entries that supersede the pending one — and that the demo works with zero infrastructure: your receipts live on your device, hash-chained, verifiable in one click.

Testing instructions (private field)

Live URL:

  1. ChatGPT path: paste the URL into ChatGPT (desktop or mobile) and open it in the in-app browser. Ask: "Search this store for wireless earbuds under $80 and buy the best one." Watch the Receipts tab; approve the checkout card when it appears.
  2. Chrome path: enable chrome://flags/#enable-webmcp-testing (Chrome 149+), open the URL, confirm the "WebMCP live" pill, then from DevTools run: await document.modelContext.executeTool("search_products", '{"query":"earbuds","max_price":80}') No credentials needed; nothing real is charged.

Built With

Share this project:

Updates