Skip to main content
Glama

MCP Elicitation LAB

An MCP server in the middle of a tool call needs more from the person, and asks the client for it in form mode or URL mode. This lab runs 19 scenarios against a mock server and a mock client that follows the spec's rules, shows the raw JSON-RPC of every message, builds the dialog a compliant client must show, and reports findings when a server breaks a MUST or SHOULD.

Tier: Tester Repo: https://github.com/curtismu7/mcp-elicitation-LAB Catalog: D37

Catalog D37 ("MCP elicitation lab") is an existing row of the demo catalog, not a placeholder. The catalog lists its kind as Demo; this README declares Tester because the app probes and scores a server's behaviour against the spec rather than telling a customer story.

Spec basis. MCP revision 2025-11-25, plus the current draft as a labelled difference. Both elicitation pages were read in full on 2026-10-22. basic/security_best_practices, basic/authorization and basic/patterns/mrtr were NOT read, so anything about them is UNVERIFIED. Real clients (do they implement URL mode?) were not probed. See docs/safety.md.

What is simulated

Mock mode (the only mode). The MCP server and the MCP client are both mocks written for this lab, running inside one process. Nothing is fetched, opened or sent anywhere: a URL in a scenario is analysed and shown, never requested, and a netguard refuses every non-loopback socket, DNS lookup, fetch and UDP send or connect. "Opens the URL in a secure browser view" is narration, not behaviour. The phishing scenarios model the attack the spec describes with a mock identity check; they exploit nothing.

Live mode (not available). There is no real MCP server or client to connect to, so the header's Live button answers with a message and the lab stays on Mock. Setting MEL_LAB_MODE=live makes the server refuse to start, with the same message. If Live is ever added it will be owner-run.

What it shows:

  • Form mode: accept, decline, cancel, client-side validation before anything is sent, and an empty capability meaning form only.

  • URL mode: a secret goes to the server's own page and not through the client, -32042 URLElicitationRequired then a retry, declining consent, a client that did not declare URL mode, a stray completion notification.

  • Servers that break rules, on purpose: a password in a form, a nested schema, a link in a form, a URL with a credential and a token, a Punycode host over http, a mode the client never declared, a malformed -32042.

  • Phishing: Alice triggers the elicitation, Bob opens the link. A server that does not verify the person binds Bob's account to Alice's session; one that does, refuses.

  • Diagram: ReactFlow, drawn from diagram-studio/1 data loaded by name: movable boxes, Simulate again, speed, Reset (restores box positions).

  • Talk track and presenter mode: docs/talk-track.md, the page and the presenter notes are all rendered from one data file.

What is the lab's own behaviour (the spec does not define it) is labelled "lab behaviour" on screen: cancelling a form the client cannot render, and ending a malformed -32042.

Related MCP server: mcp_auth_server

Run from a clone

Prerequisites: Node 26 or newer. Docker only if you use the Docker form. Mock mode needs no setup at all: no tenant, no credentials, no settings file.

git clone https://github.com/curtismu7/mcp-elicitation-LAB.git
cd mcp-elicitation-LAB
npm ci
npm run build
npm start

Open http://127.0.0.1:6800/ . For development with hot reload: npm run dev (the API on 6800, the Vite dev server on http://127.0.0.1:6801/).

Settings file

All standalone apps read one optional settings file, ~/Development/.env (mode 600). Set STANDALONE_ENV to use another path. This lab takes one key from it and ignores everything else (it parses the file with util.parseEnv and copies only its own key); no value is ever printed:

  • MEL_LAB_MODE (optional): mock (the default). live is refused with a message. A bare MODE is never read.

The shared file holds no PORT. Run-time knobs go in the shell, not in the file: PORT (see below) and MEL_LAB_BIND (loopback unless you set it on purpose; the container does). LAB_ALLOWED_HOSTS is a comma list of host names (no ports) the lab answers to besides loopback, as <name>:<PORT>; unset means loopback only. Docker defaults it to the name the family lab-proxy sends in Host (see docker-compose.yml), and on that Host only a write whose Origin equals X-Forwarded-Proto://X-Forwarded-Host counts as same-origin. The lab holds no credentials for anything, so no secret belongs in the file.

