Inspiration
I got inspired by wanting to enable WebMCP in other SaaS products I manage, but I couldn't ensure users's properly controlled consequential actions (CRUD, for example), even after login gates.
Via browser control, each keystroke and click is just the agent impersonating, so the site genuinely can't tell you from your agent and that's dangerous for anything consequential. WebMCP allows to change the premise by operating as the declared channel, so the page knows the call came from an agent. Honest attribution is the thing that finally makes it safe to insist on the human for the steps that need one
What it does
3way turns a website into a shared, attributed session for three participants: you, your own AI agent, and the site's agent/scripts. Your agent discovers the site's tools on document.modelContext and works on your behalf, in an open ledger where every line is stamped with who said it. That is three-way trust: the site knows who's really acting, your agent knows it's calling the site's real declared tools, and you keep the final say. Routine steps happen agent-to-agent, in the open. The consequential ones — a refund, a records release, a purchase — are gated behind a WebAuthn hardware gesture (Touch ID / a passkey / a 2FA) that no agent can produce. The default is Keyholder mode: the two agents transact in the open ledger and your only action is to authorize. The same layer runs a shop and a medical-records clinic over one codebase, to prove it isn't about shopping — it's about any consequential action a person delegates to an agent.
How we built it
One tool registry, three consumers. Every tool is defined once and exposed to (a) the visiting agent via WebMCP, (b) the site's own agent via the OpenAI Realtime API, and (c) the page UI — so a consequential action follows one code path whoever starts it. Authorization lives in three checks, and only the last one counts: an advisory gate for a fast, legible refusal; a WebAuthn ceremony that records consent; and an authoritative Cloudflare Worker (/api/act) that validates a single-use token bound to (tool, requestId, deviceId) and re-derives eligibility from its own seed data, never from the request body. Sensitive data lives server-side and is returned only after a verified gesture.
Challenges we ran into
-The main one. OpenAI/ChatGPT app still support WebAuthn so we demoed via Chrome, this is surely a feature to allow very soon as the protocol matures.
Other:
- A click is not evidence. We had to prove
isTrustedis worthless as a boundary (CDP-driven input reportstrue) and move all authority to the hardware gesture. - WebMCP is pull-only — a page can't wake a visiting agent. A real agent, told to wait, ended its turn instead. So we built the gate to hold the line: a gated call is held open (bounded) until the person acts, answering the exact call that asked. After multiple tests we got 100% success rate, virtually resolving in modern frontier models the need for a true exchange between agents, stable, without latency.
- Agents still don't lean into discovering WebMCP affordances in the websites. We intuit this is also something that will evolve as the protocol is widely adopted, but for now, many agents need the nudge to search for and prioritize using WebMCP if available.
Accomplishments that we're proud of
- A consequential action that an agent provably cannot complete alone — measured, not asserted.
- Domain-neutrality shown, not claimed: shop and clinic on one gateway, identical transcript, origins, refusal shape, and gate.
- In the clinic, restricted records (mental health, substance use, genetic) are impossible for an agent to release — refused at the tool and excluded at the authoritative Worker.
- Shipped as a reusable layer, not just a demo: a drop-in library (one script tag, zero install for the user), the primitives (participant attribution, the WebAuthn gate, an authoritative Worker), and the conventions (the refusal shape) — ready to become a standard part of WebMCP.
What we learned
Attribution is the enabler for trust. Once the page can honestly tell an agent's call from a person's, you can stop trying to detect humans heuristically and instead require the one thing only a human has — a hardware gesture. Gates must read stamped fields, never prose; no authorization may depend on a model having understood a sentence.
What's next for 3way
The honest gap: none of our mitigations can wake an agent that never chose to wait — that's a spec ask we've written up; we suggest expanding the WebMCP to fully accommodate its usability as an A2A exchange.
Built With
- ai-agents
- chrome
- cloudflare-kv
- cloudflare-pages
- cloudflare-workers
- css
- document.modelcontext
- gpt-realtime
- html
- javascript
- model-context-protocol
- openai
- openai-realtime-api
- passkeys
- shadow-dom
- tsup
- typescript
- vitest
- web-components
- webauthn
- webmcp


Log in or sign up for Devpost to join the conversation.