Merge pull request #476 from koic/support_2026_07_28_as_latest_protocol_version

Support 2026-07-28 as the Latest Protocol Version
This commit is contained in:
Koichi ITO 2026-08-01 11:06:39 +09:00 • committed by GitHub
commit d20eac0a4b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 60 additions and 16 deletions

View file

@ -1,2 +1,6 @@
server: []
client: []
client:
# TODO: The conformance framework's client-initialization check pins the expected requested version to 2025-11-25,
# while this SDK's latest protocol version is 2026-07-28. Remove once the @modelcontextprotocol/conformance package
# accepts 2026-07-28.
- initialize

View file

@ -22,7 +22,7 @@ Call `MCP::Client#connect` to perform the MCP [initialization handshake](https:/
```ruby
client.connect
# => { "protocolVersion" => "2025-11-25", "capabilities" => {...}, "serverInfo" => {...} }
# => { "protocolVersion" => "2026-07-28", "capabilities" => {...}, "serverInfo" => {...} }
client.connected? # => true
client.server_info # => cached InitializeResult
@ -99,7 +99,7 @@ After `connect` succeeds, the HTTP transport captures the `Mcp-Session-Id` heade
```ruby
http_transport.session_id # => "abc123..."
http_transport.protocol_version # => "2025-11-25"
http_transport.protocol_version # => "2026-07-28"
```
If the server terminates the session, subsequent requests return HTTP 404 and the transport raises `MCP::Client::SessionExpiredError` (a subclass of `RequestHandlerError`). Session state is cleared automatically; callers should start a new session by calling `connect` again.

View file

@ -2,16 +2,17 @@
module MCP
class Configuration
LATEST_STABLE_PROTOCOL_VERSION = "2025-11-25"
LATEST_STABLE_PROTOCOL_VERSION = "2026-07-28"
SUPPORTED_STABLE_PROTOCOL_VERSIONS = [
LATEST_STABLE_PROTOCOL_VERSION, "2025-06-18", "2025-03-26", "2024-11-05",
LATEST_STABLE_PROTOCOL_VERSION, "2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05",
].freeze
DEFAULT_NEGOTIATED_PROTOCOL_VERSION = "2025-03-26"
# Protocol versions of the stateless "modern" lifecycle introduced by the MCP 2026-07-28 spec release (SEP-2575).
# Modern versions are deliberately kept out of `SUPPORTED_STABLE_PROTOCOL_VERSIONS`: the modern lifecycle has
# no `initialize` handshake, so these versions are never negotiated (each request carries its own version in `_meta`
# and is validated against this list independently), and `protocol_version=` keeps rejecting them for the same reason.
# 2026-07-28 serves both lifecycles of the dual-era model: it is negotiable through the legacy `initialize`
# handshake (so it also appears in `SUPPORTED_STABLE_PROTOCOL_VERSIONS`), and it is the version of the modern
# lifecycle, where each request carries its own version in `_meta` and is validated against this list
# independently, with no handshake.
# https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575
LATEST_MODERN_PROTOCOL_VERSION = "2026-07-28"
SUPPORTED_MODERN_PROTOCOL_VERSIONS = [LATEST_MODERN_PROTOCOL_VERSION].freeze

View file

@ -54,7 +54,7 @@ module MCP
Configuration.new(protocol_version: "DRAFT-2025-v3")
end
assert_equal("protocol_version must be 2025-11-25, 2025-06-18, 2025-03-26, or 2024-11-05", exception.message)
assert_equal("protocol_version must be 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26, or 2024-11-05", exception.message)
end
test "raises ArgumentError when protocol_version is not a supported protocol version" do
@ -63,7 +63,7 @@ module MCP
custom_version = "2025-03-27"
config.protocol_version = custom_version
end
assert_equal("protocol_version must be 2025-11-25, 2025-06-18, 2025-03-26, or 2024-11-05", exception.message)
assert_equal("protocol_version must be 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26, or 2024-11-05", exception.message)
end
test "exposes the SEP-2575 modern protocol versions" do
@ -73,12 +73,11 @@ module MCP
refute Configuration.modern_protocol_version?("2025-11-25")
end
test "raises ArgumentError when setting a modern protocol version" do
# Modern versions (SEP-2575) are never negotiated via `initialize`, so they are deliberately not settable as
# the legacy fallback version.
assert_raises(ArgumentError) do
Configuration.new(protocol_version: Configuration::LATEST_MODERN_PROTOCOL_VERSION)
end
test "accepts 2026-07-28 as the protocol version" do
# 2026-07-28 serves both lifecycles of the dual-era model (SEP-2575), so it is negotiable through
# the legacy `initialize` handshake and settable as the fallback version.
config = Configuration.new(protocol_version: Configuration::LATEST_MODERN_PROTOCOL_VERSION)
assert_equal "2026-07-28", config.protocol_version
end
test "raises ArgumentError when protocol_version is not a boolean value" do

View file

@ -1993,6 +1993,32 @@ module MCP
assert_equal 200, response[0]
end
test "POST request with the 2026-07-28 MCP-Protocol-Version header succeeds" do
init_request = create_rack_request(
"POST",
"/",
{ "CONTENT_TYPE" => "application/json" },
{ jsonrpc: "2.0", method: "initialize", id: "init", params: initialize_params(protocolVersion: "2026-07-28") }.to_json,
)
init_response = @transport.handle_request(init_request)
assert_equal "2026-07-28", JSON.parse(init_response[2][0])["result"]["protocolVersion"]
session_id = init_response[1]["mcp-session-id"]
request = create_rack_request(
"POST",
"/",
{
"CONTENT_TYPE" => "application/json",
"HTTP_MCP_SESSION_ID" => session_id,
"HTTP_MCP_PROTOCOL_VERSION" => "2026-07-28",
},
{ jsonrpc: "2.0", method: "tools/list", id: "list" }.to_json,
)
response = @transport.handle_request(request)
assert_equal 200, response[0]
end
test "POST request without MCP-Protocol-Version header succeeds" do
init_request = create_rack_request(
"POST",

View file

@ -2036,6 +2036,20 @@ module MCP
assert_equal Configuration::LATEST_STABLE_PROTOCOL_VERSION, response[:result][:protocolVersion]
end
test "server negotiates 2026-07-28 when the client requests it via initialize" do
server = Server.new(name: "test_server")
request = {
jsonrpc: "2.0",
method: "initialize",
id: 1,
params: initialize_params(protocolVersion: "2026-07-28"),
}
response = server.handle(request)
assert_equal "2026-07-28", response[:result][:protocolVersion]
end
test "server removes description and icons from server_info when negotiating to 2025-06-18" do
server = Server.new(
name: "test_server",