Skip to content

Commit cfc42db

Browse files
atesgoralclaude
andcommitted
Handle 202 Accepted response in HTTP client
Per the Streamable HTTP spec, a server returns 202 Accepted with no body as the ACK for a JSON-RPC notification or response. The client previously errored on 202 because it fell through Content-Type dispatch. Short-circuit to return nil before Content-Type handling so fire-and-forget messages (e.g. notifications/initialized) no longer raise. https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 5c0fee3 commit cfc42db

3 files changed

Lines changed: 20 additions & 1 deletion

File tree

examples/streamable_http_server.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def call(env)
171171
curl -i http://localhost:9393 -H "Mcp-Session-Id: YOUR_SESSION_ID" \\
172172
--json '{"jsonrpc":"2.0","method":"tools/call","id":3,"params":{"name":"notification_tool","arguments":{"message":"Hello SSE!", "delay": 2}}}'
173173
174-
Note: When an SSE stream is active, tool responses will appear in the SSE stream and the POST request will return {"accepted": true}
174+
Note: When an SSE stream is active, tool responses will appear in the SSE stream and the POST request will return 202 Accepted with no body.
175175
176176
Press Ctrl+C to stop the server
177177
MESSAGE

lib/mcp/client/http.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ def require_event_stream_parser!
100100
end
101101

102102
def parse_response_body(response, method, params)
103+
# 202 Accepted is the server's ACK for a JSON-RPC notification or response; no body is expected.
104+
# https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server
105+
return if response.status == 202
106+
103107
content_type = response.headers["Content-Type"]
104108

105109
if content_type&.include?("text/event-stream")

test/mcp/client/http_test.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,21 @@ def test_send_request_parses_sse_error_response
369369
assert_equal("Invalid request", response.dig("error", "message"))
370370
end
371371

372+
def test_send_request_returns_nil_for_202_accepted_response
373+
request = {
374+
jsonrpc: "2.0",
375+
method: "notifications/initialized",
376+
}
377+
378+
stub_request(:post, url)
379+
.with(body: request.to_json)
380+
.to_return(status: 202, body: "")
381+
382+
response = client.send_request(request: request)
383+
384+
assert_nil(response)
385+
end
386+
372387
def test_send_request_raises_error_for_sse_without_response
373388
request = {
374389
jsonrpc: "2.0",

0 commit comments

Comments
 (0)