Merge pull request #223 from chattermill/md-protocol-negotiation
Add protocol version negotiation to server initialization
This commit is contained in:
commit
15ef5ebda2
2 changed files with 116 additions and 5 deletions
|
|
@ -18,6 +18,9 @@ module MCP
|
||||||
class Server
|
class Server
|
||||||
DEFAULT_VERSION = "0.1.0"
|
DEFAULT_VERSION = "0.1.0"
|
||||||
|
|
||||||
|
UNSUPPORTED_PROPERTIES_UNTIL_2025_06_18 = [:description, :icons].freeze
|
||||||
|
UNSUPPORTED_PROPERTIES_UNTIL_2025_03_26 = [:title, :websiteUrl].freeze
|
||||||
|
|
||||||
class RequestHandlerError < StandardError
|
class RequestHandlerError < StandardError
|
||||||
attr_reader :error_type
|
attr_reader :error_type
|
||||||
attr_reader :original_error
|
attr_reader :original_error
|
||||||
|
|
@ -319,13 +322,32 @@ module MCP
|
||||||
}.compact
|
}.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
def init(request)
|
def init(params)
|
||||||
@client = request[:clientInfo] if request
|
@client = params[:clientInfo] if params
|
||||||
|
|
||||||
|
protocol_version = params[:protocolVersion] if params
|
||||||
|
negotiated_version = if Configuration::SUPPORTED_STABLE_PROTOCOL_VERSIONS.include?(protocol_version)
|
||||||
|
protocol_version
|
||||||
|
else
|
||||||
|
configuration.protocol_version
|
||||||
|
end
|
||||||
|
|
||||||
|
info = server_info.reject do |property|
|
||||||
|
negotiated_version <= "2025-06-18" && UNSUPPORTED_PROPERTIES_UNTIL_2025_06_18.include?(property) ||
|
||||||
|
negotiated_version <= "2025-03-26" && UNSUPPORTED_PROPERTIES_UNTIL_2025_03_26.include?(property)
|
||||||
|
end
|
||||||
|
|
||||||
|
response_instructions = instructions
|
||||||
|
|
||||||
|
if negotiated_version == "2024-11-05"
|
||||||
|
response_instructions = nil
|
||||||
|
end
|
||||||
|
|
||||||
{
|
{
|
||||||
protocolVersion: configuration.protocol_version,
|
protocolVersion: negotiated_version,
|
||||||
capabilities: capabilities,
|
capabilities: capabilities,
|
||||||
serverInfo: server_info,
|
serverInfo: info,
|
||||||
instructions: instructions,
|
instructions: response_instructions,
|
||||||
}.compact
|
}.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1274,6 +1274,95 @@ module MCP
|
||||||
assert_equal custom_version, response[:result][:protocolVersion]
|
assert_equal custom_version, response[:result][:protocolVersion]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "server negotiates protocol version when client requests a supported version" do
|
||||||
|
server = Server.new(name: "test_server")
|
||||||
|
|
||||||
|
request = {
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
method: "initialize",
|
||||||
|
id: 1,
|
||||||
|
params: {
|
||||||
|
protocolVersion: "2025-06-18",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = server.handle(request)
|
||||||
|
assert_equal "2025-06-18", response[:result][:protocolVersion]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "server falls back to default version when client requests unsupported version" do
|
||||||
|
server = Server.new(name: "test_server")
|
||||||
|
|
||||||
|
request = {
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
method: "initialize",
|
||||||
|
id: 1,
|
||||||
|
params: {
|
||||||
|
protocolVersion: "1999-01-01",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = server.handle(request)
|
||||||
|
assert_equal Configuration::LATEST_STABLE_PROTOCOL_VERSION, 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",
|
||||||
|
description: "A test server",
|
||||||
|
icons: [Icon.new(src: "https://example.com/icon.png")],
|
||||||
|
)
|
||||||
|
|
||||||
|
request = {
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
method: "initialize",
|
||||||
|
id: 1,
|
||||||
|
params: {
|
||||||
|
protocolVersion: "2025-06-18",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = server.handle(request)
|
||||||
|
assert_equal "2025-06-18", response[:result][:protocolVersion]
|
||||||
|
refute response[:result][:serverInfo].key?(:description)
|
||||||
|
refute response[:result][:serverInfo].key?(:icons)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "server removes title and websiteUrl when negotiating to 2025-03-26" do
|
||||||
|
server = Server.new(name: "test_server", title: "Test Server", website_url: "https://example.com")
|
||||||
|
|
||||||
|
request = {
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
method: "initialize",
|
||||||
|
id: 1,
|
||||||
|
params: {
|
||||||
|
protocolVersion: "2025-03-26",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = server.handle(request)
|
||||||
|
assert_equal "2025-03-26", response[:result][:protocolVersion]
|
||||||
|
refute response[:result][:serverInfo].key?(:title)
|
||||||
|
refute response[:result][:serverInfo].key?(:websiteUrl)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "server removes instructions when negotiating to 2024-11-05" do
|
||||||
|
server = Server.new(name: "test_server", instructions: "Some instructions")
|
||||||
|
|
||||||
|
request = {
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
method: "initialize",
|
||||||
|
id: 1,
|
||||||
|
params: {
|
||||||
|
protocolVersion: "2024-11-05",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = server.handle(request)
|
||||||
|
assert_equal "2024-11-05", response[:result][:protocolVersion]
|
||||||
|
refute response[:result].key?(:instructions)
|
||||||
|
end
|
||||||
|
|
||||||
test "tools/call handles missing arguments field" do
|
test "tools/call handles missing arguments field" do
|
||||||
server = Server.new(
|
server = Server.new(
|
||||||
tools: [TestTool],
|
tools: [TestTool],
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue