diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9077935a..66107452 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: entry: - - { ruby: '2.7', allowed-failure: false } + - { ruby: '2.7.0', allowed-failure: false } # Minimum supported Ruby version. - { ruby: '3.0', allowed-failure: false } - { ruby: '3.1', allowed-failure: false } - { ruby: '3.2', allowed-failure: false } diff --git a/lib/mcp/server_context.rb b/lib/mcp/server_context.rb index baed180b..98739842 100644 --- a/lib/mcp/server_context.rb +++ b/lib/mcp/server_context.rb @@ -130,9 +130,14 @@ def notify_elicitation_complete(**kwargs) end end - def method_missing(name, ...) + # Forward arguments explicitly with `*args, **kwargs, &block` rather than the `...` forwarding syntax. + # The gem supports Ruby 2.7.0 (see `required_ruby_version`), but RuboCop's Parser backend only runs on Ruby 2.7.8, + # so leading-argument forwarding like `def method_missing(name, ...)` is allowed by the linter even though it + # raises a `SyntaxError` on Ruby 2.7.0 through 2.7.2 (it was added in Ruby 2.7.3). Explicit forwarding keeps + # this method loadable on Ruby 2.7.0. + def method_missing(name, *args, **kwargs, &block) if @context.respond_to?(name) - @context.public_send(name, ...) + @context.public_send(name, *args, **kwargs, &block) else super end diff --git a/test/mcp/server_context_test.rb b/test/mcp/server_context_test.rb index 86fd972d..44fa12e4 100644 --- a/test/mcp/server_context_test.rb +++ b/test/mcp/server_context_test.rb @@ -201,6 +201,20 @@ def context.custom_method assert_equal "custom_value", server_context.custom_method end + test "ServerContext forwards positional, keyword, and block arguments to the context" do + context = Object.new + def context.combine(prefix, suffix:, &block) + block.call("#{prefix}-#{suffix}") + end + progress = Progress.new(notification_target: mock, progress_token: nil) + + server_context = ServerContext.new(context, progress: progress, notification_target: mock) + + result = server_context.combine("a", suffix: "b", &:upcase) + + assert_equal "A-B", result + end + test "ServerContext#report_progress works with nil context" do progress = mock progress.expects(:report).with(50, total: 100, message: nil).once diff --git a/test/test_helper.rb b/test/test_helper.rb index 19e9974b..b89bffad 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -6,6 +6,16 @@ require "minitest/mock" require "mocha/minitest" +# mocha relies on `Hash.ruby2_keywords_hash?`, which is absent on Ruby 2.7.0 and the earlier 2.7.x releases +# before it was backported. Those versions also lack the flag-setting APIs, so no hash is ever flagged as +# ruby2_keywords and returning `false` is correct. Without this shim, mocha raises `NoMethodError` and +# the suite cannot run on Ruby 2.7.0. +unless Hash.respond_to?(:ruby2_keywords_hash?) + def Hash.ruby2_keywords_hash?(_hash) + false + end +end + require "active_support" require "active_support/test_case"