Support Ruby 2.7 - Ruby 3.1
## Summary Unlike applications, libraries provide value by remaining usable for a broad range of users, even when that means supporting older Ruby versions beyond Ruby's own EOL timeline. I maintain RuboCop, a Ruby linter. Because linters need to work across the ecosystem, they often need to keep compatibility with older Ruby versions to some extent. The trade-off is that the MCP Ruby SDK must remain compatible with Ruby 2.7. However, given the ecosystem impact, supporting Ruby 2.7 is still worthwhile. For example, bundled gems such as `csv` (Ruby >= 2.5), `bigdecimal` (Ruby >= 2.5), `json` (Ruby >= 2.7), and `language_server-protocol` (Ruby >= 2.5) tend to keep compatibility with older Ruby versions. Unlike dropping support, which imposes restrictions on users, this change broadens compatibility and does not introduce breaking changes. ## Development Note `rubocop-shopify` (2.18) supports Ruby 3.1+, and this PR does not change that. Since RuboCop can configure the runtime Ruby version and the target Ruby version for analysis independently, CI continues to run RuboCop on Ruby 4.0, while analyzing code with `TargetRubyVersion: 2.7`. When setting `TargetRubyVersion: 2.7`, several RuboCop offenses were resolved. Additionally, Sorbet-related libraries support Ruby 3.0+. Since these are not dependencies of the MCP Ruby SDK itself, they are versioned and tested in the development Gemfile.
This commit is contained in:
parent
4968d9cffc
commit
aa8bbad491
26 changed files with 106 additions and 100 deletions
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
|
|
@ -7,6 +7,9 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
entry:
|
entry:
|
||||||
|
- { ruby: '2.7', allowed-failure: false }
|
||||||
|
- { ruby: '3.0', allowed-failure: false }
|
||||||
|
- { ruby: '3.1', allowed-failure: false }
|
||||||
- { ruby: '3.2', allowed-failure: false }
|
- { ruby: '3.2', allowed-failure: false }
|
||||||
- { ruby: '3.3', allowed-failure: false }
|
- { ruby: '3.3', allowed-failure: false }
|
||||||
- { ruby: '3.4', allowed-failure: false }
|
- { ruby: '3.4', allowed-failure: false }
|
||||||
|
|
@ -29,7 +32,7 @@ jobs:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
- uses: ruby/setup-ruby@v1
|
- uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.2 # Specify the oldest supported Ruby version.
|
ruby-version: 4.0 # Specify the latest supported Ruby version.
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
- run: bundle exec rake rubocop
|
- run: bundle exec rake rubocop
|
||||||
|
|
||||||
|
|
@ -40,6 +43,6 @@ jobs:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
- uses: ruby/setup-ruby@v1
|
- uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
ruby-version: 3.2 # Specify the oldest supported Ruby version.
|
ruby-version: 4.0 # Specify the latest supported Ruby version.
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
- run: bundle exec yard --no-output
|
- run: bundle exec yard --no-output
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ plugins:
|
||||||
- rubocop-minitest
|
- rubocop-minitest
|
||||||
- rubocop-rake
|
- rubocop-rake
|
||||||
|
|
||||||
|
AllCops:
|
||||||
|
TargetRubyVersion: 2.7
|
||||||
|
|
||||||
Gemspec/DevelopmentDependencies:
|
Gemspec/DevelopmentDependencies:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ This is the official Ruby SDK for the Model Context Protocol (MCP), implementing
|
||||||
|
|
||||||
## Dev environment setup
|
## Dev environment setup
|
||||||
|
|
||||||
- Ruby 3.2.0+ required
|
- Ruby 3.2.0+ required to run the full test suite, including all Sorbet-related features
|
||||||
- Run `bundle install` to install dependencies
|
- Run `bundle install` to install dependencies
|
||||||
- Dependencies: `json-schema` >= 4.1 - Schema validation
|
- Dependencies: `json-schema` >= 4.1 - Schema validation
|
||||||
|
|
||||||
|
|
|
||||||
9
Gemfile
9
Gemfile
|
|
@ -8,17 +8,18 @@ gemspec
|
||||||
# Specify development dependencies below
|
# Specify development dependencies below
|
||||||
gem "rubocop-minitest", require: false
|
gem "rubocop-minitest", require: false
|
||||||
gem "rubocop-rake", require: false
|
gem "rubocop-rake", require: false
|
||||||
gem "rubocop-shopify", require: false
|
gem "rubocop-shopify", ">= 2.18", require: false if RUBY_VERSION >= "3.1"
|
||||||
|
|
||||||
gem "puma", ">= 5.0.0"
|
gem "puma", ">= 5.0.0"
|
||||||
gem "rackup", ">= 2.1.0"
|
gem "rackup", ">= 2.1.0"
|
||||||
|
|
||||||
gem "activesupport"
|
gem "activesupport"
|
||||||
gem "debug"
|
# Fix io-console install error when Ruby 3.0.
|
||||||
|
gem "debug" if RUBY_VERSION >= "3.1"
|
||||||
gem "rake", "~> 13.0"
|
gem "rake", "~> 13.0"
|
||||||
gem "sorbet-static-and-runtime"
|
gem "sorbet-static-and-runtime" if RUBY_VERSION >= "3.0"
|
||||||
gem "yard", "~> 0.9"
|
gem "yard", "~> 0.9"
|
||||||
gem "yard-sorbet", "~> 0.9"
|
gem "yard-sorbet", "~> 0.9" if RUBY_VERSION >= "3.1"
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem "faraday", ">= 2.0"
|
gem "faraday", ">= 2.0"
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,14 @@ module JsonRpcHandler
|
||||||
|
|
||||||
def handle(request, id_validation_pattern: DEFAULT_ALLOWED_ID_CHARACTERS, &method_finder)
|
def handle(request, id_validation_pattern: DEFAULT_ALLOWED_ID_CHARACTERS, &method_finder)
|
||||||
if request.is_a?(Array)
|
if request.is_a?(Array)
|
||||||
return error_response(id: :unknown_id, id_validation_pattern:, error: {
|
return error_response(id: :unknown_id, id_validation_pattern: id_validation_pattern, error: {
|
||||||
code: ErrorCode::INVALID_REQUEST,
|
code: ErrorCode::INVALID_REQUEST,
|
||||||
message: "Invalid Request",
|
message: "Invalid Request",
|
||||||
data: "Request is an empty array",
|
data: "Request is an empty array",
|
||||||
}) if request.empty?
|
}) if request.empty?
|
||||||
|
|
||||||
# Handle batch requests
|
# Handle batch requests
|
||||||
responses = request.map { |req| process_request(req, id_validation_pattern:, &method_finder) }.compact
|
responses = request.map { |req| process_request(req, id_validation_pattern: id_validation_pattern, &method_finder) }.compact
|
||||||
|
|
||||||
# A single item is hoisted out of the array
|
# A single item is hoisted out of the array
|
||||||
return responses.first if responses.one?
|
return responses.first if responses.one?
|
||||||
|
|
@ -38,9 +38,9 @@ module JsonRpcHandler
|
||||||
responses if responses.any?
|
responses if responses.any?
|
||||||
elsif request.is_a?(Hash)
|
elsif request.is_a?(Hash)
|
||||||
# Handle single request
|
# Handle single request
|
||||||
process_request(request, id_validation_pattern:, &method_finder)
|
process_request(request, id_validation_pattern: id_validation_pattern, &method_finder)
|
||||||
else
|
else
|
||||||
error_response(id: :unknown_id, id_validation_pattern:, error: {
|
error_response(id: :unknown_id, id_validation_pattern: id_validation_pattern, error: {
|
||||||
code: ErrorCode::INVALID_REQUEST,
|
code: ErrorCode::INVALID_REQUEST,
|
||||||
message: "Invalid Request",
|
message: "Invalid Request",
|
||||||
data: "Request must be an array or a hash",
|
data: "Request must be an array or a hash",
|
||||||
|
|
@ -51,9 +51,9 @@ module JsonRpcHandler
|
||||||
def handle_json(request_json, id_validation_pattern: DEFAULT_ALLOWED_ID_CHARACTERS, &method_finder)
|
def handle_json(request_json, id_validation_pattern: DEFAULT_ALLOWED_ID_CHARACTERS, &method_finder)
|
||||||
begin
|
begin
|
||||||
request = JSON.parse(request_json, symbolize_names: true)
|
request = JSON.parse(request_json, symbolize_names: true)
|
||||||
response = handle(request, id_validation_pattern:, &method_finder)
|
response = handle(request, id_validation_pattern: id_validation_pattern, &method_finder)
|
||||||
rescue JSON::ParserError
|
rescue JSON::ParserError
|
||||||
response = error_response(id: :unknown_id, id_validation_pattern:, error: {
|
response = error_response(id: :unknown_id, id_validation_pattern: id_validation_pattern, error: {
|
||||||
code: ErrorCode::PARSE_ERROR,
|
code: ErrorCode::PARSE_ERROR,
|
||||||
message: "Parse error",
|
message: "Parse error",
|
||||||
data: "Invalid JSON",
|
data: "Invalid JSON",
|
||||||
|
|
@ -74,7 +74,7 @@ module JsonRpcHandler
|
||||||
'Method name must be a string and not start with "rpc."'
|
'Method name must be a string and not start with "rpc."'
|
||||||
end
|
end
|
||||||
|
|
||||||
return error_response(id: :unknown_id, id_validation_pattern:, error: {
|
return error_response(id: :unknown_id, id_validation_pattern: id_validation_pattern, error: {
|
||||||
code: ErrorCode::INVALID_REQUEST,
|
code: ErrorCode::INVALID_REQUEST,
|
||||||
message: "Invalid Request",
|
message: "Invalid Request",
|
||||||
data: error,
|
data: error,
|
||||||
|
|
@ -84,7 +84,7 @@ module JsonRpcHandler
|
||||||
params = request[:params]
|
params = request[:params]
|
||||||
|
|
||||||
unless valid_params?(params)
|
unless valid_params?(params)
|
||||||
return error_response(id:, id_validation_pattern:, error: {
|
return error_response(id: id, id_validation_pattern: id_validation_pattern, error: {
|
||||||
code: ErrorCode::INVALID_PARAMS,
|
code: ErrorCode::INVALID_PARAMS,
|
||||||
message: "Invalid params",
|
message: "Invalid params",
|
||||||
data: "Method parameters must be an array or an object or null",
|
data: "Method parameters must be an array or an object or null",
|
||||||
|
|
@ -95,7 +95,7 @@ module JsonRpcHandler
|
||||||
method = method_finder.call(method_name)
|
method = method_finder.call(method_name)
|
||||||
|
|
||||||
if method.nil?
|
if method.nil?
|
||||||
return error_response(id:, id_validation_pattern:, error: {
|
return error_response(id: id, id_validation_pattern: id_validation_pattern, error: {
|
||||||
code: ErrorCode::METHOD_NOT_FOUND,
|
code: ErrorCode::METHOD_NOT_FOUND,
|
||||||
message: "Method not found",
|
message: "Method not found",
|
||||||
data: method_name,
|
data: method_name,
|
||||||
|
|
@ -104,9 +104,9 @@ module JsonRpcHandler
|
||||||
|
|
||||||
result = method.call(params)
|
result = method.call(params)
|
||||||
|
|
||||||
success_response(id:, result:)
|
success_response(id: id, result: result)
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
error_response(id:, id_validation_pattern:, error: {
|
error_response(id: id, id_validation_pattern: id_validation_pattern, error: {
|
||||||
code: ErrorCode::INTERNAL_ERROR,
|
code: ErrorCode::INTERNAL_ERROR,
|
||||||
message: "Internal error",
|
message: "Internal error",
|
||||||
data: e.message,
|
data: e.message,
|
||||||
|
|
@ -136,8 +136,8 @@ module JsonRpcHandler
|
||||||
def success_response(id:, result:)
|
def success_response(id:, result:)
|
||||||
{
|
{
|
||||||
jsonrpc: Version::V2_0,
|
jsonrpc: Version::V2_0,
|
||||||
id:,
|
id: id,
|
||||||
result:,
|
result: result,
|
||||||
} unless id.nil?
|
} unless id.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,42 +18,42 @@ module MCP
|
||||||
rescue Faraday::BadRequestError => e
|
rescue Faraday::BadRequestError => e
|
||||||
raise RequestHandlerError.new(
|
raise RequestHandlerError.new(
|
||||||
"The #{method} request is invalid",
|
"The #{method} request is invalid",
|
||||||
{ method:, params: },
|
{ method: method, params: params },
|
||||||
error_type: :bad_request,
|
error_type: :bad_request,
|
||||||
original_error: e,
|
original_error: e,
|
||||||
)
|
)
|
||||||
rescue Faraday::UnauthorizedError => e
|
rescue Faraday::UnauthorizedError => e
|
||||||
raise RequestHandlerError.new(
|
raise RequestHandlerError.new(
|
||||||
"You are unauthorized to make #{method} requests",
|
"You are unauthorized to make #{method} requests",
|
||||||
{ method:, params: },
|
{ method: method, params: params },
|
||||||
error_type: :unauthorized,
|
error_type: :unauthorized,
|
||||||
original_error: e,
|
original_error: e,
|
||||||
)
|
)
|
||||||
rescue Faraday::ForbiddenError => e
|
rescue Faraday::ForbiddenError => e
|
||||||
raise RequestHandlerError.new(
|
raise RequestHandlerError.new(
|
||||||
"You are forbidden to make #{method} requests",
|
"You are forbidden to make #{method} requests",
|
||||||
{ method:, params: },
|
{ method: method, params: params },
|
||||||
error_type: :forbidden,
|
error_type: :forbidden,
|
||||||
original_error: e,
|
original_error: e,
|
||||||
)
|
)
|
||||||
rescue Faraday::ResourceNotFound => e
|
rescue Faraday::ResourceNotFound => e
|
||||||
raise RequestHandlerError.new(
|
raise RequestHandlerError.new(
|
||||||
"The #{method} request is not found",
|
"The #{method} request is not found",
|
||||||
{ method:, params: },
|
{ method: method, params: params },
|
||||||
error_type: :not_found,
|
error_type: :not_found,
|
||||||
original_error: e,
|
original_error: e,
|
||||||
)
|
)
|
||||||
rescue Faraday::UnprocessableEntityError => e
|
rescue Faraday::UnprocessableEntityError => e
|
||||||
raise RequestHandlerError.new(
|
raise RequestHandlerError.new(
|
||||||
"The #{method} request is unprocessable",
|
"The #{method} request is unprocessable",
|
||||||
{ method:, params: },
|
{ method: method, params: params },
|
||||||
error_type: :unprocessable_entity,
|
error_type: :unprocessable_entity,
|
||||||
original_error: e,
|
original_error: e,
|
||||||
)
|
)
|
||||||
rescue Faraday::Error => e # Catch-all
|
rescue Faraday::Error => e # Catch-all
|
||||||
raise RequestHandlerError.new(
|
raise RequestHandlerError.new(
|
||||||
"Internal error handling #{method} request",
|
"Internal error handling #{method} request",
|
||||||
{ method:, params: },
|
{ method: method, params: params },
|
||||||
error_type: :internal_error,
|
error_type: :internal_error,
|
||||||
original_error: e,
|
original_error: e,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -85,10 +85,10 @@ module MCP
|
||||||
validate_tool_call_arguments = other.validate_tool_call_arguments
|
validate_tool_call_arguments = other.validate_tool_call_arguments
|
||||||
|
|
||||||
Configuration.new(
|
Configuration.new(
|
||||||
exception_reporter:,
|
exception_reporter: exception_reporter,
|
||||||
instrumentation_callback:,
|
instrumentation_callback: instrumentation_callback,
|
||||||
protocol_version:,
|
protocol_version: protocol_version,
|
||||||
validate_tool_call_arguments:,
|
validate_tool_call_arguments: validate_tool_call_arguments,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
{ text:, annotations:, type: "text" }.compact
|
{ text: text, annotations: annotations, type: "text" }.compact
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
{ data:, mime_type:, annotations:, type: "image" }.compact
|
{ data: data, mime_type: mime_type, annotations: annotations, type: "image" }.compact
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ module MCP
|
||||||
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
||||||
begin
|
begin
|
||||||
@instrumentation_data = {}
|
@instrumentation_data = {}
|
||||||
add_instrumentation_data(method:)
|
add_instrumentation_data(method: method)
|
||||||
|
|
||||||
result = yield block
|
result = yield block
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ module MCP
|
||||||
icons icons
|
icons icons
|
||||||
arguments arguments
|
arguments arguments
|
||||||
define_singleton_method(:template) do |args, server_context: nil|
|
define_singleton_method(:template) do |args, server_context: nil|
|
||||||
instance_exec(args, server_context:, &block)
|
instance_exec(args, server_context: server_context, &block)
|
||||||
end
|
end
|
||||||
meta meta
|
meta meta
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
{ role:, content: content.to_h }.compact
|
{ role: role, content: content.to_h }.compact
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
{ description:, messages: messages.map(&:to_h) }.compact
|
{ description: description, messages: messages.map(&:to_h) }.compact
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
{ uri:, mime_type: }.compact
|
{ uri: uri, mime_type: mime_type }.compact
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
{ resource: resource.to_h, annotations: }.compact
|
{ resource: resource.to_h, annotations: annotations }.compact
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
def define_tool(name: nil, title: nil, description: nil, input_schema: nil, annotations: nil, meta: nil, &block)
|
def define_tool(name: nil, title: nil, description: nil, input_schema: nil, annotations: nil, meta: nil, &block)
|
||||||
tool = Tool.define(name:, title:, description:, input_schema:, annotations:, meta:, &block)
|
tool = Tool.define(name: name, title: title, description: description, input_schema: input_schema, annotations: annotations, meta: meta, &block)
|
||||||
tool_name = tool.name_value
|
tool_name = tool.name_value
|
||||||
|
|
||||||
@tool_names << tool_name
|
@tool_names << tool_name
|
||||||
|
|
@ -124,7 +124,7 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
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: name, title: title, description: description, arguments: arguments, &block)
|
||||||
@prompts[prompt.name_value] = prompt
|
@prompts[prompt.name_value] = prompt
|
||||||
|
|
||||||
validate!
|
validate!
|
||||||
|
|
@ -289,11 +289,11 @@ module MCP
|
||||||
|
|
||||||
def server_info
|
def server_info
|
||||||
@server_info ||= {
|
@server_info ||= {
|
||||||
description:,
|
description: description,
|
||||||
icons:,
|
icons: icons,
|
||||||
name:,
|
name: name,
|
||||||
title:,
|
title: title,
|
||||||
version:,
|
version: version,
|
||||||
websiteUrl: website_url,
|
websiteUrl: website_url,
|
||||||
}.compact
|
}.compact
|
||||||
end
|
end
|
||||||
|
|
@ -316,13 +316,13 @@ module MCP
|
||||||
|
|
||||||
tool = tools[tool_name]
|
tool = tools[tool_name]
|
||||||
unless tool
|
unless tool
|
||||||
add_instrumentation_data(tool_name:, error: :tool_not_found)
|
add_instrumentation_data(tool_name: tool_name, error: :tool_not_found)
|
||||||
|
|
||||||
return error_tool_response("Tool not found: #{tool_name}")
|
return error_tool_response("Tool not found: #{tool_name}")
|
||||||
end
|
end
|
||||||
|
|
||||||
arguments = request[:arguments] || {}
|
arguments = request[:arguments] || {}
|
||||||
add_instrumentation_data(tool_name:)
|
add_instrumentation_data(tool_name: tool_name)
|
||||||
|
|
||||||
if tool.input_schema&.missing_required_arguments?(arguments)
|
if tool.input_schema&.missing_required_arguments?(arguments)
|
||||||
add_instrumentation_data(error: :missing_required_arguments)
|
add_instrumentation_data(error: :missing_required_arguments)
|
||||||
|
|
@ -360,7 +360,7 @@ module MCP
|
||||||
raise RequestHandlerError.new("Prompt not found #{prompt_name}", request, error_type: :prompt_not_found)
|
raise RequestHandlerError.new("Prompt not found #{prompt_name}", request, error_type: :prompt_not_found)
|
||||||
end
|
end
|
||||||
|
|
||||||
add_instrumentation_data(prompt_name:)
|
add_instrumentation_data(prompt_name: prompt_name)
|
||||||
|
|
||||||
prompt_args = request[:arguments]
|
prompt_args = request[:arguments]
|
||||||
prompt.validate_arguments!(prompt_args)
|
prompt.validate_arguments!(prompt_args)
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ module MCP
|
||||||
|
|
||||||
notification = {
|
notification = {
|
||||||
jsonrpc: "2.0",
|
jsonrpc: "2.0",
|
||||||
method:,
|
method: method,
|
||||||
}
|
}
|
||||||
notification[:params] = params if params
|
notification[:params] = params if params
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ module MCP
|
||||||
idempotentHint: idempotent_hint,
|
idempotentHint: idempotent_hint,
|
||||||
openWorldHint: open_world_hint,
|
openWorldHint: open_world_hint,
|
||||||
readOnlyHint: read_only_hint,
|
readOnlyHint: read_only_hint,
|
||||||
title:,
|
title: title,
|
||||||
}.compact
|
}.compact
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
{ content:, isError: error?, structuredContent: @structured_content }.compact
|
{ content: content, isError: error?, structuredContent: @structured_content }.compact
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ Gem::Specification.new do |spec|
|
||||||
spec.homepage = "https://github.com/modelcontextprotocol/ruby-sdk"
|
spec.homepage = "https://github.com/modelcontextprotocol/ruby-sdk"
|
||||||
spec.license = "MIT"
|
spec.license = "MIT"
|
||||||
|
|
||||||
spec.required_ruby_version = ">= 3.2.0"
|
# Since this library is used by a broad range of users, it does not align its support policy with Ruby's EOL.
|
||||||
|
spec.required_ruby_version = ">= 2.7.0"
|
||||||
|
|
||||||
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
||||||
spec.metadata["changelog_uri"] = "https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v#{spec.version}"
|
spec.metadata["changelog_uri"] = "https://github.com/modelcontextprotocol/ruby-sdk/releases/tag/v#{spec.version}"
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ describe JsonRpcHandler do
|
||||||
register("add") { |params| params[:a] + params[:b] }
|
register("add") { |params| params[:a] + params[:b] }
|
||||||
id = "request-123_abc"
|
id = "request-123_abc"
|
||||||
|
|
||||||
handle jsonrpc: "2.0", id:, method: "add", params: { a: 1, b: 2 }
|
handle jsonrpc: "2.0", id: id, method: "add", params: { a: 1, b: 2 }
|
||||||
|
|
||||||
assert_rpc_success expected_result: 3
|
assert_rpc_success expected_result: 3
|
||||||
assert_equal id, @response[:id]
|
assert_equal id, @response[:id]
|
||||||
|
|
@ -104,7 +104,7 @@ describe JsonRpcHandler do
|
||||||
register("add") { |params| params[:a] + params[:b] }
|
register("add") { |params| params[:a] + params[:b] }
|
||||||
id = 42
|
id = 42
|
||||||
|
|
||||||
handle jsonrpc: "2.0", id:, method: "add", params: { a: 1, b: 2 }
|
handle jsonrpc: "2.0", id: id, method: "add", params: { a: 1, b: 2 }
|
||||||
|
|
||||||
assert_rpc_success expected_result: 3
|
assert_rpc_success expected_result: 3
|
||||||
assert_equal id, @response[:id]
|
assert_equal id, @response[:id]
|
||||||
|
|
@ -124,7 +124,7 @@ describe JsonRpcHandler do
|
||||||
register("add") { |params| params[:a] + params[:b] }
|
register("add") { |params| params[:a] + params[:b] }
|
||||||
id = "request-123_ABC"
|
id = "request-123_ABC"
|
||||||
|
|
||||||
handle jsonrpc: "2.0", id:, method: "add", params: { a: 1, b: 2 }
|
handle jsonrpc: "2.0", id: id, method: "add", params: { a: 1, b: 2 }
|
||||||
|
|
||||||
assert_rpc_success expected_result: 3
|
assert_rpc_success expected_result: 3
|
||||||
assert_equal id, @response[:id]
|
assert_equal id, @response[:id]
|
||||||
|
|
@ -134,7 +134,7 @@ describe JsonRpcHandler do
|
||||||
register("add") { |params| params[:a] + params[:b] }
|
register("add") { |params| params[:a] + params[:b] }
|
||||||
id = "550e8400-e29b-41d4-a716-446655440000"
|
id = "550e8400-e29b-41d4-a716-446655440000"
|
||||||
|
|
||||||
handle jsonrpc: "2.0", id:, method: "add", params: { a: 1, b: 2 }
|
handle jsonrpc: "2.0", id: id, method: "add", params: { a: 1, b: 2 }
|
||||||
|
|
||||||
assert_rpc_success expected_result: 3
|
assert_rpc_success expected_result: 3
|
||||||
assert_equal id, @response[:id]
|
assert_equal id, @response[:id]
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue