## 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.
118 lines
3.5 KiB
Ruby
118 lines
3.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module MCP
|
|
class Configuration
|
|
LATEST_STABLE_PROTOCOL_VERSION = "2025-11-25"
|
|
SUPPORTED_STABLE_PROTOCOL_VERSIONS = [
|
|
LATEST_STABLE_PROTOCOL_VERSION, "2025-06-18", "2025-03-26", "2024-11-05",
|
|
]
|
|
|
|
attr_writer :exception_reporter, :instrumentation_callback
|
|
|
|
def initialize(exception_reporter: nil, instrumentation_callback: nil, protocol_version: nil,
|
|
validate_tool_call_arguments: true)
|
|
@exception_reporter = exception_reporter
|
|
@instrumentation_callback = instrumentation_callback
|
|
@protocol_version = protocol_version
|
|
if protocol_version
|
|
validate_protocol_version!(protocol_version)
|
|
end
|
|
validate_value_of_validate_tool_call_arguments!(validate_tool_call_arguments)
|
|
|
|
@validate_tool_call_arguments = validate_tool_call_arguments
|
|
end
|
|
|
|
def protocol_version=(protocol_version)
|
|
validate_protocol_version!(protocol_version)
|
|
|
|
@protocol_version = protocol_version
|
|
end
|
|
|
|
def validate_tool_call_arguments=(validate_tool_call_arguments)
|
|
validate_value_of_validate_tool_call_arguments!(validate_tool_call_arguments)
|
|
|
|
@validate_tool_call_arguments = validate_tool_call_arguments
|
|
end
|
|
|
|
def protocol_version
|
|
@protocol_version || LATEST_STABLE_PROTOCOL_VERSION
|
|
end
|
|
|
|
def protocol_version?
|
|
!@protocol_version.nil?
|
|
end
|
|
|
|
def exception_reporter
|
|
@exception_reporter || default_exception_reporter
|
|
end
|
|
|
|
def exception_reporter?
|
|
!@exception_reporter.nil?
|
|
end
|
|
|
|
def instrumentation_callback
|
|
@instrumentation_callback || default_instrumentation_callback
|
|
end
|
|
|
|
def instrumentation_callback?
|
|
!@instrumentation_callback.nil?
|
|
end
|
|
|
|
attr_reader :validate_tool_call_arguments
|
|
|
|
def validate_tool_call_arguments?
|
|
!!@validate_tool_call_arguments
|
|
end
|
|
|
|
def merge(other)
|
|
return self if other.nil?
|
|
|
|
exception_reporter = if other.exception_reporter?
|
|
other.exception_reporter
|
|
else
|
|
@exception_reporter
|
|
end
|
|
instrumentation_callback = if other.instrumentation_callback?
|
|
other.instrumentation_callback
|
|
else
|
|
@instrumentation_callback
|
|
end
|
|
protocol_version = if other.protocol_version?
|
|
other.protocol_version
|
|
else
|
|
@protocol_version
|
|
end
|
|
validate_tool_call_arguments = other.validate_tool_call_arguments
|
|
|
|
Configuration.new(
|
|
exception_reporter: exception_reporter,
|
|
instrumentation_callback: instrumentation_callback,
|
|
protocol_version: protocol_version,
|
|
validate_tool_call_arguments: validate_tool_call_arguments,
|
|
)
|
|
end
|
|
|
|
private
|
|
|
|
def validate_protocol_version!(protocol_version)
|
|
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
|
|
|
|
def validate_value_of_validate_tool_call_arguments!(validate_tool_call_arguments)
|
|
unless validate_tool_call_arguments.is_a?(TrueClass) || validate_tool_call_arguments.is_a?(FalseClass)
|
|
raise ArgumentError, "validate_tool_call_arguments must be a boolean"
|
|
end
|
|
end
|
|
|
|
def default_exception_reporter
|
|
@default_exception_reporter ||= ->(exception, server_context) {}
|
|
end
|
|
|
|
def default_instrumentation_callback
|
|
@default_instrumentation_callback ||= ->(data) {}
|
|
end
|
|
end
|
|
end
|