Multi-round tool result: on the 2026-07-28 protocol a tool that needs user
input mid-call returns resultType: "input_required" with embedded
inputRequests and an opaque requestState, instead of pushing a
server→client request. The client fulfils the embedded requests and retries the
original tools/call carrying inputResponses and the echoed requestState.
The story shows both the Client auto-loop (one await call_tool, callbacks
fired transparently) and a manual client.session loop (the persistable form).
# HTTP — the client self-hosts the server on a free port, runs, then tears it
# down (the InputRequiredResult round-trip is 2026-era only)
uv run python -m stories.mrtr.client --http
# same, against the lowlevel-API server variant
uv run python -m stories.mrtr.client --http --server server_lowlevelclient.pymain— the auto-loop is invisible at the call site:Client(target, mode=mode, elicitation_callback=on_elicit)thenawait client.call_tool("deploy", ...). The sameon_elicitcallback the legacy push path uses is dispatched for each embeddedinputRequestsentry.client.pymanual block —client.session.call_tool(..., allow_input_required=True)returns the rawInputRequiredResultsorequest_statecan be persisted between rounds; the retry is just anothertools/callwithinput_responses=/request_state=.server.pydeploy—ctx.input_responses/ctx.request_stateread the retry payload; the first round returnsInputRequiredResult(input_requests={...}, request_state=...), the second returns the final string.server_lowlevel.py— same wire contract viaparams.input_responses/params.request_stateand a hand-builtInputRequiredResult.
- Loop bound. The auto-loop gives up after
input_required_max_rounds(default 10) withInputRequiredRoundsExceededError; raise it on theClientctor or drop to the manual loop. requestStateintegrity is the server's job. The client echoes it byte-exact and never inspects it; the server MUST treat it as attacker-controlled. The SDK ships no signing helper yet.
Input required tool results — server features
legacy_elicitation/ and sampling/ — the handshake-era push equivalents this
mechanism replaces on the 2026 protocol. refund_desk/ — resolver DI at the
MCPServer tier: the questions a tool can declare instead of pushing by hand.