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:
commit
d20eac0a4b
6 changed files with 60 additions and 16 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in a new issue