Skip to content

SEP-2322: Multi Round-Trip Requests #2322

Merged
CaitieM20 merged 112 commits into
modelcontextprotocol:mainfrom
CaitieM20:merge
May 6, 2026
Merged

SEP-2322: Multi Round-Trip Requests #2322
CaitieM20 merged 112 commits into
modelcontextprotocol:mainfrom
CaitieM20:merge

Conversation

@CaitieM20

@CaitieM20 CaitieM20 commented Feb 28, 2026

Copy link
Copy Markdown
Contributor

This is a draft SEP for Multi Round-Trip Requests (MRTR) from the Transports Working Group. It is one of the changes discussed and planned at the December 2025 Core Maintainer Meetup. Exploring the Future of MCP Transports Blog

This SEP Is still in draft, Schema changes are proposed but not locked, documentation updates, conformance tests and additional work still to come, but its ready to move out of Transports Working Group and open up to broader feedback.

Authors: Mark D. Roth (@markdroth), Caitie McCaffrey (@CaitieM20), Gabriel Zimmerman (@gjz22)

Motivation and Context

See SEP for details.

How Has This Been Tested?

Conformance Tests: modelcontextprotocol/conformance#188

Breaking Changes

Yes, see SEP for details

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

Additional context

CaitieM20 and others added 30 commits February 20, 2026 10:36
…uestParams — now available on any

  client-initiated request, not just tool calls
   2. Added typed InputResponse = ElicitResult | CreateMessageResult — InputResponses values are now properly typed
  instead of { result: { [key: string]: unknown } }
   3. Updated examples — removed the extra result wrapper from TaskInputResponseRequest and
  TaskInputResponseRequestParams examples to match the new typed schema

  All checks pass: ✅ TypeScript compiles, ✅ JSON schema up to date, ✅ 140/140 examples valid.

Caitie Note: Need to take a look at task-input-response-params.json looks wrong on cursory inspection.
…itRequets these should only be sent as part of IncompleteResponse Objects now
…a JSONRPCIncompleteResultResponse and add examples
…pper in the SEP because InputRequests maps keys directly to the requests so the InputResponses now follows that pattern and there is no benefit to the added wrapper. The only argument for the wrapper would be if we wanted to carry error's alongside results but we do not in these cases. If there is an error the client would retry until the necessary information was retrieved and then send back to the server.
@localden localden added final SEP finalized. and removed accepted SEP accepted by core maintainers, but still requires final wording and reference implementation. labels Jun 4, 2026
koic added a commit to modelcontextprotocol/ruby-sdk that referenced this pull request Jul 11, 2026
## 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 #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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

final SEP finalized. roadmap/transport Roadmap: Transport Evolution & Scalability (incl. Server Cards) SEP transport Related to MCP transports

Projects

Status: Accepted

Development

Successfully merging this pull request may close these issues.