MCP Elicitation: How an MCP Server Asks the User Mid-Task
Elicitation is how an MCP server stops and asks the person a question instead of guessing: a confirmation, a missing field, a sign-in to another system. Claude Code shipped MCP Tasks on top of it on 23 October. Here is how it works under the current spec, what changed for stateless servers, and where it is supported.
Oct 25, 2026
MCP elicitation is how a Model Context Protocol server asks the user a question in the middle of a task, through the AI client, instead of guessing. The server sends a short message plus either a small form (form mode) or a link to a web page (URL mode); the user accepts, declines or cancels, and the server carries on with the answer. Under the current specification (2026-07-28) the question travels back in the tool's own response, so it works on stateless servers too. And on 23 October, Claude Code put MCP Tasks in public beta, which lets a long-running tool pause for the same kind of input. Below: how it works, the two modes, what changed, who supports it, and what it means if you build or buy an MCP server.
Why a server needs to ask
A tool call carries whatever arguments the model chose. Often that is not enough:
- A missing or ambiguous field. "Create the invoice for Martin": which of the three Martins?
- A confirmation before a write. Delete 40 records, send an email to a client, post a payment.
- Access to a third system. The server needs the user's own sign-in to another service before it can call it.
Without elicitation, the server returns an error, the model guesses, or the model asks in plain chat and has to pass the answer back as a new tool argument. Elicitation makes the question part of the protocol: the client shows it as a real dialog, clearly labelled with the server that asked, and the answer comes back in a known shape.
How it works under the 2026-07-28 spec
The current elicitation specification uses multi round-trip requests:
- The client calls a tool (
tools/call). - The server needs input, so it answers with an
InputRequiredResultcontaining anelicitation/createrequest, and optionally an opaquerequestState. - The client shows the dialog. The user accepts, declines or cancels.
- The client retries the original call with the answer in
inputResponsesand therequestStateechoed back. - The server finishes and returns the normal result, or asks again.
The client declares what it supports on every request, in _meta: elicitation: { form: {}, url: {} }. A server must not send a mode the client did not declare.
Why this matters: the server does not have to hold a connection or a session open while the person thinks. In the earlier design, elicitation was a request from the server to the client, which needs a live session to route the answer back. A stateless server, the kind that scales like any web API, could not do it. We run ours stateless, and on the Go SDK version they use today (v1.6.1) the SDK's own documentation says that in stateless mode "any server->client request is rejected immediately". The Go SDK v1.8.0 adds the multi round-trip mechanism; that upgrade is what makes elicitation possible on our servers.
Form mode and URL mode
| Form mode | URL mode | |
|---|---|---|
| What the user sees | A dialog with fields, inside the client | A prompt to open a link in the browser |
| What it collects | A flat object: strings (email, URI, date formats), numbers, booleans, single or multi-select enums | Nothing through the client; the interaction happens on your page |
| Data seen by the client | Yes | Only the URL |
| Use for | Choices, confirmations, missing fields | Sign-in to a third-party system, API keys, payments |
| Never use for | Passwords, API keys, access tokens, payment details | Authorizing the user to your own MCP server (that is MCP authorization, not elicitation) |
Two rules from the spec are worth reading twice:
- Sensitive data goes through URL mode only. The spec says servers "MUST NOT use form mode elicitation to request sensitive information such as passwords, API keys, access tokens, or payment credentials". URL mode keeps them out of the client, its logs and the model's context. (Claude Code's own docs use a username and password prompt as a form example; the spec is the rule to follow.)
- URL mode needs a same-user check. The spec describes a phishing attack where one user sends the elicitation link to another, who then authorizes the wrong account. The fix it gives: send users to a "connect" page on your own domain that checks the person who opened it is the person whose session asked, comparing the
subclaim from your authorization server, before redirecting to the third party.
Every answer comes back as one of three actions: accept (with content in form mode), decline (an explicit no) or cancel (dismissed). Handle all three. A decline on a destructive action should stop it; a cancel can mean "ask later".
MCP Tasks: elicitation for long-running work
MCP Tasks is an official extension, not part of the core spec. When a call will take a while (a batch import, a report, an approval), the server returns a task handle instead of blocking. The client polls tasks/get. If the task needs a person, its status becomes input_required and it carries the same elicitation requests; the client answers with tasks/update. Statuses are working, input_required, completed, failed and cancelled.
What Claude Code supports today:
- Elicitation: form and URL mode, served in interactive terminal sessions. An
Elicitationhook can answer automatically. In a non-interactive session, Claude Code asks the server to cancel a task that needs input. - Tasks: public beta from v2.1.304, in terminal CLI sessions, Agent SDK sessions and GitHub Actions runs, on servers connected on protocol revision 2026-07-28. The VS Code extension and the desktop app do not have it yet, and neither do third-party providers such as Amazon Bedrock.
Support in other clients differs and moves fast. Build the server so it works without elicitation: if the client did not declare it, fall back to a clear error or a two-step tool ("preview" then "confirm").
What this means if you build or buy an MCP server
- Put confirmations where writes are. Tools that change data should ask before acting on anything hard to undo. Mark read-only tools
readOnlyHintso clients can skip confirmation on them. - Never take secrets in a form. If a tool needs the user's account on another system, use URL mode and a connect page, and store the token server-side, bound to that user.
- Plan the SDK upgrade with the spec. Elicitation on a stateless server needs an SDK that speaks 2026-07-28. Check yours before designing a flow around it.
- Treat long work as a task. A tool that runs for minutes should return a task handle, not hold the connection.
What we do, and what we don't do yet
What we run: MCP servers for business systems, stateless, on the official Go SDK, with OAuth sign-in per user. Each tool's permission scope comes from its readOnlyHint annotation: a read-only tool needs only the read scope, everything else needs write. We cover the rest in how to build an MCP server, remote MCP servers and MCP security.
What we don't do yet: our servers do not use elicitation today. They are on Go SDK v1.6.1, which cannot send it in stateless mode. Confirmations live in the tool design (separate preview and commit tools) and in the client's own approval prompt. Moving to v1.8.0 and the 2026-07-28 protocol is the step that unlocks it, and we will write up what we learn when we ship it.