Skip to content

Commit 07ee3d6

Browse files
committed
Fix to return a response code 202 if the server accepts JSON-RPC notifications and responses
If the server accepts JSON-RPC notifications and responses, it must return an HTTP status code of 202 without a body. refs - https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#sending-messages-to-the-server - https://www.jsonrpc.org/specification Follow up: #111
1 parent eb0d9c0 commit 07ee3d6

File tree

2 files changed

+45
-4
lines changed

2 files changed

+45
-4
lines changed

lib/mcp/server/transports/streamable_http_transport.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ def handle_post(request)
108108

109109
if body["method"] == "initialize"
110110
handle_initialization(body_string, body)
111-
elsif body["method"] == MCP::Methods::NOTIFICATIONS_INITIALIZED
112-
handle_notification_initialized
111+
elsif notification_or_response?(body)
112+
# For notifications and responses only, return 202 Accepted
113+
handle_notification_or_response
113114
else
114115
handle_regular_request(body_string, session_id)
115116
end
@@ -168,6 +169,10 @@ def parse_request_body(body_string)
168169
[400, { "Content-Type" => "application/json" }, [{ error: "Invalid JSON" }.to_json]]
169170
end
170171

172+
def notification_or_response?(body)
173+
!(body["id"] && body["method"])
174+
end
175+
171176
def handle_initialization(body_string, body)
172177
session_id = SecureRandom.uuid
173178

@@ -187,7 +192,7 @@ def handle_initialization(body_string, body)
187192
[200, headers, [response]]
188193
end
189194

190-
def handle_notification_initialized
195+
def handle_notification_or_response
191196
[202, {}, []]
192197
end
193198

test/mcp/server/transports/streamable_http_transport_test.rb

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ class Server
88
module Transports
99
class StreamableHTTPTransportTest < ActiveSupport::TestCase
1010
setup do
11+
tool = Tool.define(
12+
name: "test_tool",
13+
title: "Test tool",
14+
description: "A test tool",
15+
)
16+
1117
@server = Server.new(
1218
name: "test_server",
13-
tools: [],
19+
tools: [tool],
1420
prompts: [],
1521
resources: [],
1622
)
@@ -620,6 +626,36 @@ class StreamableHTTPTransportTest < ActiveSupport::TestCase
620626
assert_empty(response[2])
621627
end
622628

629+
test "POST tools/list returns 200 with body" do
630+
init_request = create_rack_request(
631+
"POST",
632+
"/",
633+
{ "CONTENT_TYPE" => "application/json" },
634+
{ jsonrpc: "2.0", method: "initialize", id: "init" }.to_json,
635+
)
636+
init_response = @transport.handle_request(init_request)
637+
session_id = init_response[1]["Mcp-Session-Id"]
638+
639+
request = create_rack_request(
640+
"POST",
641+
"/",
642+
{
643+
"CONTENT_TYPE" => "application/json",
644+
"HTTP_MCP_SESSION_ID" => session_id,
645+
},
646+
{ jsonrpc: "2.0", method: MCP::Methods::TOOLS_LIST, id: "123" }.to_json,
647+
)
648+
649+
response = @transport.handle_request(request)
650+
assert_equal 200, response[0]
651+
assert_equal({ "Content-Type" => "application/json" }, response[1])
652+
653+
body = JSON.parse(response[2][0])
654+
assert_equal "2.0", body["jsonrpc"]
655+
assert_equal "123", body["id"]
656+
assert_equal "test_tool", body["result"]["tools"][0]["name"]
657+
end
658+
623659
private
624660

625661
def create_rack_request(method, path, headers, body = nil)

0 commit comments

Comments
 (0)