Skip to main content
Glama

Never Ask Twice

Never Ask Twice

The website already knows the answer. The browser agent can't reach it — until the site hands it over.

License: Apache-2.0 WebMCP Entry Runtime Live Demo

Live: https://neverasktwice.dev/chat — renders in any browser. WebMCP tools register automatically in a WebMCP-capable browser. Add ?webmcp=off to the same URL for the control condition.

Demo (2:42): https://youtu.be/YggGztPaWpkNever Ask Twice — The Website Already Knows. Real browser, real WebMCP invocation, no scripted footage.


The 15-second version

A support site holds real context about the person visiting it: their service level, their integrations, their open issue, who they escalate to.

A browser agent standing on that same page cannot reliably use any of it. It scrapes, it guesses, or it gives up and asks the human to type it in again — the exact thing the person came to the site to avoid.

WebMCP closes that gap. The site declares typed, authorized capabilities; the agent discovers and calls them.

Before this challenge

What the challenge window added

Existed

A support memory engine — working / episodic / semantic tiers, forgetting, budgeted recall — behind a chat UI and a stdio MCP server

Reachable by a browser agent

No. Context lived server-side behind a chat box.

Yes. Two typed WebMCP tools on document.modelContext

Agent can read context

Falls back to page inspection, then asks the human

Calls get_support_context, answers directly

Agent can correct context

Not possible

update_escalation_contact, gated on explicit human confirmation

Tenant safety

Convention

Mechanism — server-side scope, signed cookie, no model-supplied selectors

The pre-existing stdio MCP server is not WebMCP. It is a separate, non-browser surface that predates this challenge. Everything scored here is the browser-native work listed in the right column.

Related MCP server: Memsolus MCP Server

The two tools

Both are registered on the page via document.modelContext.registerTool. Neither accepts an account, customer, tenant, or session selector — scope is resolved server-side from a signed visitor cookie, so the model cannot name whose data it wants.

Tool

Kind

Arguments

Boundary

get_support_context

read

topics[] from a closed five-value vocabulary, optional

readOnlyHint, bounded output, result marked untrusted

update_escalation_contact

mutate

newContact, optional reason

Requires an explicit human Confirm and persist click; atomic supersession; independent readback before success is reported

Try it in 60 seconds

Open https://neverasktwice.dev/chat in a WebMCP-capable browser and watch the WebMCP Action Trace panel while you ask:

1 — Read. The prompt used verbatim in the frozen counterfactual:

What does support already know about our setup?

Trace: CALLED → SCOPED → RETURNED. The agent answers with Gold SLA, Salesforce, Priya — without asking you for any of it. Run the same prompt at /chat?webmcp=off and the agent asks you to paste it in.

2 — Confirmed correction. A mutation a human must approve:

Priya has left the account. Our escalation contact is now Marcus Chen — please update it.

Trace: CALLED → CONFIRMATION_REQUESTED → (you click Confirm and persist) → EXECUTED → OBSERVED. Cancel instead, and nothing is written. After committing, ask prompt 1 again — the old contact is gone and the new one is returned.

Evidence

Each gate is a frozen document with its raw log beside it. None of it is reconstructed after the fact.

Gate

Claim

Document

Raw

G1

A real browser discovered and executed the tool natively in Chrome

docs/webmcp-spike-evidence.md

webmcp-live-verification.jsonl

G2

Counterfactual — WebMCP ON vs OFF changes the user journey

docs/webmcp-counterfactual-comparison.md

webmcp-counterfactual-preconditions.jsonl

G3

Security — the agent's reach is mechanically tenant-bound

docs/webmcp-security-g3.md

webmcp-security-g3-negative-tests.jsonl

G4

Mutation — confirmed, atomic, reread before success

docs/webmcp-mutation-g4.md

webmcp-mutation-g4-negative-tests.jsonl

Each document states its own limits. G2 is one pair, one model, one question, and it does not claim browser agents cannot reach this data without WebMCP. G4 does not claim prompt-injection immunity.

Provenance

This is an Existing Project, meaningfully extended. The boundary is mechanical, not asserted:

  • Pre-challenge baseline: c2997996 — tagged baseline-pre-webmcp, zero WebMCP files.

  • All WebMCP work: 2026-09-01 → 2026-09-03.

git ls-tree -r baseline-pre-webmcp --name-only | grep -c webmcp   # 0
git log --oneline baseline-pre-webmcp..HEAD                       # the challenge window

