@@ -185,6 +185,8 @@ async function sendPostRequest(baseUrl: URL, message: JSONRPCMessage | JSONRPCMe
185185
186186 if ( sessionId ) {
187187 headers [ "mcp-session-id" ] = sessionId ;
188+ // After initialization, include the protocol version header
189+ headers [ "mcp-protocol-version" ] = "2025-03-26" ;
188190 }
189191
190192 return fetch ( baseUrl , {
@@ -277,7 +279,7 @@ describe("StreamableHTTPServerTransport", () => {
277279 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 / ) ;
278280 } ) ;
279281
280- it ( "should pandle post requests via sse response correctly" , async ( ) => {
282+ it ( "should handle post requests via sse response correctly" , async ( ) => {
281283 sessionId = await initializeServer ( ) ;
282284
283285 const response = await sendPostRequest ( baseUrl , TEST_MESSAGES . toolsList , sessionId ) ;
@@ -376,6 +378,7 @@ describe("StreamableHTTPServerTransport", () => {
376378 headers : {
377379 Accept : "text/event-stream" ,
378380 "mcp-session-id" : sessionId ,
381+ "mcp-protocol-version" : "2025-03-26" ,
379382 } ,
380383 } ) ;
381384
@@ -417,6 +420,7 @@ describe("StreamableHTTPServerTransport", () => {
417420 headers : {
418421 Accept : "text/event-stream" ,
419422 "mcp-session-id" : sessionId ,
423+ "mcp-protocol-version" : "2025-03-26" ,
420424 } ,
421425 } ) ;
422426
@@ -448,6 +452,7 @@ describe("StreamableHTTPServerTransport", () => {
448452 headers : {
449453 Accept : "text/event-stream" ,
450454 "mcp-session-id" : sessionId ,
455+ "mcp-protocol-version" : "2025-03-26" ,
451456 } ,
452457 } ) ;
453458
@@ -459,6 +464,7 @@ describe("StreamableHTTPServerTransport", () => {
459464 headers : {
460465 Accept : "text/event-stream" ,
461466 "mcp-session-id" : sessionId ,
467+ "mcp-protocol-version" : "2025-03-26" ,
462468 } ,
463469 } ) ;
464470
@@ -477,6 +483,7 @@ describe("StreamableHTTPServerTransport", () => {
477483 headers : {
478484 Accept : "application/json" ,
479485 "mcp-session-id" : sessionId ,
486+ "mcp-protocol-version" : "2025-03-26" ,
480487 } ,
481488 } ) ;
482489
@@ -670,6 +677,7 @@ describe("StreamableHTTPServerTransport", () => {
670677 headers : {
671678 Accept : "text/event-stream" ,
672679 "mcp-session-id" : sessionId ,
680+ "mcp-protocol-version" : "2025-03-26" ,
673681 } ,
674682 } ) ;
675683
@@ -705,7 +713,10 @@ describe("StreamableHTTPServerTransport", () => {
705713 // Now DELETE the session
706714 const deleteResponse = await fetch ( tempUrl , {
707715 method : "DELETE" ,
708- headers : { "mcp-session-id" : tempSessionId || "" } ,
716+ headers : {
717+ "mcp-session-id" : tempSessionId || "" ,
718+ "mcp-protocol-version" : "2025-03-26" ,
719+ } ,
709720 } ) ;
710721
711722 expect ( deleteResponse . status ) . toBe ( 200 ) ;
@@ -721,13 +732,129 @@ describe("StreamableHTTPServerTransport", () => {
721732 // Try to delete with invalid session ID
722733 const response = await fetch ( baseUrl , {
723734 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+ } ,
725739 } ) ;
726740
727741 expect ( response . status ) . toBe ( 404 ) ;
728742 const errorData = await response . json ( ) ;
729743 expectErrorResponse ( errorData , - 32001 , / S e s s i o n n o t f o u n d / ) ;
730744 } ) ;
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+ } ) ;
731858} ) ;
732859
733860describe ( "StreamableHTTPServerTransport with AuthInfo" , ( ) => {
@@ -1120,6 +1247,7 @@ describe("StreamableHTTPServerTransport with resumability", () => {
11201247 headers : {
11211248 Accept : "text/event-stream" ,
11221249 "mcp-session-id" : sessionId ,
1250+ "mcp-protocol-version" : "2025-03-26" ,
11231251 } ,
11241252 } ) ;
11251253
@@ -1196,6 +1324,7 @@ describe("StreamableHTTPServerTransport with resumability", () => {
11961324 headers : {
11971325 Accept : "text/event-stream" ,
11981326 "mcp-session-id" : sessionId ,
1327+ "mcp-protocol-version" : "2025-03-26" ,
11991328 "last-event-id" : firstEventId
12001329 } ,
12011330 } ) ;
@@ -1282,14 +1411,20 @@ describe("StreamableHTTPServerTransport in stateless mode", () => {
12821411 // Open first SSE stream
12831412 const stream1 = await fetch ( baseUrl , {
12841413 method : "GET" ,
1285- headers : { Accept : "text/event-stream" } ,
1414+ headers : {
1415+ Accept : "text/event-stream" ,
1416+ "mcp-protocol-version" : "2025-03-26"
1417+ } ,
12861418 } ) ;
12871419 expect ( stream1 . status ) . toBe ( 200 ) ;
12881420
12891421 // Open second SSE stream - should still be rejected, stateless mode still only allows one
12901422 const stream2 = await fetch ( baseUrl , {
12911423 method : "GET" ,
1292- headers : { Accept : "text/event-stream" } ,
1424+ headers : {
1425+ Accept : "text/event-stream" ,
1426+ "mcp-protocol-version" : "2025-03-26"
1427+ } ,
12931428 } ) ;
12941429 expect ( stream2 . status ) . toBe ( 409 ) ; // Conflict - only one stream allowed
12951430 } ) ;
0 commit comments