@@ -842,8 +842,8 @@ describe("StreamableHTTPServerTransport", () => {
842
842
} ,
843
843
body : JSON . stringify ( initMessage ) ,
844
844
} ) ;
845
-
846
- await transport . handleRequest ( initReq , mockResponse ) ;
845
+ const initResponse = createMockResponse ( ) ;
846
+ await transport . handleRequest ( initReq , initResponse ) ;
847
847
mockResponse . writeHead . mockClear ( ) ;
848
848
} ) ;
849
849
@@ -934,17 +934,17 @@ describe("StreamableHTTPServerTransport", () => {
934
934
// Now stream should be closed
935
935
expect ( mockResponse . end ) . toHaveBeenCalled ( ) ;
936
936
} ) ;
937
-
937
+
938
938
it ( "should keep stream open when multiple requests share the same connection" , async ( ) => {
939
939
// Create a fresh response for this test
940
940
const sharedResponse = createMockResponse ( ) ;
941
-
941
+
942
942
// Send two requests in a batch that will share the same connection
943
943
const batchRequests : JSONRPCMessage [ ] = [
944
944
{ jsonrpc : "2.0" , method : "method1" , params : { } , id : "req1" } ,
945
945
{ jsonrpc : "2.0" , method : "method2" , params : { } , id : "req2" }
946
946
] ;
947
-
947
+
948
948
const req = createMockRequest ( {
949
949
method : "POST" ,
950
950
headers : {
@@ -954,40 +954,40 @@ describe("StreamableHTTPServerTransport", () => {
954
954
} ,
955
955
body : JSON . stringify ( batchRequests )
956
956
} ) ;
957
-
957
+
958
958
await transport . handleRequest ( req , sharedResponse ) ;
959
-
959
+
960
960
// Respond to first request
961
961
const response1 : JSONRPCMessage = {
962
- jsonrpc : "2.0" ,
962
+ jsonrpc : "2.0" ,
963
963
result : { value : "result1" } ,
964
964
id : "req1"
965
965
} ;
966
-
966
+
967
967
await transport . send ( response1 ) ;
968
-
968
+
969
969
// Connection should remain open because req2 is still pending
970
970
expect ( sharedResponse . write ) . toHaveBeenCalledWith (
971
971
expect . stringContaining ( `event: message\ndata: ${ JSON . stringify ( response1 ) } \n\n` )
972
972
) ;
973
973
expect ( sharedResponse . end ) . not . toHaveBeenCalled ( ) ;
974
-
974
+
975
975
// Respond to second request
976
976
const response2 : JSONRPCMessage = {
977
977
jsonrpc : "2.0" ,
978
978
result : { value : "result2" } ,
979
979
id : "req2"
980
980
} ;
981
-
981
+
982
982
await transport . send ( response2 ) ;
983
-
983
+
984
984
// Now connection should close as all requests are complete
985
985
expect ( sharedResponse . write ) . toHaveBeenCalledWith (
986
- expect . stringContaining ( `event: message\ndata: ${ JSON . stringify ( response2 ) } \n\n` )
986
+ expect . stringContaining ( `event: message\ndata: ${ JSON . stringify ( response2 ) } \n\n` )
987
987
) ;
988
988
expect ( sharedResponse . end ) . toHaveBeenCalled ( ) ;
989
989
} ) ;
990
-
990
+
991
991
it ( "should clean up connection tracking when a response is sent" , async ( ) => {
992
992
const req = createMockRequest ( {
993
993
method : "POST" ,
@@ -997,32 +997,32 @@ describe("StreamableHTTPServerTransport", () => {
997
997
"mcp-session-id" : transport . sessionId
998
998
} ,
999
999
body : JSON . stringify ( {
1000
- jsonrpc : "2.0" ,
1001
- method : "test" ,
1002
- params : { } ,
1000
+ jsonrpc : "2.0" ,
1001
+ method : "test" ,
1002
+ params : { } ,
1003
1003
id : "cleanup-test"
1004
1004
} )
1005
1005
} ) ;
1006
-
1006
+
1007
1007
const response = createMockResponse ( ) ;
1008
1008
await transport . handleRequest ( req , response ) ;
1009
-
1009
+
1010
1010
// Verify that the request is tracked in the SSE map
1011
- expect ( transport [ "_sseResponseMapping" ] . size ) . toBe ( 1 ) ;
1011
+ expect ( transport [ "_sseResponseMapping" ] . size ) . toBe ( 2 ) ;
1012
1012
expect ( transport [ "_sseResponseMapping" ] . has ( "cleanup-test" ) ) . toBe ( true ) ;
1013
-
1013
+
1014
1014
// Send a response
1015
1015
await transport . send ( {
1016
1016
jsonrpc : "2.0" ,
1017
1017
result : { } ,
1018
1018
id : "cleanup-test"
1019
1019
} ) ;
1020
-
1020
+
1021
1021
// Verify that the mapping was cleaned up
1022
- expect ( transport [ "_sseResponseMapping" ] . size ) . toBe ( 0 ) ;
1022
+ expect ( transport [ "_sseResponseMapping" ] . size ) . toBe ( 1 ) ;
1023
1023
expect ( transport [ "_sseResponseMapping" ] . has ( "cleanup-test" ) ) . toBe ( false ) ;
1024
1024
} ) ;
1025
-
1025
+
1026
1026
it ( "should clean up connection tracking when client disconnects" , async ( ) => {
1027
1027
// Setup two requests that share a connection
1028
1028
const req = createMockRequest ( {
@@ -1034,12 +1034,12 @@ describe("StreamableHTTPServerTransport", () => {
1034
1034
} ,
1035
1035
body : JSON . stringify ( [
1036
1036
{ jsonrpc : "2.0" , method : "longRunning1" , params : { } , id : "req1" } ,
1037
- { jsonrpc : "2.0" , method : "longRunning2" , params : { } , id : "req2" }
1037
+ { jsonrpc : "2.0" , method : "longRunning2" , params : { } , id : "req2" }
1038
1038
] )
1039
1039
} ) ;
1040
-
1040
+
1041
1041
const response = createMockResponse ( ) ;
1042
-
1042
+
1043
1043
// We need to manually store the callback to trigger it later
1044
1044
let closeCallback : ( ( ) => void ) | undefined ;
1045
1045
response . on . mockImplementation ( ( event , callback : ( ) => void ) => {
@@ -1048,19 +1048,19 @@ describe("StreamableHTTPServerTransport", () => {
1048
1048
}
1049
1049
return response ;
1050
1050
} ) ;
1051
-
1051
+
1052
1052
await transport . handleRequest ( req , response ) ;
1053
-
1053
+
1054
1054
// Both requests should be mapped to the same response
1055
- expect ( transport [ "_sseResponseMapping" ] . size ) . toBe ( 2 ) ;
1055
+ expect ( transport [ "_sseResponseMapping" ] . size ) . toBe ( 3 ) ;
1056
1056
expect ( transport [ "_sseResponseMapping" ] . get ( "req1" ) ) . toBe ( response ) ;
1057
1057
expect ( transport [ "_sseResponseMapping" ] . get ( "req2" ) ) . toBe ( response ) ;
1058
-
1058
+
1059
1059
// Simulate client disconnect by triggering the stored callback
1060
1060
if ( closeCallback ) closeCallback ( ) ;
1061
-
1061
+
1062
1062
// All entries using this response should be removed
1063
- expect ( transport [ "_sseResponseMapping" ] . size ) . toBe ( 0 ) ;
1063
+ expect ( transport [ "_sseResponseMapping" ] . size ) . toBe ( 1 ) ;
1064
1064
expect ( transport [ "_sseResponseMapping" ] . has ( "req1" ) ) . toBe ( false ) ;
1065
1065
expect ( transport [ "_sseResponseMapping" ] . has ( "req2" ) ) . toBe ( false ) ;
1066
1066
} ) ;
0 commit comments