Merge pull request #179 from koic/add_draft_version
Add "Draft" protocol version to supported protocol versions
This commit is contained in:
commit
11aea51c42
6 changed files with 106 additions and 9 deletions
|
|
@ -348,6 +348,8 @@ configuration = MCP::Configuration.new(protocol_version: "2024-11-05")
|
||||||
MCP::Server.new(name: "test_server", configuration: configuration)
|
MCP::Server.new(name: "test_server", configuration: configuration)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If no protocol version is specified, the [Draft version](https://modelcontextprotocol.io/specification/draft) will be applied by default.
|
||||||
|
|
||||||
This will make all new server instances use the specified protocol version instead of the default version. The protocol version can be reset to the default by setting it to `nil`:
|
This will make all new server instances use the specified protocol version instead of the default version. The protocol version can be reset to the default by setting it to `nil`:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
module MCP
|
module MCP
|
||||||
class Configuration
|
class Configuration
|
||||||
DEFAULT_PROTOCOL_VERSION = "2025-06-18"
|
# DRAFT-2025-v3 is the latest draft protocol version:
|
||||||
SUPPORTED_PROTOCOL_VERSIONS = [DEFAULT_PROTOCOL_VERSION, "2025-03-26", "2024-11-05"]
|
# https://github.com/modelcontextprotocol/modelcontextprotocol/blob/14ec41c/schema/draft/schema.ts#L15
|
||||||
|
DRAFT_PROTOCOL_VERSION = "DRAFT-2025-v3"
|
||||||
|
SUPPORTED_STABLE_PROTOCOL_VERSIONS = ["2025-06-18", "2025-03-26", "2024-11-05"]
|
||||||
|
|
||||||
attr_writer :exception_reporter, :instrumentation_callback
|
attr_writer :exception_reporter, :instrumentation_callback
|
||||||
|
|
||||||
|
|
@ -33,7 +35,7 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
def protocol_version
|
def protocol_version
|
||||||
@protocol_version || DEFAULT_PROTOCOL_VERSION
|
@protocol_version || DRAFT_PROTOCOL_VERSION
|
||||||
end
|
end
|
||||||
|
|
||||||
def protocol_version?
|
def protocol_version?
|
||||||
|
|
@ -93,8 +95,8 @@ module MCP
|
||||||
private
|
private
|
||||||
|
|
||||||
def validate_protocol_version!(protocol_version)
|
def validate_protocol_version!(protocol_version)
|
||||||
unless SUPPORTED_PROTOCOL_VERSIONS.include?(protocol_version)
|
unless SUPPORTED_STABLE_PROTOCOL_VERSIONS.include?(protocol_version)
|
||||||
message = "protocol_version must be #{SUPPORTED_PROTOCOL_VERSIONS[0...-1].join(", ")}, or #{SUPPORTED_PROTOCOL_VERSIONS[-1]}"
|
message = "protocol_version must be #{SUPPORTED_STABLE_PROTOCOL_VERSIONS[0...-1].join(", ")}, or #{SUPPORTED_STABLE_PROTOCOL_VERSIONS[-1]}"
|
||||||
raise ArgumentError, message
|
raise ArgumentError, message
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,8 @@ module MCP
|
||||||
def define_prompt(name: nil, title: nil, description: nil, arguments: [], &block)
|
def define_prompt(name: nil, title: nil, description: nil, arguments: [], &block)
|
||||||
prompt = Prompt.define(name:, title:, description:, arguments:, &block)
|
prompt = Prompt.define(name:, title:, description:, arguments:, &block)
|
||||||
@prompts[prompt.name_value] = prompt
|
@prompts[prompt.name_value] = prompt
|
||||||
|
|
||||||
|
validate!
|
||||||
end
|
end
|
||||||
|
|
||||||
def define_custom_method(method_name:, &block)
|
def define_custom_method(method_name:, &block)
|
||||||
|
|
@ -171,6 +173,21 @@ module MCP
|
||||||
private
|
private
|
||||||
|
|
||||||
def validate!
|
def validate!
|
||||||
|
# NOTE: The draft protocol version is the next version after 2025-03-26.
|
||||||
|
if @configuration.protocol_version <= "2025-03-26"
|
||||||
|
if server_info.key?(:title)
|
||||||
|
message = "Error occurred in server_info. `title` is not supported in protocol version 2025-03-26 or earlier"
|
||||||
|
raise ArgumentError, message
|
||||||
|
end
|
||||||
|
|
||||||
|
primitive_titles = [@tools.values, @prompts.values, @resources, @resource_templates].flatten.map(&:title)
|
||||||
|
|
||||||
|
if primitive_titles.any?
|
||||||
|
message = "Error occurred in #{primitive_titles.join(", ")}. `title` is not supported in protocol version 2025-03-26 or earlier"
|
||||||
|
raise ArgumentError, message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if @configuration.protocol_version == "2024-11-05"
|
if @configuration.protocol_version == "2024-11-05"
|
||||||
if @instructions
|
if @instructions
|
||||||
message = "`instructions` supported by protocol version 2025-03-26 or higher"
|
message = "`instructions` supported by protocol version 2025-03-26 or higher"
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,24 @@ module MCP
|
||||||
assert_equal test_context, reported_context
|
assert_equal test_context, reported_context
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# https://github.com/modelcontextprotocol/modelcontextprotocol/blob/14ec41c/schema/draft/schema.ts#L15
|
||||||
test "initializes with default protocol version" do
|
test "initializes with default protocol version" do
|
||||||
config = Configuration.new
|
config = Configuration.new
|
||||||
assert_equal Configuration::DEFAULT_PROTOCOL_VERSION, config.protocol_version
|
assert_equal Configuration::DRAFT_PROTOCOL_VERSION, config.protocol_version
|
||||||
|
end
|
||||||
|
|
||||||
|
test "uses the draft protocol version when protocol_version is set to nil" do
|
||||||
|
config = Configuration.new(protocol_version: nil)
|
||||||
|
assert_equal Configuration::DRAFT_PROTOCOL_VERSION, config.protocol_version
|
||||||
|
end
|
||||||
|
|
||||||
|
test "raises ArgumentError when setting the draft protocol version" do
|
||||||
|
exception = assert_raises(ArgumentError) do
|
||||||
|
# To use the draft version externally, either omit `protocol_version` or set it to nil.
|
||||||
|
Configuration.new(protocol_version: Configuration::DRAFT_PROTOCOL_VERSION)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal("protocol_version must be 2025-06-18, 2025-03-26, or 2024-11-05", exception.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "raises ArgumentError when protocol_version is not a supported protocol version" do
|
test "raises ArgumentError when protocol_version is not a supported protocol version" do
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ module MCP
|
||||||
body = JSON.parse(response[2][0])
|
body = JSON.parse(response[2][0])
|
||||||
assert_equal "2.0", body["jsonrpc"]
|
assert_equal "2.0", body["jsonrpc"]
|
||||||
assert_equal "123", body["id"]
|
assert_equal "123", body["id"]
|
||||||
assert_equal "2025-06-18", body["result"]["protocolVersion"]
|
assert_equal Configuration::DRAFT_PROTOCOL_VERSION, body["result"]["protocolVersion"]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "handles GET request with valid session ID" do
|
test "handles GET request with valid session ID" do
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ module MCP
|
||||||
jsonrpc: "2.0",
|
jsonrpc: "2.0",
|
||||||
id: 1,
|
id: 1,
|
||||||
result: {
|
result: {
|
||||||
protocolVersion: "2025-06-18",
|
protocolVersion: Configuration::DRAFT_PROTOCOL_VERSION,
|
||||||
capabilities: {
|
capabilities: {
|
||||||
prompts: { listChanged: true },
|
prompts: { listChanged: true },
|
||||||
resources: { listChanged: true },
|
resources: { listChanged: true },
|
||||||
|
|
@ -776,7 +776,7 @@ module MCP
|
||||||
}
|
}
|
||||||
|
|
||||||
response = @server.handle(request)
|
response = @server.handle(request)
|
||||||
assert_equal Configuration::DEFAULT_PROTOCOL_VERSION, response[:result][:protocolVersion]
|
assert_equal Configuration::DRAFT_PROTOCOL_VERSION, response[:result][:protocolVersion]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "server response does not include title when not configured" do
|
test "server response does not include title when not configured" do
|
||||||
|
|
@ -852,6 +852,67 @@ module MCP
|
||||||
assert_equal("Error occurred in defined_tool. `annotations` are supported by protocol version 2025-03-26 or higher", exception.message)
|
assert_equal("Error occurred in defined_tool. `annotations` are supported by protocol version 2025-03-26 or higher", exception.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "raises error if `title` of `server_info` is used with protocol version 2025-03-26" do
|
||||||
|
configuration = Configuration.new(protocol_version: "2025-03-26")
|
||||||
|
|
||||||
|
exception = assert_raises(ArgumentError) do
|
||||||
|
Server.new(name: "test_server", title: "Example Server Display Name", configuration: configuration)
|
||||||
|
end
|
||||||
|
assert_equal("Error occurred in server_info. `title` is not supported in protocol version 2025-03-26 or earlier", exception.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "raises error if `title` of tool is used with protocol version 2025-03-26" do
|
||||||
|
configuration = Configuration.new(protocol_version: "2025-03-26")
|
||||||
|
server = Server.new(name: "test_server", configuration: configuration)
|
||||||
|
|
||||||
|
exception = assert_raises(ArgumentError) do
|
||||||
|
server.define_tool(
|
||||||
|
title: "Test tool",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
assert_equal("Error occurred in Test tool. `title` is not supported in protocol version 2025-03-26 or earlier", exception.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "raises error if `title` of prompt is used with protocol version 2025-03-26" do
|
||||||
|
configuration = Configuration.new(protocol_version: "2025-03-26")
|
||||||
|
server = Server.new(name: "test_server", configuration: configuration)
|
||||||
|
|
||||||
|
exception = assert_raises(ArgumentError) do
|
||||||
|
server.define_prompt(
|
||||||
|
title: "Test prompt",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
assert_equal("Error occurred in Test prompt. `title` is not supported in protocol version 2025-03-26 or earlier", exception.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "raises error if `title` of resource is used with protocol version 2025-03-26" do
|
||||||
|
configuration = Configuration.new(protocol_version: "2025-03-26")
|
||||||
|
|
||||||
|
resource = Resource.new(
|
||||||
|
uri: "https://test_resource.invalid",
|
||||||
|
name: "test-resource",
|
||||||
|
title: "Test resource",
|
||||||
|
)
|
||||||
|
exception = assert_raises(ArgumentError) do
|
||||||
|
Server.new(name: "test_server", resources: [resource], configuration: configuration)
|
||||||
|
end
|
||||||
|
assert_equal("Error occurred in Test resource. `title` is not supported in protocol version 2025-03-26 or earlier", exception.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "raises error if `title` of resource template is used with protocol version 2025-03-26" do
|
||||||
|
configuration = Configuration.new(protocol_version: "2025-03-26")
|
||||||
|
|
||||||
|
resource = Resource.new(
|
||||||
|
uri: "https://test_resource.invalid",
|
||||||
|
name: "test-resource",
|
||||||
|
title: "Test resource template",
|
||||||
|
)
|
||||||
|
exception = assert_raises(ArgumentError) do
|
||||||
|
Server.new(name: "test_server", resources: [resource], configuration: configuration)
|
||||||
|
end
|
||||||
|
assert_equal("Error occurred in Test resource template. `title` is not supported in protocol version 2025-03-26 or earlier", exception.message)
|
||||||
|
end
|
||||||
|
|
||||||
test "#define_tool adds a tool to the server" do
|
test "#define_tool adds a tool to the server" do
|
||||||
@server.define_tool(
|
@server.define_tool(
|
||||||
name: "defined_tool",
|
name: "defined_tool",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue