Skip to content

Commit 5425c9c

Browse files
authored
Merge pull request #455 from koic/reject_notifications_for_unknown_sessions
Reject notifications carrying an unknown or expired session
2 parents 1101900 + 6236ea1 commit 5425c9c

2 files changed

Lines changed: 39 additions & 0 deletions

File tree

lib/mcp/server/transports/streamable_http_transport.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,11 @@ def handle_post(request)
517517
end
518518

519519
if notification?(body)
520+
# Reject a notification carrying an unknown or expired session ID instead of
521+
# dispatching it against the shared `Server`. Mirrors the response and regular-request
522+
# branches; without it a custom notification handler could run without a live session.
523+
return session_not_found_response if !@stateless && !session_active?(session_id)
524+
520525
dispatch_notification(body_string, session_id)
521526
handle_accepted
522527
elsif response?(body)

test/mcp/server/transports/streamable_http_transport_test.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,40 @@ def string
525525
assert_equal "Missing session ID", body["error"]["message"]
526526
end
527527

528+
test "rejects notification with an unknown session ID in stateful mode" do
529+
request = create_rack_request(
530+
"POST",
531+
"/",
532+
{ "CONTENT_TYPE" => "application/json", "HTTP_MCP_SESSION_ID" => "does-not-exist" },
533+
{ jsonrpc: "2.0", method: "notifications/initialized" }.to_json,
534+
)
535+
536+
response = @transport.handle_request(request)
537+
assert_equal 404, response[0]
538+
body = JSON.parse(response[2][0])
539+
assert_equal "Session not found", body["error"]["message"]
540+
end
541+
542+
test "accepts a notification carrying a live session ID in stateful mode" do
543+
init_request = create_rack_request(
544+
"POST",
545+
"/",
546+
{ "CONTENT_TYPE" => "application/json" },
547+
{ jsonrpc: "2.0", method: "initialize", id: "init", params: initialize_params }.to_json,
548+
)
549+
session_id = @transport.handle_request(init_request)[1]["Mcp-Session-Id"]
550+
551+
notification = create_rack_request(
552+
"POST",
553+
"/",
554+
{ "CONTENT_TYPE" => "application/json", "HTTP_MCP_SESSION_ID" => session_id },
555+
{ jsonrpc: "2.0", method: "notifications/initialized" }.to_json,
556+
)
557+
558+
response = @transport.handle_request(notification)
559+
assert_equal 202, response[0]
560+
end
561+
528562
test "rejects response without session ID in stateful mode" do
529563
request = create_rack_request(
530564
"POST",

0 commit comments

Comments
 (0)