@@ -575,6 +575,111 @@ class StreamableHTTPTransportTest < ActiveSupport::TestCase
575
575
assert_equal "Method not allowed" , body [ "error" ]
576
576
end
577
577
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
+
578
683
test "handle post request with a standard error" do
579
684
request = create_rack_request (
580
685
"POST" ,
0 commit comments