Recognize multi round-trip input_required results per SEP-2322#433
Open
koic wants to merge 1 commit into
Open
Conversation
## Motivation and Context SEP-2322 (modelcontextprotocol/modelcontextprotocol#2322, merged for the 2026-07-28 spec release) introduces Multi Round-Trip Requests: instead of issuing in-flight server-to-client JSON-RPC requests, a server answers with a result whose `resultType` is `"input_required"`, carrying an `inputRequests` map (of `sampling/createMessage`, `roots/list`, and `elicitation/create` request shapes) and an opaque `requestState`; the client fulfills the requests and re-issues the original request with `inputResponses` and the echoed `requestState`. The wire contract (the `resultType` discriminator and the `inputRequests`/`requestState` shape) stayed stable across all three closed TypeScript prototype iterations (typescript-sdk#2062/#2065, the v2-stateless stack, and #2251) and the Python draft (python-sdk#2322), but the server-side suspend/resume mechanism is still unsettled in both SDKs (typescript-sdk#2251 was put on hold on 2026-06-08). This change therefore implements only the stable, additive vocabulary and the client-side recognition, leaving server emission and automatic resumption for a follow-up once the reference design lands: - New `MCP::ResultType` module with `COMPLETE` and `INPUT_REQUIRED` constants documenting the `resultType` values. - `MCP::Client` raises the new `MCP::Client::InputRequiredError` (exposing `input_requests`, `request_state`, and the raw `result`) when any response carries `resultType: "input_required"`, instead of silently returning a non-final result as if it were the answer. The check lives in the shared request path, so every client method is covered. Servers on stable protocol versions never emit `resultType`, so default behavior is unchanged. Part of modelcontextprotocol#382. ## How Has This Been Tested? New tests in `test/mcp/client_test.rb`: - `call_tool` raises `InputRequiredError` for an `input_required` result and exposes `input_requests`, `request_state`, and the full raw result - `call_tool` returns normally when `resultType` is `"complete"` and when it is absent (wire-compat regression for stable-protocol servers) - `list_tools` also raises for `input_required` results, proving the recognition covers the shared request path `bundle exec rake` (tests, RuboCop, and conformance baseline) passes. ## Breaking Changes None for spec-compliant stable servers, which never send `resultType`. A response that does carry `resultType: "input_required"` now raises `MCP::Client::InputRequiredError` instead of being returned as a final result, which was always a misinterpretation of the draft semantics.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation and Context
SEP-2322 (modelcontextprotocol/modelcontextprotocol#2322, merged for the 2026-07-28 spec release) introduces Multi Round-Trip Requests: instead of issuing in-flight server-to-client JSON-RPC requests, a server answers with a result whose
resultTypeis"input_required", carrying aninputRequestsmap (ofsampling/createMessage,roots/list, andelicitation/createrequest shapes) and an opaquerequestState; the client fulfills the requests and re-issues the original request withinputResponsesand the echoedrequestState.The wire contract (the
resultTypediscriminator and theinputRequests/requestStateshape) stayed stable across all three closed TypeScript prototype iterations (typescript-sdk#2062/#2065, the v2-stateless stack, and #2251) and the Python draft (python-sdk#2322), but the server-side suspend/resume mechanism is still unsettled in both SDKs (typescript-sdk#2251 was put on hold on 2026-06-08). This change therefore implements only the stable, additive vocabulary and the client-side recognition, leaving server emission and automatic resumption for a follow-up once the reference design lands:MCP::ResultTypemodule withCOMPLETEandINPUT_REQUIREDconstants documenting theresultTypevalues.MCP::Clientraises the newMCP::Client::InputRequiredError(exposinginput_requests,request_state, and the rawresult) when any response carriesresultType: "input_required", instead of silently returning a non-final result as if it were the answer. The check lives in the shared request path, so every client method is covered. Servers on stable protocol versions never emitresultType, so default behavior is unchanged.Part of #382.
How Has This Been Tested?
New tests in
test/mcp/client_test.rb:call_toolraisesInputRequiredErrorfor aninput_requiredresult and exposesinput_requests,request_state, and the full raw resultcall_toolreturns normally whenresultTypeis"complete"and when it is absent (wire-compat regression for stable-protocol servers)list_toolsalso raises forinput_requiredresults, proving the recognition covers the shared request pathbundle exec rake(tests, RuboCop, and conformance baseline) passes.Breaking Changes
None for spec-compliant stable servers, which never send
resultType. A response that does carryresultType: "input_required"now raisesMCP::Client::InputRequiredErrorinstead of being returned as a final result, which was always a misinterpretation of the draft semantics.Types of changes
Checklist