diff --git a/lib/mcp/server.rb b/lib/mcp/server.rb index afb3e845..aadf9206 100644 --- a/lib/mcp/server.rb +++ b/lib/mcp/server.rb @@ -648,7 +648,14 @@ def handle_request(request, method, session: nil, related_request_id: nil, auth_ # Re-raise through RequestHandlerError, the one channel whose message is # deliberately surfaced to clients: `JsonRpcHandler`'s blind `rescue StandardError` # no longer echoes exception messages into the error `data` member (CWE-209). - raise RequestHandlerError.new(e.message, request, error_type: :internal_error, original_error: e) + # A server that does not declare a capability does not implement its methods, hence Method not found. + raise RequestHandlerError.new( + e.message, + request, + error_type: :method_not_found, + error_code: JsonRpcHandler::ErrorCode::METHOD_NOT_FOUND, + original_error: e, + ) end # `initialize` MUST NOT be cancelled (MCP spec 2025-11-25, cancellation item 2), diff --git a/test/mcp/server/transports/streamable_http_transport_test.rb b/test/mcp/server/transports/streamable_http_transport_test.rb index 1e1ebc7a..991b22fd 100644 --- a/test/mcp/server/transports/streamable_http_transport_test.rb +++ b/test/mcp/server/transports/streamable_http_transport_test.rb @@ -6100,6 +6100,17 @@ def string end end + test "modern POST answers a method of an undeclared capability with 404 and -32601" do + @server.capabilities = { tools: {} } + + response = @transport.handle_request(modern_rack_request(modern_body("prompts/list", {}))) + + assert_equal 404, response[0] + body = JSON.parse(response[2][0]) + assert_equal(-32601, body.dig("error", "code")) + assert_equal "Server does not support prompts (required for prompts/list)", body.dig("error", "message") + end + test "modern POST maps a missing client capability to 400 with -32021" do @server.define_tool(name: "guarded_tool") do |server_context:| server_context.require_client_capability!(:elicitation, :form) diff --git a/test/mcp/server_test.rb b/test/mcp/server_test.rb index c1ac383f..f2c0f9cc 100644 --- a/test/mcp/server_test.rb +++ b/test/mcp/server_test.rb @@ -1880,7 +1880,7 @@ def read_resource_request(uri) assert_equal "2.0", response[:jsonrpc] assert_equal 1, response[:id] - assert_equal(-32603, response[:error][:code]) + assert_equal(-32601, response[:error][:code]) assert_includes response[:error][:data], "Server does not support logging" end @@ -1888,15 +1888,18 @@ def read_resource_request(uri) @server.capabilities = {} response = @server.handle({ jsonrpc: "2.0", method: "prompts/list", id: 1 }) + assert_equal(-32601, response[:error][:code]) assert_equal "Server does not support prompts (required for prompts/list)", response[:error][:data] response = @server.handle({ jsonrpc: "2.0", method: "resources/list", id: 1 }) + assert_equal(-32601, response[:error][:code]) assert_equal "Server does not support resources (required for resources/list)", response[:error][:data] end test "#handle method with missing required nested capability returns an error" do @server.capabilities = { resources: {} } response = @server.handle({ jsonrpc: "2.0", method: "resources/subscribe", id: 1 }) + assert_equal(-32601, response[:error][:code]) assert_equal "Server does not support resources.subscribe (required for resources/subscribe)", response[:error][:data] end