Add "Draft" protocol version to supported protocol versions
For example, the `title` introduced in #109 is not supported in the latest stable protocol version "2025-06-18":
https://modelcontextprotocol.io/specification/2025-06-18
It is supported in the Draft of the next version:
https://modelcontextprotocol.io/specification/draft
In other words, the fact that the Ruby SDK treats "2025-06-18" as the default protocol version while `title` is
only supported in the Draft results in an inconsistency.
Because of this, a new version `"Draft"` has been added to the list of supported versions.
Its value follows the schema below and is defined as `DRAFT-2025-v3`:
14ec41c/schema/draft/schema.ts (L15)
It was also considered to continue using the latest stable version "2025-06-18" as the Ruby SDK default instead of the Draft.
However, in that case, users would need to explicitly specify `MCP::Server.new(protocol_version: 'DRAFT-2025-v3')`,
which adds extra burden. In this PR, Draft is made the default in order to provide the following benefits:
- Users are likely to prefer using the Draft version over the latest stable version
- No need to specify the `protocol_version` option when initializing `MCP::Server`
- Users generally do not need to know the internal development value `DRAFT-2025-v3`
The primary case for specifying `protocol_version` explicitly is when strict adherence to a particular version is required.
However, it seems more practical to prioritize use cases where backward-compatible features, including those from the Draft,
are desirable. This is the rationale behind making the Draft version the default.
In addition, making the Draft version the default protocol version preserves backward compatibility for `MCP::Server`.
NOTE: `DRAFT-2025-v3` is a development code, so its value cannot be set externally.
It is applied either when `protocol_version` is omitted or when `nil` is set explicitly,
such as with `MCP::Configuration.new(protocol_version: nil)`.
This prevents users from creating implementations that depend on development codes like `DRAFT-2025-v3`.
This commit is contained in:
parent
400a56e83d
commit
bf729baef2
6 changed files with 106 additions and 9 deletions
|
|
@ -343,6 +343,8 @@ configuration = MCP::Configuration.new(protocol_version: "2024-11-05")
|
|||
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`:
|
||||
|
||||
```ruby
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
module MCP
|
||||
class Configuration
|
||||
DEFAULT_PROTOCOL_VERSION = "2025-06-18"
|
||||
SUPPORTED_PROTOCOL_VERSIONS = [DEFAULT_PROTOCOL_VERSION, "2025-03-26", "2024-11-05"]
|
||||
# DRAFT-2025-v3 is the latest draft protocol version:
|
||||
# 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
|
||||
|
||||
|
|
@ -33,7 +35,7 @@ module MCP
|
|||
end
|
||||
|
||||
def protocol_version
|
||||
@protocol_version || DEFAULT_PROTOCOL_VERSION
|
||||
@protocol_version || DRAFT_PROTOCOL_VERSION
|
||||
end
|
||||
|
||||
def protocol_version?
|
||||
|
|
@ -93,8 +95,8 @@ module MCP
|
|||
private
|
||||
|
||||
def validate_protocol_version!(protocol_version)
|
||||
unless SUPPORTED_PROTOCOL_VERSIONS.include?(protocol_version)
|
||||
message = "protocol_version must be #{SUPPORTED_PROTOCOL_VERSIONS[0...-1].join(", ")}, or #{SUPPORTED_PROTOCOL_VERSIONS[-1]}"
|
||||
unless SUPPORTED_STABLE_PROTOCOL_VERSIONS.include?(protocol_version)
|
||||
message = "protocol_version must be #{SUPPORTED_STABLE_PROTOCOL_VERSIONS[0...-1].join(", ")}, or #{SUPPORTED_STABLE_PROTOCOL_VERSIONS[-1]}"
|
||||
raise ArgumentError, message
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ module MCP
|
|||
def define_prompt(name: nil, title: nil, description: nil, arguments: [], &block)
|
||||
prompt = Prompt.define(name:, title:, description:, arguments:, &block)
|
||||
@prompts[prompt.name_value] = prompt
|
||||
|
||||
validate!
|
||||
end
|
||||
|
||||
def define_custom_method(method_name:, &block)
|
||||
|
|
@ -171,6 +173,21 @@ module MCP
|
|||
private
|
||||
|
||||
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 @instructions
|
||||
message = "`instructions` supported by protocol version 2025-03-26 or higher"
|
||||
|
|
|
|||
|
|
@ -35,9 +35,24 @@ module MCP
|
|||
assert_equal test_context, reported_context
|
||||
end
|
||||
|
||||
# https://github.com/modelcontextprotocol/modelcontextprotocol/blob/14ec41c/schema/draft/schema.ts#L15
|
||||
test "initializes with default protocol version" do
|
||||
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
|
||||
|
||||
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])
|
||||
assert_equal "2.0", body["jsonrpc"]
|
||||
assert_equal "123", body["id"]
|
||||
assert_equal "2025-06-18", body["result"]["protocolVersion"]
|
||||
assert_equal Configuration::DRAFT_PROTOCOL_VERSION, body["result"]["protocolVersion"]
|
||||
end
|
||||
|
||||
test "handles GET request with valid session ID" do
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ module MCP
|
|||
jsonrpc: "2.0",
|
||||
id: 1,
|
||||
result: {
|
||||
protocolVersion: "2025-06-18",
|
||||
protocolVersion: Configuration::DRAFT_PROTOCOL_VERSION,
|
||||
capabilities: {
|
||||
prompts: { listChanged: true },
|
||||
resources: { listChanged: true },
|
||||
|
|
@ -776,7 +776,7 @@ module MCP
|
|||
}
|
||||
|
||||
response = @server.handle(request)
|
||||
assert_equal Configuration::DEFAULT_PROTOCOL_VERSION, response[:result][:protocolVersion]
|
||||
assert_equal Configuration::DRAFT_PROTOCOL_VERSION, response[:result][:protocolVersion]
|
||||
end
|
||||
|
||||
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)
|
||||
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
|
||||
@server.define_tool(
|
||||
name: "defined_tool",
|
||||
|
|
|
|||
Loading…
Reference in a new issue