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. ctx.elicit() reads and validates that response for you.
Invalid accepted form data produces another required round.
The result statuses are:
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 toctx.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 an absolute URL string as the third argument. 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.