Skip to content

Commit 160d64d

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 541bbe0 commit 160d64d

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
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,8 @@ 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+
handle_notification_or_response
113113
else
114114
handle_regular_request(body_string, session_id)
115115
end
@@ -168,6 +168,11 @@ def parse_request_body(body_string)
168168
[400, { "Content-Type" => "application/json" }, [{ error: "Invalid JSON" }.to_json]]
169169
end
170170

171+
def notification_or_response?(body)
172+
# Check if the body is a notification or a response
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: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,62 @@ class StreamableHTTPTransportTest < ActiveSupport::TestCase
622622
assert_empty(response[2])
623623
end
624624

625+
test "handles POST request when JSON-RPC notification object is received" do
626+
notification_request = create_rack_request(
627+
"POST",
628+
"/",
629+
{ "CONTENT_TYPE" => "application/json" },
630+
{ jsonrpc: "2.0", method: "some_notification" }.to_json,
631+
)
632+
633+
response = @transport.handle_request(notification_request)
634+
assert_equal 202, response[0]
635+
assert_empty(response[1])
636+
assert_empty(response[2])
637+
end
638+
639+
test "handles POST request when JSON-RPC response object with result is received" do
640+
response_request = create_rack_request(
641+
"POST",
642+
"/",
643+
{ "CONTENT_TYPE" => "application/json" },
644+
{ jsonrpc: "2.0", id: "123", result: { content: { type: "text" } } }.to_json,
645+
)
646+
647+
response = @transport.handle_request(response_request)
648+
assert_equal 202, response[0]
649+
assert_empty(response[1])
650+
assert_empty(response[2])
651+
end
652+
653+
test "handles POST request when JSON-RPC response object with error is received" do
654+
response_request = create_rack_request(
655+
"POST",
656+
"/",
657+
{ "CONTENT_TYPE" => "application/json" },
658+
{ jsonrpc: "2.0", id: "123", error: { content: { type: "text" } } }.to_json,
659+
)
660+
661+
response = @transport.handle_request(response_request)
662+
assert_equal 202, response[0]
663+
assert_empty(response[1])
664+
assert_empty(response[2])
665+
end
666+
667+
test "handles POST request when JSON-RPC error object is received" do
668+
response_request = create_rack_request(
669+
"POST",
670+
"/",
671+
{ "CONTENT_TYPE" => "application/json" },
672+
{ jsonrpc: "2.0", id: "123", error: { content: { type: "text" } } }.to_json,
673+
)
674+
675+
response = @transport.handle_request(response_request)
676+
assert_equal 202, response[0]
677+
assert_empty(response[1])
678+
assert_empty(response[2])
679+
end
680+
625681
private
626682

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

0 commit comments

Comments
 (0)