Full table — baseline, challenge additions, deployed code and tree, deployment id, final commit: docs/webmcp-build-period.md.

Third-party assets: THIRD_PARTY_NOTICES.md.

Run it yourself

pnpm install
pnpm vitest run tests/webmcp-escalation-contact-g4.test.ts \
                tests/webmcp-security-g3.test.ts \
                tests/webmcp-support-context.test.ts   # 57 tests, no secrets needed

These are the deterministic security and state-transition tests behind G3 and G4 — selector rejection, cross-origin rejection, missing confirmation, rollback under injected failure, retry, and cross-visitor isolation. They need no database and no API key.

Full local setup (Postgres, migrations, live Qwen path) is in Local development below.


Pre-existing system — historical background

Everything in this section predates the WebMCP Challenge and is not submitted as challenge work. It is the system the challenge work extends.

Never Ask Twice was built for the Qwen Cloud Global AI Hackathon — MemoryAgent track (July 2026), where it was submitted as a B2B support memory agent.

Support that remembers. Customers don't want a smarter chatbot if they still have to repeat their SLA, setup, open issue, and escalation contact every time they come back.

The demo agent is Nat, powered by NATE — the Never Ask Twice Engine — a scoped memory layer that turns support conversations into durable, auditable customer context.

What makes it a MemoryAgent

  • Working memory — current-session context usable before session-close distillation.

  • Episodic memory — raw support events with Qwen embeddings and provenance.

  • Semantic memory — distilled customer facts with confidence, validity windows, and source links.

  • Forgetting policy — TTL expiry, supersession, stale-memory exclusion, audit-safe provenance.

  • Budgeted recall — relevant memories only, capped to a strict context budget.

  • stdio MCP surface — four memory tools for agent interoperability. (Not WebMCP.)

This is not transcript logging. It is structured memory with retrieval discipline, provenance, forgetting, and measurable cross-session improvement.

The deterministic eval harness

pnpm eval

Expected fixture output:

memory-on re-ask rate: 0.00
memory-on recall accuracy: 1.00
memory-off re-ask rate: 1.00
memory-off recall accuracy: 0.00
re-ask rate: 0.00 (memory) vs 1.00 (no-memory)

Read this as a fixture assertion, not a measurement. The harness is intentionally deterministic for reproducible scoring: fixed synthetic fixtures and a fake Qwen client. It is a regression guard on the memory policy, not a live benchmark, and it is unrelated to the WebMCP claims above. Details: docs/evaluation.md.

Prior-period status

Area

Status

Notes

Public clean-room repo

Done

Synthetic data only; boundary scan included.

Memory service

Done

Working, episodic, semantic, forgetting, budgeted recall.

stdio MCP surface

Done

Four memory tools via pnpm mcp:list-tools.

Qwen-backed live path

Done

/health reports mode: "qwen-live".

Railway deployment

Live — judge-clickable

neverasktwice.dev renders in a browser; re-verified 2026-09-02. See deploy/railway.md.

Alibaba FC deployment

Live — verify by curl

curl https://never-awice-api-kvsvpczulb.us-east-1.fcapp.run/health. Alibaba forces Content-Disposition: attachment on the free *.fcapp.run subdomain, so a browser downloads instead of rendering — platform policy, not a broken deploy. See deploy/alibaba-fc.md.

Qwen-hackathon demo video

Done — superseded

Watch — frozen Acme scenario, July 2026. This is not the WebMCP Challenge video. The challenge demo is above.

Build log

Done

Building customer support memory that survives an audit

Architecture

Browser agent (WebMCP)          Customer chat / stdio MCP
        |                                |
        v                                v
  document.modelContext            Hono API
  get_support_context      -->  /webmcp/support-context
  update_escalation_contact -->  /webmcp/escalation-contact/{propose,commit}
        |                                |
        +--------> scope resolved server-side from signed visitor cookie
                                         |
                                         v
                                  MemoryService
                                    |-- working memory
                                    |-- episodic memory  (+ Qwen embeddings)
                                    |-- semantic memory
                                    |-- forgetting: TTL + supersession
                                         |
                                         +--> Qwen Cloud (DashScope-compatible API)
                                         +--> Postgres + pgvector

Full diagram and component map: docs/architecture.md.

Brand assets

Logo files and usage rules: docs/assets/brand. Tagline: Support that remembers. Descriptor: Enterprise Support MemoryAgent.


