Skip to content

Add Stateless Lifecycle Foundations per SEP-2575#471

Open
koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:stateless_foundations
Open

Add Stateless Lifecycle Foundations per SEP-2575#471
koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:stateless_foundations

Conversation

@koic

@koic koic commented Jul 26, 2026

Copy link
Copy Markdown
Member

Motivation and Context

SEP-2575 (modelcontextprotocol/modelcontextprotocol#2575, merged for the 2026-07-28 spec release) replaces the initialize handshake with a stateless "modern" lifecycle: every request carries its protocol version, client info, and client capabilities in reserved _meta keys, and the server validates each request independently. This change lays the shared vocabulary for that lifecycle without changing any behavior:

  • MCP::Configuration gains LATEST_MODERN_PROTOCOL_VERSION ("2026-07-28"), SUPPORTED_MODERN_PROTOCOL_VERSIONS, and Configuration.modern_protocol_version?. Modern versions are deliberately kept out of SUPPORTED_STABLE_PROTOCOL_VERSIONS so initialize can never negotiate them and protocol_version= keeps rejecting them.
  • MCP::ErrorCodes gains HEADER_MISMATCH (-32020), completing the spec's stateless lifecycle error code block alongside the existing -32021/-32022 constants.
  • New MCP::RequestEnvelope parses and validates the per-request _meta triple (io.modelcontextprotocol/protocolVersion, clientInfo, clientCapabilities, plus the optional deprecated logLevel). A request is classified as modern only when the full triple is present, matching the TypeScript SDK's RequestMetaEnvelopeSchema and the Python SDK's _has_modern_envelope, so partial or legacy _meta entries keep flowing through the legacy path untouched.
  • New typed errors Server::UnsupportedProtocolVersionError (-32022 with data: { supported:, requested: }) and Server::MissingRequiredClientCapabilityError (-32021 with data: { requiredCapabilities: }) reuse the established RequestHandlerError error_code/error_data plumbing (the -32042 URL elicitation precedent).

Nothing dispatches through RequestEnvelope yet; the server-side modern handling, transport routing, and client support build on this in follow-up changes.

Refs #389.

How Has This Been Tested?

New test/mcp/request_envelope_test.rb covers the modern-triple classification (full triple, partial triple, string keys, legacy progressToken), parsed field access, the -32022 error data shape, and invalid-request errors for incomplete or mistyped triples. test/mcp/configuration_test.rb asserts the new constants, the predicate, and that modern versions stay rejected by protocol_version=. test/mcp/server_test.rb asserts both typed errors surface on the wire with their SEP-2575 codes and data through Server#handle. test/mcp/error_codes_test.rb pins -32020.

Breaking Changes

None. Constants and classes are additive; no request path changes behavior.

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

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

## Motivation and Context

SEP-2575 (modelcontextprotocol/modelcontextprotocol#2575, merged for the 2026-07-28 spec release) replaces
the `initialize` handshake with a stateless "modern" lifecycle: every request carries its protocol version,
client info, and client capabilities in reserved `_meta` keys, and the server validates each request independently.
This change lays the shared vocabulary for that lifecycle without changing any behavior:

- `MCP::Configuration` gains `LATEST_MODERN_PROTOCOL_VERSION` ("2026-07-28"), `SUPPORTED_MODERN_PROTOCOL_VERSIONS`,
  and `Configuration.modern_protocol_version?`. Modern versions are deliberately kept out of `SUPPORTED_STABLE_PROTOCOL_VERSIONS`
  so `initialize` can never negotiate them and `protocol_version=` keeps rejecting them.
- `MCP::ErrorCodes` gains `HEADER_MISMATCH` (-32020), completing the spec's stateless lifecycle error code block alongside
   the existing -32021/-32022 constants.
- New `MCP::RequestEnvelope` parses and validates the per-request `_meta` triple (`io.modelcontextprotocol/protocolVersion`,
  `clientInfo`, `clientCapabilities`, plus the optional deprecated `logLevel`). A request is classified as modern only
  when the full triple is present, matching the TypeScript SDK's `RequestMetaEnvelopeSchema` and the Python SDK's `_has_modern_envelope`,
  so partial or legacy `_meta` entries keep flowing through the legacy path untouched.
- New typed errors `Server::UnsupportedProtocolVersionError` (-32022 with `data: { supported:, requested: }`) and
  `Server::MissingRequiredClientCapabilityError` (-32021 with `data: { requiredCapabilities: }`) reuse the established `RequestHandlerError`
  `error_code`/`error_data` plumbing (the -32042 URL elicitation precedent).

Nothing dispatches through `RequestEnvelope` yet; the server-side modern handling, transport routing, and client support build on
this in follow-up changes.

Refs modelcontextprotocol#389.

## How Has This Been Tested?

New `test/mcp/request_envelope_test.rb` covers the modern-triple classification (full triple, partial triple, string keys,
legacy `progressToken`), parsed field access, the -32022 error data shape, and invalid-request errors for incomplete or mistyped triples.
`test/mcp/configuration_test.rb` asserts the new constants, the predicate, and that modern versions stay rejected by `protocol_version=`.
`test/mcp/server_test.rb` asserts both typed errors surface on the wire with their SEP-2575 codes and data through `Server#handle`.
`test/mcp/error_codes_test.rb` pins -32020.

## Breaking Changes

None. Constants and classes are additive; no request path changes behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant