@@ -575,6 +575,111 @@ class StreamableHTTPTransportTest < ActiveSupport::TestCase
575575 assert_equal "Method not allowed" , body [ "error" ]
576576 end
577577
578+ test "stateless mode allows requests without session IDs, responding with a new session ID" do
579+ stateless_transport = StreamableHTTPTransport . new ( @server , stateless : true )
580+
581+ init_request = create_rack_request (
582+ "POST" ,
583+ "/" ,
584+ { "CONTENT_TYPE" => "application/json" } ,
585+ { jsonrpc : "2.0" , method : "initialize" , id : "init" } . to_json ,
586+ )
587+ init_response = stateless_transport . handle_request ( init_request )
588+ session_id = init_response [ 1 ] [ "Mcp-Session-Id" ]
589+
590+ assert_not_nil session_id
591+ end
592+
593+ test "stateless mode responds without any session ID when session ID is present" do
594+ stateless_transport = StreamableHTTPTransport . new ( @server , stateless : true )
595+
596+ request = create_rack_request (
597+ "POST" ,
598+ "/" ,
599+ {
600+ "CONTENT_TYPE" => "application/json" ,
601+ "HTTP_MCP_SESSION_ID" => "unseen_session_id" ,
602+ } ,
603+ { jsonrpc : "2.0" , method : "ping" , id : "123" } . to_json ,
604+ )
605+
606+ response = stateless_transport . handle_request ( request )
607+ assert_equal 200 , response [ 0 ]
608+ assert_equal (
609+ {
610+ "Content-Type" => "application/json" ,
611+ } ,
612+ response [ 1 ] ,
613+ )
614+
615+ body = JSON . parse ( response [ 2 ] [ 0 ] )
616+ assert_equal "2.0" , body [ "jsonrpc" ]
617+ assert_equal "123" , body [ "id" ]
618+ end
619+
620+ test "stateless mode responds with 405 when SSE is requested" do
621+ stateless_transport = StreamableHTTPTransport . new ( @server , stateless : true )
622+
623+ get_request = create_rack_request (
624+ "GET" ,
625+ "/" ,
626+ {
627+ "CONTENT_TYPE" => "application/json,text/event-stream" ,
628+ } ,
629+ )
630+ response = stateless_transport . handle_request ( get_request )
631+ assert_equal 405 , response [ 0 ]
632+ assert_equal ( { "Content-Type" => "application/json" } , response [ 1 ] )
633+
634+ body = JSON . parse ( response [ 2 ] [ 0 ] )
635+ assert_equal "Method not allowed" , body [ "error" ]
636+ end
637+
638+ test "stateless mode silently responds with success to session DELETE when session ID is not present" do
639+ stateless_transport = StreamableHTTPTransport . new ( @server , stateless : true )
640+
641+ delete_request = create_rack_request (
642+ "DELETE" ,
643+ "/" ,
644+ { } ,
645+ )
646+ response = stateless_transport . handle_request ( delete_request )
647+ assert_equal 200 , response [ 0 ]
648+ assert_equal ( { "Content-Type" => "application/json" } , response [ 1 ] )
649+
650+ body = JSON . parse ( response [ 2 ] [ 0 ] )
651+ assert body [ "success" ]
652+ end
653+
654+ test "stateless mode silently responds with success to session DELETE when session ID is provided" do
655+ stateless_transport = StreamableHTTPTransport . new ( @server , stateless : true )
656+
657+ delete_request = create_rack_request (
658+ "DELETE" ,
659+ "/" ,
660+ { "HTTP_MCP_SESSION_ID" => "session_id" } ,
661+ )
662+ response = stateless_transport . handle_request ( delete_request )
663+ assert_equal 200 , response [ 0 ]
664+ assert_equal ( { "Content-Type" => "application/json" } , response [ 1 ] )
665+
666+ body = JSON . parse ( response [ 2 ] [ 0 ] )
667+ assert body [ "success" ]
668+ end
669+
670+ test "stateless mode does not support notifications" do
671+ stateless_transport = StreamableHTTPTransport . new ( @server , stateless : true )
672+
673+ # There are no sessions, so this should fail
674+ assert_raises ( RuntimeError , "Stateless mode does not support notifications" ) do
675+ stateless_transport . send_notification (
676+ "test_notification" ,
677+ { message : "Hello" } ,
678+ session_id : "some_session_id" ,
679+ )
680+ end
681+ end
682+
578683 test "handle post request with a standard error" do
579684 request = create_rack_request (
580685 "POST" ,
0 commit comments