@@ -185,6 +185,8 @@ async function sendPostRequest(baseUrl: URL, message: JSONRPCMessage | JSONRPCMe
185
185
186
186
if ( sessionId ) {
187
187
headers [ "mcp-session-id" ] = sessionId ;
188
+ // After initialization, include the protocol version header
189
+ headers [ "mcp-protocol-version" ] = "2025-03-26" ;
188
190
}
189
191
190
192
return fetch ( baseUrl , {
@@ -277,7 +279,7 @@ describe("StreamableHTTPServerTransport", () => {
277
279
expectErrorResponse ( errorData , - 32600 , / O n l y o n e i n i t i a l i z a t i o n r e q u e s t i s a l l o w e d / ) ;
278
280
} ) ;
279
281
280
- it ( "should pandle post requests via sse response correctly" , async ( ) => {
282
+ it ( "should handle post requests via sse response correctly" , async ( ) => {
281
283
sessionId = await initializeServer ( ) ;
282
284
283
285
const response = await sendPostRequest ( baseUrl , TEST_MESSAGES . toolsList , sessionId ) ;
@@ -376,6 +378,7 @@ describe("StreamableHTTPServerTransport", () => {
376
378
headers : {
377
379
Accept : "text/event-stream" ,
378
380
"mcp-session-id" : sessionId ,
381
+ "mcp-protocol-version" : "2025-03-26" ,
379
382
} ,
380
383
} ) ;
381
384
@@ -417,6 +420,7 @@ describe("StreamableHTTPServerTransport", () => {
417
420
headers : {
418
421
Accept : "text/event-stream" ,
419
422
"mcp-session-id" : sessionId ,
423
+ "mcp-protocol-version" : "2025-03-26" ,
420
424
} ,
421
425
} ) ;
422
426
@@ -448,6 +452,7 @@ describe("StreamableHTTPServerTransport", () => {
448
452
headers : {
449
453
Accept : "text/event-stream" ,
450
454
"mcp-session-id" : sessionId ,
455
+ "mcp-protocol-version" : "2025-03-26" ,
451
456
} ,
452
457
} ) ;
453
458
@@ -459,6 +464,7 @@ describe("StreamableHTTPServerTransport", () => {
459
464
headers : {
460
465
Accept : "text/event-stream" ,
461
466
"mcp-session-id" : sessionId ,
467
+ "mcp-protocol-version" : "2025-03-26" ,
462
468
} ,
463
469
} ) ;
464
470
@@ -477,6 +483,7 @@ describe("StreamableHTTPServerTransport", () => {
477
483
headers : {
478
484
Accept : "application/json" ,
479
485
"mcp-session-id" : sessionId ,
486
+ "mcp-protocol-version" : "2025-03-26" ,
480
487
} ,
481
488
} ) ;
482
489
@@ -670,6 +677,7 @@ describe("StreamableHTTPServerTransport", () => {
670
677
headers : {
671
678
Accept : "text/event-stream" ,
672
679
"mcp-session-id" : sessionId ,
680
+ "mcp-protocol-version" : "2025-03-26" ,
673
681
} ,
674
682
} ) ;
675
683
@@ -705,7 +713,10 @@ describe("StreamableHTTPServerTransport", () => {
705
713
// Now DELETE the session
706
714
const deleteResponse = await fetch ( tempUrl , {
707
715
method : "DELETE" ,
708
- headers : { "mcp-session-id" : tempSessionId || "" } ,
716
+ headers : {
717
+ "mcp-session-id" : tempSessionId || "" ,
718
+ "mcp-protocol-version" : "2025-03-26" ,
719
+ } ,
709
720
} ) ;
710
721
711
722
expect ( deleteResponse . status ) . toBe ( 200 ) ;
@@ -721,13 +732,129 @@ describe("StreamableHTTPServerTransport", () => {
721
732
// Try to delete with invalid session ID
722
733
const response = await fetch ( baseUrl , {
723
734
method : "DELETE" ,
724
- headers : { "mcp-session-id" : "invalid-session-id" } ,
735
+ headers : {
736
+ "mcp-session-id" : "invalid-session-id" ,
737
+ "mcp-protocol-version" : "2025-03-26" ,
738
+ } ,
725
739
} ) ;
726
740
727
741
expect ( response . status ) . toBe ( 404 ) ;
728
742
const errorData = await response . json ( ) ;
729
743
expectErrorResponse ( errorData , - 32001 , / S e s s i o n n o t f o u n d / ) ;
730
744
} ) ;
745
+
746
+ describe ( "protocol version header validation" , ( ) => {
747
+ it ( "should accept requests with matching protocol version" , async ( ) => {
748
+ sessionId = await initializeServer ( ) ;
749
+
750
+ // Send request with matching protocol version
751
+ const response = await sendPostRequest ( baseUrl , TEST_MESSAGES . toolsList , sessionId ) ;
752
+
753
+ expect ( response . status ) . toBe ( 200 ) ;
754
+ } ) ;
755
+
756
+ it ( "should accept requests without protocol version header" , async ( ) => {
757
+ sessionId = await initializeServer ( ) ;
758
+
759
+ // Send request without protocol version header
760
+ const response = await fetch ( baseUrl , {
761
+ method : "POST" ,
762
+ headers : {
763
+ "Content-Type" : "application/json" ,
764
+ Accept : "application/json, text/event-stream" ,
765
+ "mcp-session-id" : sessionId ,
766
+ // No mcp-protocol-version header
767
+ } ,
768
+ body : JSON . stringify ( TEST_MESSAGES . toolsList ) ,
769
+ } ) ;
770
+
771
+ expect ( response . status ) . toBe ( 200 ) ;
772
+ } ) ;
773
+
774
+ it ( "should reject requests with unsupported protocol version" , async ( ) => {
775
+ sessionId = await initializeServer ( ) ;
776
+
777
+ // Send request with unsupported protocol version
778
+ const response = await fetch ( baseUrl , {
779
+ method : "POST" ,
780
+ headers : {
781
+ "Content-Type" : "application/json" ,
782
+ Accept : "application/json, text/event-stream" ,
783
+ "mcp-session-id" : sessionId ,
784
+ "mcp-protocol-version" : "1999-01-01" , // Unsupported version
785
+ } ,
786
+ body : JSON . stringify ( TEST_MESSAGES . toolsList ) ,
787
+ } ) ;
788
+
789
+ expect ( response . status ) . toBe ( 400 ) ;
790
+ const errorData = await response . json ( ) ;
791
+ expectErrorResponse ( errorData , - 32000 , / B a d R e q u e s t : U n s u p p o r t e d p r o t o c o l v e r s i o n / ) ;
792
+ } ) ;
793
+
794
+ it ( "should accept but warn when protocol version differs from negotiated version" , async ( ) => {
795
+ sessionId = await initializeServer ( ) ;
796
+
797
+ // Spy on console.warn to verify warning is logged
798
+ const warnSpy = jest . spyOn ( console , 'warn' ) . mockImplementation ( ) ;
799
+
800
+ // Send request with different but supported protocol version
801
+ const response = await fetch ( baseUrl , {
802
+ method : "POST" ,
803
+ headers : {
804
+ "Content-Type" : "application/json" ,
805
+ Accept : "application/json, text/event-stream" ,
806
+ "mcp-session-id" : sessionId ,
807
+ "mcp-protocol-version" : "2024-11-05" , // Different but supported version
808
+ } ,
809
+ body : JSON . stringify ( TEST_MESSAGES . toolsList ) ,
810
+ } ) ;
811
+
812
+ // Request should still succeed
813
+ expect ( response . status ) . toBe ( 200 ) ;
814
+
815
+ // But warning should have been logged
816
+ expect ( warnSpy ) . toHaveBeenCalledWith (
817
+ expect . stringContaining ( "Request has header with protocol version 2024-11-05, but version previously negotiated is 2025-03-26" )
818
+ ) ;
819
+
820
+ warnSpy . mockRestore ( ) ;
821
+ } ) ;
822
+
823
+ it ( "should handle protocol version validation for GET requests" , async ( ) => {
824
+ sessionId = await initializeServer ( ) ;
825
+
826
+ // GET request with unsupported protocol version
827
+ const response = await fetch ( baseUrl , {
828
+ method : "GET" ,
829
+ headers : {
830
+ Accept : "text/event-stream" ,
831
+ "mcp-session-id" : sessionId ,
832
+ "mcp-protocol-version" : "invalid-version" ,
833
+ } ,
834
+ } ) ;
835
+
836
+ expect ( response . status ) . toBe ( 400 ) ;
837
+ const errorData = await response . json ( ) ;
838
+ expectErrorResponse ( errorData , - 32000 , / B a d R e q u e s t : U n s u p p o r t e d p r o t o c o l v e r s i o n / ) ;
839
+ } ) ;
840
+
841
+ it ( "should handle protocol version validation for DELETE requests" , async ( ) => {
842
+ sessionId = await initializeServer ( ) ;
843
+
844
+ // DELETE request with unsupported protocol version
845
+ const response = await fetch ( baseUrl , {
846
+ method : "DELETE" ,
847
+ headers : {
848
+ "mcp-session-id" : sessionId ,
849
+ "mcp-protocol-version" : "invalid-version" ,
850
+ } ,
851
+ } ) ;
852
+
853
+ expect ( response . status ) . toBe ( 400 ) ;
854
+ const errorData = await response . json ( ) ;
855
+ expectErrorResponse ( errorData , - 32000 , / B a d R e q u e s t : U n s u p p o r t e d p r o t o c o l v e r s i o n / ) ;
856
+ } ) ;
857
+ } ) ;
731
858
} ) ;
732
859
733
860
describe ( "StreamableHTTPServerTransport with AuthInfo" , ( ) => {
@@ -1120,6 +1247,7 @@ describe("StreamableHTTPServerTransport with resumability", () => {
1120
1247
headers : {
1121
1248
Accept : "text/event-stream" ,
1122
1249
"mcp-session-id" : sessionId ,
1250
+ "mcp-protocol-version" : "2025-03-26" ,
1123
1251
} ,
1124
1252
} ) ;
1125
1253
@@ -1196,6 +1324,7 @@ describe("StreamableHTTPServerTransport with resumability", () => {
1196
1324
headers : {
1197
1325
Accept : "text/event-stream" ,
1198
1326
"mcp-session-id" : sessionId ,
1327
+ "mcp-protocol-version" : "2025-03-26" ,
1199
1328
"last-event-id" : firstEventId
1200
1329
} ,
1201
1330
} ) ;
@@ -1282,14 +1411,20 @@ describe("StreamableHTTPServerTransport in stateless mode", () => {
1282
1411
// Open first SSE stream
1283
1412
const stream1 = await fetch ( baseUrl , {
1284
1413
method : "GET" ,
1285
- headers : { Accept : "text/event-stream" } ,
1414
+ headers : {
1415
+ Accept : "text/event-stream" ,
1416
+ "mcp-protocol-version" : "2025-03-26"
1417
+ } ,
1286
1418
} ) ;
1287
1419
expect ( stream1 . status ) . toBe ( 200 ) ;
1288
1420
1289
1421
// Open second SSE stream - should still be rejected, stateless mode still only allows one
1290
1422
const stream2 = await fetch ( baseUrl , {
1291
1423
method : "GET" ,
1292
- headers : { Accept : "text/event-stream" } ,
1424
+ headers : {
1425
+ Accept : "text/event-stream" ,
1426
+ "mcp-protocol-version" : "2025-03-26"
1427
+ } ,
1293
1428
} ) ;
1294
1429
expect ( stream2 . status ) . toBe ( 409 ) ; // Conflict - only one stream allowed
1295
1430
} ) ;
0 commit comments