From 805e020d4021f0acb65b601bf215a96619e206c3 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Thu, 26 Mar 2026 04:34:15 +0900 Subject: [PATCH] Remove undocumented handler override methods ## Motivation and Context The following public methods allow replacing the SDK's built-in request handlers: - `tools_call_handler` - `tools_list_handler` - `resources_list_handler` - `resources_templates_list_handler` - `prompts_list_handler` - `prompts_get_handler` These were introduced in Internal Release 0.2.0 (https://github.com/modelcontextprotocol/ruby-sdk/commit/6004f42) as part of "allow setting handlers on Server", before declarative APIs (`define_tool`, `Prompt` class, `Resource` class) were fully established. Now that those declarative APIs exist, these handler overrides are redundant: none are documented in the README.md, and no usage exists outside of the SDK's own tests. These handler overrides also create architectural problems. Since custom handlers cannot receive session context, they would not work correctly with a per-session architecture, such as session-scoped notifications. ### Changes - Removed `tools_call_handler`, `tools_list_handler`, `resources_list_handler`, `resources_templates_list_handler`, `prompts_list_handler`, and `prompts_get_handler` from `Server`. - Removed the associated tests. - Retained `resources_read_handler` (documented in the README.md and actively used in examples and conformance server, because resource reading is application-specific). ## Breaking Change The following methods are removed without a deprecation period: `tools_call_handler`, `tools_list_handler`, `resources_list_handler`, `resources_templates_list_handler`, `prompts_list_handler`, `prompts_get_handler`. These were never documented in the README.md and have no known usage outside of the SDK's own tests. As a result, little to no impact on users is expected, and a deprecation warning would have no practical audience. Users who relied on these should use `define_tool`, prompt/resource registration, or `resources_read_handler` instead. --- lib/mcp/server.rb | 30 ++-------- test/mcp/server_test.rb | 123 ---------------------------------------- 2 files changed, 6 insertions(+), 147 deletions(-) diff --git a/lib/mcp/server.rb b/lib/mcp/server.rb index 52552072..9badde5b 100644 --- a/lib/mcp/server.rb +++ b/lib/mcp/server.rb @@ -199,34 +199,16 @@ def notify_log_message(data:, level:, logger: nil) report_exception(e, { notification: "log_message" }) end - def resources_list_handler(&block) - @handlers[Methods::RESOURCES_LIST] = block - end - + # Sets a custom handler for `resources/read` requests. + # The block receives the parsed request params and should return resource + # contents. The return value is set as the `contents` field of the response. + # + # @yield [params] The request params containing `:uri`. + # @yieldreturn [Array, Hash] Resource contents. def resources_read_handler(&block) @handlers[Methods::RESOURCES_READ] = block end - def resources_templates_list_handler(&block) - @handlers[Methods::RESOURCES_TEMPLATES_LIST] = block - end - - def tools_list_handler(&block) - @handlers[Methods::TOOLS_LIST] = block - end - - def tools_call_handler(&block) - @handlers[Methods::TOOLS_CALL] = block - end - - def prompts_list_handler(&block) - @handlers[Methods::PROMPTS_LIST] = block - end - - def prompts_get_handler(&block) - @handlers[Methods::PROMPTS_GET] = block - end - private def validate! diff --git a/test/mcp/server_test.rb b/test/mcp/server_test.rb index fac919b6..1b124123 100644 --- a/test/mcp/server_test.rb +++ b/test/mcp/server_test.rb @@ -270,23 +270,6 @@ class ServerTest < ActiveSupport::TestCase assert_equal({ foo: "bar" }, result[:tools][0][:_meta]) end - test "#tools_list_handler sets the tools/list handler" do - @server.tools_list_handler do - [{ name: "hammer", description: "Hammer time!" }] - end - - request = { - jsonrpc: "2.0", - method: "tools/list", - id: 1, - } - - response = @server.handle(request) - result = response[:result] - assert_equal({ tools: [{ name: "hammer", description: "Hammer time!" }] }, result) - assert_instrumentation_data({ method: "tools/list" }) - end - test "#handle tools/call executes tool and returns result" do tool_name = "test_tool" tool_args = { arg: "value" } @@ -564,24 +547,6 @@ class Example < Tool assert_includes response[:error][:data], "Tool not found: unknown_tool" end - test "#tools_call_handler sets the tools/call handler" do - @server.tools_call_handler do |request| - tool_name = request[:name] - Tool::Response.new("#{tool_name} called successfully").to_h - end - - request = { - jsonrpc: "2.0", - method: "tools/call", - params: { name: "my_tool", arguments: {} }, - id: 1, - } - - response = @server.handle(request) - assert_equal({ content: "my_tool called successfully", isError: false }, response[:result]) - assert_instrumentation_data({ method: "tools/call" }) - end - test "#handle prompts/list returns list of prompts" do request = { jsonrpc: "2.0", @@ -594,22 +559,6 @@ class Example < Tool assert_instrumentation_data({ method: "prompts/list" }) end - test "#prompts_list_handler sets the prompts/list handler" do - @server.prompts_list_handler do - [{ name: "foo_prompt", description: "Foo prompt" }] - end - - request = { - jsonrpc: "2.0", - method: "prompts/list", - id: 1, - } - - response = @server.handle(request) - assert_equal({ prompts: [{ name: "foo_prompt", description: "Foo prompt" }] }, response[:result]) - assert_instrumentation_data({ method: "prompts/list" }) - end - test "#handle prompts/get returns templated prompt" do request = { jsonrpc: "2.0", @@ -669,32 +618,6 @@ class Example < Tool }) end - test "#prompts_get_handler sets the prompts/get handler" do - @server.prompts_get_handler do |request| - prompt_name = request[:name] - Prompt::Result.new( - description: prompt_name, - messages: [ - Prompt::Message.new(role: "user", content: Content::Text.new(request[:arguments]["foo"])), - ], - ).to_h - end - - request = { - jsonrpc: "2.0", - method: "prompts/get", - id: 1, - params: { name: "foo_bar_prompt", arguments: { "foo" => "bar" } }, - } - - response = @server.handle(request) - assert_equal( - { description: "foo_bar_prompt", messages: [{ role: "user", content: { type: "text", text: "bar" } }] }, - response[:result], - ) - assert_instrumentation_data({ method: "prompts/get" }) - end - test "#handle resources/list returns a list of resources" do request = { jsonrpc: "2.0", @@ -707,25 +630,6 @@ class Example < Tool assert_instrumentation_data({ method: "resources/list" }) end - test "#resources_list_handler sets the resources/list handler" do - @server.resources_list_handler do - [{ uri: "https://test_resource.invalid", name: "test-resource", title: "Test Resource", description: "Test resource" }] - end - - request = { - jsonrpc: "2.0", - method: "resources/list", - id: 1, - } - - response = @server.handle(request) - assert_equal( - { resources: [{ uri: "https://test_resource.invalid", name: "test-resource", title: "Test Resource", description: "Test resource" }] }, - response[:result], - ) - assert_instrumentation_data({ method: "resources/list" }) - end - test "#handle resources/read returns an empty array of contents by default" do request = { jsonrpc: "2.0", @@ -783,33 +687,6 @@ class Example < Tool assert_instrumentation_data({ method: "resources/templates/list" }) end - test "#resources_templates_list_handler sets the resources/templates/list handler" do - @server.resources_templates_list_handler do - [{ uriTemplate: "test_resource_template/{id}", name: "Test resource template", description: "a template" }] - end - - request = { - jsonrpc: "2.0", - method: "resources/templates/list", - id: 1, - } - - response = @server.handle(request) - assert_equal( - { - resourceTemplates: [ - { - uriTemplate: "test_resource_template/{id}", - name: "Test resource template", - description: "a template", - }, - ], - }, - response[:result], - ) - assert_instrumentation_data({ method: "resources/templates/list" }) - end - test "#configure_logging_level returns empty hash on success" do response = @server.handle( {