Local development

1. Clone and install

git clone https://github.com/marcelle-labs/never-ask-twice.git
cd never-ask-twice
pnpm install

2. Configure environment

cp .env.example .env

Set DASHSCOPE_API_KEY for live Qwen-backed embeddings, distillation, and adjudication. The example is pre-filled for local Postgres on port 5433.

DATABASE_URL=postgresql://neverasktwice:neverasktwice@localhost:5433/neverasktwice
DASHSCOPE_API_KEY=your-key-here
QWEN_BASE_URL=https://dashscope-intl.aliyuncs.com/compatible-mode/v1
QWEN_CHAT_MODEL=qwen-plus
QWEN_EMBEDDING_MODEL=text-embedding-v3
QWEN_EMBEDDING_DIM=1024
MEMORY_TOKEN_BUDGET=1200

Without DASHSCOPE_API_KEY, the API boots in local-safe mode: zero-vector embeddings and empty distillation responses so the server runs without secrets. It does not perform real Qwen work.

3–7. Database, eval, and server

docker compose up -d   # Postgres on localhost:5433
pnpm migrate
pnpm eval              # deterministic fixture harness
pnpm boundary-scan     # clean-room scan
pnpm dev               # API on http://localhost:3000

API endpoints:

  • GET /health — health and capability status.

  • GET /webmcp/support-context — WebMCP read surface (same-origin, cookie-scoped).

  • POST /webmcp/escalation-contact/propose · /commit — WebMCP confirmed mutation.

  • POST /turn — append a customer/agent turn.

  • POST /sessions/:id/close — close a session and distill episodic → semantic.

  • POST /recall — recall a bounded memory bundle.

8. Run the stdio MCP server

pnpm build
node dist/src/mcp/server.js

Exposes recall_memory, write_memory, distill_session, and forget.

Project structure

  • apps/api — Hono API, local server, FC handler, and the /chat UI.

  • apps/api/src/webmcpWebMCP surface: support-context read, escalation-contact mutation, scope resolution.

  • src/agent — deterministic support-agent policy used by the eval harness.

  • src/contracts.ts — memory predicate enum, Zod contracts, shared types.

  • src/db — Drizzle schema and SQL migration string.

  • src/memory — memory service, stores, retrieval, supersession, forgetting.

  • src/mcp — stdio MCP surface over the shared memory service.

  • src/qwen — single Qwen Cloud client module.

  • src/testing — deterministic fake Qwen client.

  • eval — frozen three-session scenario, ground truth, expected output, runner.

  • scripts — boundary scan, migration, MCP list-tools, WebMCP security evidence.

  • docs — architecture, memory model, evaluation, forgetting, and all WebMCP evidence.

  • deploy — Railway and Alibaba FC deployment proofs.

Key commands

Command

Purpose

pnpm install

Install dependencies

pnpm build

Build the project

pnpm lint

TypeScript type check

pnpm test

Full test suite

pnpm eval

Deterministic memory ON/OFF fixture harness

pnpm migrate

Run database migrations

pnpm boundary-scan

Clean-room boundary scan

pnpm mcp:list-tools

List the stdio MCP tools

pnpm demo:script-check

Verify demo fixtures are aligned

Security and clean-room boundary

Never Ask Twice uses synthetic data only. Do not commit real customer data, secrets, .env files, or private platform identifiers. The repository includes a boundary scan that fails on known forbidden tokens, and a local-safe mode so judges can run the server without secrets.

See SECURITY.md and docs/webmcp-security-g3.md.

License

Apache-2.0 — see LICENSE. Third-party notices: THIRD_PARTY_NOTICES.md.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides AI agents with persistent, searchable memory that survives across conversations using semantic search, temporal versioning, and smart organization. Enables long-term context retention and cross-session continuity for AI assistants.
    14
    -
  • A
    license
    A
    quality
    D
    maintenance
    Provides persistent long-term memory for AI agents through semantic search and automated knowledge graph extraction. It enables agents to store, recall, and reason over facts, preferences, and relationships across multiple conversations and sessions.
    14
    12 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides persistent, cross-session memory for AI agents, allowing them to store and automatically retrieve information across different conversations and sessions without repeating context.
    9 npm
    175
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP-native persistent-memory agent that remembers user preferences across sessions, forgets superseded facts, and recalls relevant memories within a tight token budget.
    MIT