Ports, and what to do if the port is taken

Ports: MCP Elicitation LAB listens on 6800 (set with PORT, default 6800). The Vite dev server uses 6801 (set with VITE_PORT). The Docker host port is HOST_PORT, default 6800. Port range for this app: 6800-6849.

If the port is taken:

  1. Find what is using it: lsof -iTCP:6800 -sTCP:LISTEN -n -P

  2. If it is an old copy of this app, stop that process: kill .

  3. If it is something else, either stop it or start this app on another port: PORT= npm start

  4. Do not use 8080, 5173, 3000, 4000, 4400, 4510, 4600-4601, 18080, 19080 or 19090. Those are taken by other demos or other tools.

The server refuses a PORT outside 6800-6849 or on that reserved list.

Mock and live modes

The header has a Mock | Live toggle on the page, with the current mode beside it ("Mode: mock") and the same mode named in the banner, which also shows in presenter mode. Mock is on. Clicking Live shows why it is not available and changes nothing: no request is made and the banner still says MOCK. The server answers GET /api/info with mode: "mock" and the reason Live is refused.

Health, doctor and reset

npm run doctor   # Node, mode, bind, port range, every scenario behaves as declared, citations, diagram data, talk track, netguard, one real HTTP run, port free
npm run reset    # forgets every run in the default workspace; settings are kept
npm run smoke    # drives every scenario through a RUNNING lab over HTTP (BASE_URL=http://127.0.0.1:6800)

The app answers GET /api/health with demo-health/1 (public, GET only, no detail; the state comes from the same checks as the doctor). Reset in the header does the same as the script for your own workspace, and also puts the diagram boxes back where the data says. Each browser tab has its own workspace (X-Workspace, default default), so one tab's Reset never touches another's.

Docker (optional)

HOST_PORT=6800 docker compose up --build -d

Publishes to 127.0.0.1 only (a test pins it). The container is read-only, drops all capabilities, runs as a non-root user and needs nothing else. Docker on OrbStack, never Docker Desktop.

Tests

npm test

Runs the server (vitest), the web UI (vitest) and the repo checks (node --test scripts/*.test.mjs). On Node 26, 103 pass: 59 server, 17 web and 27 repo checks. The browser logs the deliberate 4xx answers a negative scenario provokes as console messages; that is expected. Also by hand, with the family's shared standards kit: its check-drift.sh . and check-css.sh ., and its conformance.mjs . --new (not yet run in CI; rule 18 warns because the SE k8s build is deferred).

Troubleshooting

  • The port is taken: see "Ports, and what to do if the port is taken" above.

  • refusing to start: mode: MEL_LAB_MODE is set to live (or something else). This lab has only Mock; unset it.

  • The page says "Could not load" or the diagram is empty: the API is not running, or you opened the Vite dev server without the API. Run npm start and open port 6800, or npm run dev.

  • A request is refused with 403 bad_host or cross_origin: the lab only answers a loopback Host (or a LAB_ALLOWED_HOSTS name, which is how the family lab-proxy reaches it) and same-origin writes. Open it as http://127.0.0.1:6800/ or through the family launcher, and do not put any other proxy in front.

  • Docker health stays "starting": run docker compose logs; the container needs port 6800 free inside and HOST_PORT free on the host.

Ownership

  • Owner: the Ping SE demo family owner (see the repo settings).

  • License: MIT (see LICENSE).

  • Found a problem? Open an issue on the repo.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      A comprehensive reference implementation demonstrating all features of the Model Context Protocol (MCP) specification, serving as documentation, learning resource, and testing tool for MCP implementations.
      1
      MIT
    • F
      license
      Not graded
      quality
      D
      maintenance
      A proof-of-concept MCP server implementing OAuth 2.1 authorization with CIMD client registration and PKCE, demonstrating protected resource access and step-up authentication.
      -
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables MCP clients to interact with a fictional bank through remote tools, including mock banking operations, OAuth 2.1 authentication, and a live X-ray dashboard for observing session activity.
      MIT