From caa126afc4d74f77339f49086e4b66e915ad8515 Mon Sep 17 00:00:00 2001 From: Dominik Klein Date: Wed, 14 Oct 2026 22:14:50 +0200 Subject: [PATCH] Accept any string as a request id MCP allows any string as a request id, but the server passed requests to JsonRpcHandler with its default pattern, which only accepts letters, digits, "_" and "-". Fixes #603. --- lib/mcp/server.rb | 4 ++-- test/mcp/server_test.rb | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/mcp/server.rb b/lib/mcp/server.rb index afb3e845..c6dedf57 100644 --- a/lib/mcp/server.rb +++ b/lib/mcp/server.rb @@ -285,7 +285,7 @@ def initialize( # handlers as `server_context.auth_info`. # @return [Hash, nil] The JSON-RPC response, or `nil` for notifications. def handle(request, session: nil, auth_info: nil) - JsonRpcHandler.handle(request) do |method, request_id| + JsonRpcHandler.handle(request, id_validation_pattern: nil) do |method, request_id| handle_request(request, method, session: session, related_request_id: request_id, auth_info: auth_info) end end @@ -300,7 +300,7 @@ def handle(request, session: nil, auth_info: nil) # for the current request, as in `handle`. # @return [String, nil] The JSON-RPC response as JSON, or `nil` for notifications. def handle_json(request, session: nil, auth_info: nil) - JsonRpcHandler.handle_json(request) do |method, request_id| + JsonRpcHandler.handle_json(request, id_validation_pattern: nil) do |method, request_id| handle_request(request, method, session: session, related_request_id: request_id, auth_info: auth_info) end end diff --git a/test/mcp/server_test.rb b/test/mcp/server_test.rb index c1ac383f..2e6f2d87 100644 --- a/test/mcp/server_test.rb +++ b/test/mcp/server_test.rb @@ -125,6 +125,21 @@ class ServerTest < ActiveSupport::TestCase assert_instrumentation_data({ method: "ping" }) end + # https://modelcontextprotocol.io/specification/latest/basic#requests + test "#handle accepts any string as request id" do + ["req.1", "call:42", "urn:uuid:5e7f1b2c-0c1a-4d6e-9f3b-2a8c7d6e5f4a"].each do |id| + response = @server.handle({ jsonrpc: "2.0", method: "ping", id: id }) + + assert_equal({ jsonrpc: "2.0", id: id, result: {} }, response) + end + end + + test "#handle_json accepts any string as request id" do + response = JSON.parse(@server.handle_json(JSON.generate({ jsonrpc: "2.0", method: "ping", id: "req.1" })), symbolize_names: true) + + assert_equal({ jsonrpc: "2.0", id: "req.1", result: {} }, response) + end + test "#handle server/discover returns supported versions, capabilities, server info, and instructions" do response = @server.handle({ jsonrpc: "2.0", method: "server/discover", id: 1 }) result = response[:result]