The problem
Customer support sites can already know useful, authorized context about a customer: their service level, product setup, integrations, open issues, and escalation path. But an external browser agent normally does not have a structured, authorized interface to that state. It may guess from the page, fail to recover it, or push the work back to the person by asking them to repeat information the website already knows.
Never Ask Twice makes that gap explicit: the support site already knows; WebMCP gives the browser agent a typed, session-bound capability to use that knowledge.
What existed before this challenge
Never Ask Twice existed before the WebMCP Challenge as a B2B support-memory agent powered by Qwen. It already stored and recalled scoped customer context across support sessions.
The canonical pre-challenge baseline is commit c2997996bbd137a8acf7d08799e7d04b0c8dfd48, committed before the WebMCP submission period began. The WebMCP work was added after the challenge opened and is documented separately from the pre-existing memory system.
What I added during the WebMCP Challenge
I extended the existing site with a browser-native WebMCP surface built around two deliberately narrow tools.
get_support_context
A read-only capability that lets the current visitor's browser agent request only a bounded subset of support context: service level, product setup, integrations, open issues, and escalation contact.
The model cannot provide an account ID, customer ID, tenant ID, session ID, or fact ID. The server resolves scope from the current signed browser session instead.
update_escalation_contact
A single bounded mutation for correcting the current visitor's escalation contact. The agent can propose a replacement, but the site requires the person to explicitly confirm the displayed current and proposed values before persistence.
After confirmation, Never Ask Twice performs the correction atomically, supersedes the old current fact, records provenance, and independently rereads current support state. The tool reports success only after the replacement is observed. A cancelled confirmation produces no write.
While persistence and verification are pending, the confirmation surface locks into Saving and verifying… so repeated clicks, cancellation, dismissal, or background interaction cannot create an ambiguous operation. Completed confirmation IDs replay their existing result rather than writing again.
Why WebMCP is the right interface
This is not about making the site's own chatbot remember more. Never Ask Twice already had memory.
The WebMCP extension changes what an external browser agent can reliably do with the website's existing authorized state.
In a controlled ON/OFF comparison using the same visitor, same site, same support state, same question, and same browser-agent runtime:
What does support already know about our setup?
With WebMCP available, the agent independently selected get_support_context and answered from structured support state including the visitor's Gold service level, SSO requirement, Salesforce integration, and escalation contact.
With WebMCP disabled, no site tool was available. In that controlled run the agent's generic fallback did not recover the context and it asked the person to provide the information instead. That is a runtime-specific observed result, not a claim that generic browser inspection must always fail.
The UX delta is simple: the website already knew the answer; WebMCP let the browser agent use it without making the customer become the integration layer.
What people and agents can do together now
The browser agent can:
- select and call a typed support-context capability from natural-language intent;
- retrieve only the current visitor's authorized context;
- use structured support state instead of asking the person to restate it;
- check the current escalation contact before proposing a correction;
- propose one narrowly scoped correction when that contact is stale.
The person remains in control of persistence:
- the site displays the current value and proposed replacement;
- the person can cancel with no state change;
- the person must explicitly confirm before the write begins;
- the UI locks while the system saves and independently verifies the result;
- success is shown only after the replacement has been reread as current.
The final demo preserves the causal chain in one genuine external browser-agent take: support-context read, current-contact check, correction proposal, human confirmation, EXECUTED, OBSERVED, and a separate fresh read returning the replacement contact.
How WebMCP is implemented
The site registers its tools through the browser's native document.modelContext.registerTool surface, with a compatibility fallback for runtimes exposing the draft API under navigator.modelContext.
Security boundaries are enforced by the website, not delegated to the model:
- visitor identity is carried in a signed, HttpOnly, Secure, SameSite cookie;
- browser-facing tool schemas contain no tenant selectors;
- tenant scope is resolved only on the server;
- tenant-resolving routes do not expose wildcard CORS;
- mutations require positive same-origin evidence;
- returned customer-authored/model-distilled values are explicitly marked untrusted data;
- support-context output is bounded;
- the mutation uses a visitor-bound, short-lived confirmation record;
- duplicate completed confirmations replay their existing result rather than writing again;
- the correction is transactional and provenance-bearing;
EXECUTEDandOBSERVEDare separate states, and success is not reported as verified until the independent reread succeeds.
The page exposes a human-readable WebMCP Action Trace so the interaction can be inspected as REGISTERED, CALLED, SCOPED, RETURNED, CONFIRMATION_REQUESTED, EXECUTED, OBSERVED, CANCELLED, or REJECTED without pretending the UI knows more than the runtime actually reported.
Validation
The challenge work includes deterministic tests for tenant-selector rejection, signed-cookie scope, same-origin enforcement, output bounds, cancellation, rollback after injected failures, retry/duplicate behavior, atomic supersession, provenance, pending-state interaction safety, and post-commit readback.
The final focused/full verification passed before freeze, including the WebMCP security and mutation suites, TypeScript checking, and the repository boundary scan.
Live browser runs demonstrated both sides of the collaboration contract:
- Cancel: the agent proposed a correction, the site requested confirmation, the person cancelled, and the current contact remained unchanged.
- Confirm: the agent proposed a correction, the person approved it in the site's confirmation UI, the transaction committed, the application's internal reread produced
OBSERVED, and a later independent WebMCP read returned only the replacement as current.
Known limitations
This challenge extension exposes one bounded read capability and one bounded correction, not a generic memory editor. The support data used for judging is synthetic. Browser-agent behavior depends on the client/runtime, so the submission documents the tested browser/Inspector/model combinations rather than claiming universal agent behavior.
Built With
- drizzle-orm
- hono
- node.js
- pgvector
- playwright
- postgresql
- qwen-cloud
- railway
- typescript
- vitest
- webmcp