## 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.
27 lines
1.4 KiB
Ruby
27 lines
1.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module MCP
|
|
# MCP-specific JSON-RPC error codes, complementing the generic codes in `JsonRpcHandler::ErrorCode`.
|
|
#
|
|
# All three constants below are introduced by the stateless lifecycle of the MCP 2026-07-28 draft (SEP-2575):
|
|
#
|
|
# - `HEADER_MISMATCH` rejects an HTTP request whose headers do not match the corresponding body values,
|
|
# or whose required headers are missing or malformed (no `error.data`). It is reserved for
|
|
# the Streamable HTTP transport, since headers do not exist on stdio.
|
|
# - `MISSING_REQUIRED_CLIENT_CAPABILITY` rejects a request that requires a client capability
|
|
# the request did not declare (`error.data: { requiredCapabilities: {...} }`).
|
|
# Raised via `Server::MissingRequiredClientCapabilityError`.
|
|
# - `UNSUPPORTED_PROTOCOL_VERSION` rejects a request whose `_meta`-carried protocol version the server
|
|
# does not support (`error.data: { supported: [...], requested: "..." }`). Raised via
|
|
# `Server::UnsupportedProtocolVersionError`.
|
|
#
|
|
# The values come from the spec's MCP-specific error code block, which is allocated sequentially from `-32020`
|
|
# toward `-32099`.
|
|
#
|
|
# https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575
|
|
module ErrorCodes
|
|
HEADER_MISMATCH = -32020
|
|
MISSING_REQUIRED_CLIENT_CAPABILITY = -32021
|
|
UNSUPPORTED_PROTOCOL_VERSION = -32022
|
|
end
|
|
end
|