What it is
Dorothy is 81 and has macular degeneration. A normal grocery site is a wall of tiny text, filters, modals and a checkout with nine fields she cannot see. Handrail is the same store exposed as WebMCP tools, so her agent can run the whole flow, plus a screen built so she can still see and confirm the one thing that matters: what am I buying, for how much, and when does it come?
Live: https://handrail-fawn.vercel.app · Code: https://github.com/chinesepowered/handrail
Why this is a strong fit for WebMCP
This is the purest case for the standard. Agents driving a store by screenshots and clicks fail exactly the people who need them most, because the UI they are fighting is the same UI the person cannot use. Handrail exposes twelve structured tools with document.modelContext.registerTool:
get_profile, search_catalog, add_to_cart, set_quantity, remove_from_cart, get_cart, list_delivery_slots, set_delivery_slot, confirm_with_person, place_order, get_orders, reorder_last
The interesting one is confirm_with_person. It puts a huge summary on screen, reads it aloud, and blocks until the person taps Yes or No; the tool's promise resolves with their answer. place_order refuses unless a confirmation happened in the last three minutes. The agent gets the whole workflow; the person keeps the commit, and that guard lives in the tool boundary, not in a prompt.
How it creates a better experience
- Say it once. "My usual groceries and something for a sore throat, Tuesday morning" becomes a profile read, seven items from her usuals, a catalog search that picks lozenges, a delivery slot, and a spoken summary. Fourteen tool calls; zero taps until the confirmation.
- See only what matters. Atkinson Hyperlegible at 20px with A− / A+ scaling, a true high-contrast mode (black, white, yellow), 44–72px targets, visible focus rings,
aria-liveon the confirmation and on agent replies, voice in (Web Speech API) and spoken replies on by default. - Trust. Every agent action is listed as a tool call with arguments; the order tracker updates as the order moves; "When is it coming?" is answered from
get_ordersin one sentence.
What people and agents can do together that was hard before
Before: a family member places the order, or Dorothy phones the store, or an agent "browses" the site and gets lost in a cookie banner. Now: Dorothy speaks, the agent assembles, Dorothy confirms. The division of labour is explicit and enforced by the tools: the agent may fill the basket and choose a slot, but it cannot spend her money without the sheet and the tap.
How WebMCP is implemented
lib/webmcp.ts: registry that callsdocument.modelContext.registerTool(..., { signal })for each tool and unregisters viaAbortControlleron unmount. Native calls from the browser agent and calls from the in-page agent share oneexecutepath and one activity log.lib/tools.ts: the twelve tools with JSON Schema inputs and read-only / destructive annotations.confirm_with_person'sexecuteisasyncand awaits the store's confirmation promise.lib/shop.ts: catalog, profile, cart, slots, orders, the confirmation gate, and theplace_orderguard.components/AgentPanel.tsx+app/api/agent/route.ts: a Gemini function-calling loop that discovers the registered tools and dispatches through WebMCP, with voice in/out and a model fallback chain for free-tier limits.
Tested in Chrome 153 with chrome://flags/#enable-webmcp-testing (DevTools → Application → WebMCP lists all twelve tools) and with the in-page Gemini helper.
Demo store with fake prices; nothing is purchased.
Stack
Next.js 16 · Tailwind 4 · Atkinson Hyperlegible · Web Speech API · Gemini function calling · WebMCP · Vercel
Built With
- gemini
- next.js
- react
- tailwind
- typescript
- vercel
- web-speech-api
- webmcp
Log in or sign up for Devpost to join the conversation.