input_required result. A capable client
collects input and retries the original tool call; the callback runs again with
the response in its request context.
Use form mode for ordinary structured input and URL mode when values must stay
on an external site.
Handle the input-required round
Every call has a stable correlation key, a user-facing message, and either a Standard Schema form schema or a URL:ctx.inputResponses. inputResponse() reads that response for you, and
acceptedContent() validates accepted form data against the schema. Missing or
invalid accepted content makes acceptedContent() return undefined, so the
handler returns another input_required round.
For an elicitation key, inputResponse() returns one of these. The full union
also carries kind: "roots" and kind: "sampling" for the other request types:
Form mode
Form mode accepts a Standard Schema that can be converted to JSON Schema. Keep forms flat and use primitive fields, enums, and arrays of enum values. Add descriptions and refinements before passing the schema toinputRequired.elicit().
Do not collect passwords, API keys, payment details, or OAuth secrets in form
mode. Submitted form values pass through the MCP client.
URL mode
Pass the absolute URL toinputRequired.elicitUrl() instead of a schema. Keep
the external flow’s state in a trusted backend and look it up with a stable,
unguessable handle from the original tool input:
getOrCreateFlow must return the same
server-stored flow when the callback reruns with connectionId. Verify callback
state and completion on your own backend before performing a protected action.
Keep multi-round workflows safe
Because the callback re-runs for each input-required round:- Perform reads and validation before elicitation as needed.
- Perform irreversible side effects only after the relevant
accept. - Use a different stable key for each distinct question.
- Use verified
requestStatewhen a multi-step workflow needs trusted state. - Treat bare
ctx.inputResponsesas untrusted client input if you read it directly.
Run and test the example
http://localhost:3000/mcp. Test accept, decline, cancel, an invalid form
response that triggers another round, and the URL callback-verification path.