Skip to content

Commit d62b7f8

Browse files
Merge branch 'main' into feature/passthrough-looseobject-removal-part-2
2 parents f332ccd + fbf5fc9 commit d62b7f8

File tree

2 files changed

+65
-47
lines changed

2 files changed

+65
-47
lines changed

src/server/streamableHttp.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -794,19 +794,32 @@ export class StreamableHTTPServerTransport implements Transport {
794794
return true;
795795
}
796796

797+
/**
798+
* Validates the MCP-Protocol-Version header on incoming requests.
799+
*
800+
* For initialization: Version negotiation handles unknown versions gracefully
801+
* (server responds with its supported version).
802+
*
803+
* For subsequent requests with MCP-Protocol-Version header:
804+
* - Accept if in supported list
805+
* - 400 if unsupported
806+
*
807+
* For HTTP requests without the MCP-Protocol-Version header:
808+
* - Accept and default to the version negotiated at initialization
809+
*/
797810
private validateProtocolVersion(req: IncomingMessage, res: ServerResponse): boolean {
798-
let protocolVersion = req.headers['mcp-protocol-version'] ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
811+
let protocolVersion = req.headers['mcp-protocol-version'];
799812
if (Array.isArray(protocolVersion)) {
800813
protocolVersion = protocolVersion[protocolVersion.length - 1];
801814
}
802815

803-
if (!SUPPORTED_PROTOCOL_VERSIONS.includes(protocolVersion)) {
816+
if (protocolVersion !== undefined && !SUPPORTED_PROTOCOL_VERSIONS.includes(protocolVersion)) {
804817
res.writeHead(400).end(
805818
JSON.stringify({
806819
jsonrpc: '2.0',
807820
error: {
808821
code: -32000,
809-
message: `Bad Request: Unsupported protocol version (supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(', ')})`
822+
message: `Bad Request: Unsupported protocol version: ${protocolVersion} (supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(', ')})`
810823
},
811824
id: null
812825
})

test/server/streamableHttp.test.ts

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,21 @@ const TEST_MESSAGES = {
5555
method: 'initialize',
5656
params: {
5757
clientInfo: { name: 'test-client', version: '1.0' },
58-
protocolVersion: '2025-03-26',
58+
protocolVersion: '2025-11-25',
5959
capabilities: {}
6060
},
61+
id: 'init-1'
62+
} as JSONRPCMessage,
6163

64+
// Initialize message with an older protocol version for backward compatibility tests
65+
initializeOldVersion: {
66+
jsonrpc: '2.0',
67+
method: 'initialize',
68+
params: {
69+
clientInfo: { name: 'test-client', version: '1.0' },
70+
protocolVersion: '2025-06-18',
71+
capabilities: {}
72+
},
6273
id: 'init-1'
6374
} as JSONRPCMessage,
6475

@@ -98,8 +109,7 @@ async function sendPostRequest(
98109

99110
if (sessionId) {
100111
headers['mcp-session-id'] = sessionId;
101-
// After initialization, include the protocol version header
102-
headers['mcp-protocol-version'] = '2025-03-26';
112+
headers['mcp-protocol-version'] = '2025-11-25';
103113
}
104114

105115
return fetch(baseUrl, {
@@ -460,7 +470,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
460470
headers: {
461471
Accept: 'text/event-stream',
462472
'mcp-session-id': sessionId,
463-
'mcp-protocol-version': '2025-03-26'
473+
'mcp-protocol-version': '2025-11-25'
464474
}
465475
});
466476

@@ -501,7 +511,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
501511
headers: {
502512
Accept: 'text/event-stream',
503513
'mcp-session-id': sessionId,
504-
'mcp-protocol-version': '2025-03-26'
514+
'mcp-protocol-version': '2025-11-25'
505515
}
506516
});
507517

@@ -533,7 +543,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
533543
headers: {
534544
Accept: 'text/event-stream',
535545
'mcp-session-id': sessionId,
536-
'mcp-protocol-version': '2025-03-26'
546+
'mcp-protocol-version': '2025-11-25'
537547
}
538548
});
539549

@@ -545,7 +555,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
545555
headers: {
546556
Accept: 'text/event-stream',
547557
'mcp-session-id': sessionId,
548-
'mcp-protocol-version': '2025-03-26'
558+
'mcp-protocol-version': '2025-11-25'
549559
}
550560
});
551561

@@ -564,7 +574,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
564574
headers: {
565575
Accept: 'application/json',
566576
'mcp-session-id': sessionId,
567-
'mcp-protocol-version': '2025-03-26'
577+
'mcp-protocol-version': '2025-11-25'
568578
}
569579
});
570580

@@ -758,7 +768,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
758768
headers: {
759769
Accept: 'text/event-stream',
760770
'mcp-session-id': sessionId,
761-
'mcp-protocol-version': '2025-03-26'
771+
'mcp-protocol-version': '2025-11-25'
762772
}
763773
});
764774

@@ -796,7 +806,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
796806
method: 'DELETE',
797807
headers: {
798808
'mcp-session-id': tempSessionId || '',
799-
'mcp-protocol-version': '2025-03-26'
809+
'mcp-protocol-version': '2025-11-25'
800810
}
801811
});
802812

@@ -815,7 +825,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
815825
method: 'DELETE',
816826
headers: {
817827
'mcp-session-id': 'invalid-session-id',
818-
'mcp-protocol-version': '2025-03-26'
828+
'mcp-protocol-version': '2025-11-25'
819829
}
820830
});
821831

@@ -869,15 +879,12 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
869879

870880
expect(response.status).toBe(400);
871881
const errorData = await response.json();
872-
expectErrorResponse(errorData, -32000, /Bad Request: Unsupported protocol version \(supported versions: .+\)/);
882+
expectErrorResponse(errorData, -32000, /Bad Request: Unsupported protocol version: .+ \(supported versions: .+\)/);
873883
});
874884

875885
it('should accept when protocol version differs from negotiated version', async () => {
876886
sessionId = await initializeServer();
877887

878-
// Spy on console.warn to verify warning is logged
879-
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
880-
881888
// Send request with different but supported protocol version
882889
const response = await fetch(baseUrl, {
883890
method: 'POST',
@@ -892,11 +899,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
892899

893900
// Request should still succeed
894901
expect(response.status).toBe(200);
895-
896-
warnSpy.mockRestore();
897902
});
898903

899-
it('should handle protocol version validation for GET requests', async () => {
904+
it('should reject unsupported protocol version on GET requests', async () => {
900905
sessionId = await initializeServer();
901906

902907
// GET request with unsupported protocol version
@@ -905,30 +910,30 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
905910
headers: {
906911
Accept: 'text/event-stream',
907912
'mcp-session-id': sessionId,
908-
'mcp-protocol-version': 'invalid-version'
913+
'mcp-protocol-version': '1999-01-01' // Unsupported version
909914
}
910915
});
911916

912917
expect(response.status).toBe(400);
913918
const errorData = await response.json();
914-
expectErrorResponse(errorData, -32000, /Bad Request: Unsupported protocol version \(supported versions: .+\)/);
919+
expectErrorResponse(errorData, -32000, /Bad Request: Unsupported protocol version/);
915920
});
916921

917-
it('should handle protocol version validation for DELETE requests', async () => {
922+
it('should reject unsupported protocol version on DELETE requests', async () => {
918923
sessionId = await initializeServer();
919924

920925
// DELETE request with unsupported protocol version
921926
const response = await fetch(baseUrl, {
922927
method: 'DELETE',
923928
headers: {
924929
'mcp-session-id': sessionId,
925-
'mcp-protocol-version': 'invalid-version'
930+
'mcp-protocol-version': '1999-01-01' // Unsupported version
926931
}
927932
});
928933

929934
expect(response.status).toBe(400);
930935
const errorData = await response.json();
931-
expectErrorResponse(errorData, -32000, /Bad Request: Unsupported protocol version \(supported versions: .+\)/);
936+
expectErrorResponse(errorData, -32000, /Bad Request: Unsupported protocol version/);
932937
});
933938
});
934939
});
@@ -1325,7 +1330,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
13251330
headers: {
13261331
Accept: 'text/event-stream',
13271332
'mcp-session-id': sessionId,
1328-
'mcp-protocol-version': '2025-03-26'
1333+
'mcp-protocol-version': '2025-11-25'
13291334
}
13301335
});
13311336

@@ -1370,7 +1375,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
13701375
headers: {
13711376
Accept: 'text/event-stream',
13721377
'mcp-session-id': sessionId,
1373-
'mcp-protocol-version': '2025-03-26'
1378+
'mcp-protocol-version': '2025-11-25'
13741379
}
13751380
});
13761381
expect(sseResponse.status).toBe(200);
@@ -1404,7 +1409,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
14041409
headers: {
14051410
Accept: 'text/event-stream',
14061411
'mcp-session-id': sessionId,
1407-
'mcp-protocol-version': '2025-03-26',
1412+
'mcp-protocol-version': '2025-11-25',
14081413
'last-event-id': firstEventId
14091414
}
14101415
});
@@ -1428,7 +1433,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
14281433
headers: {
14291434
Accept: 'text/event-stream',
14301435
'mcp-session-id': sessionId,
1431-
'mcp-protocol-version': '2025-03-26'
1436+
'mcp-protocol-version': '2025-11-25'
14321437
}
14331438
});
14341439
expect(sseResponse.status).toBe(200);
@@ -1461,7 +1466,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
14611466
headers: {
14621467
Accept: 'text/event-stream',
14631468
'mcp-session-id': sessionId,
1464-
'mcp-protocol-version': '2025-03-26',
1469+
'mcp-protocol-version': '2025-11-25',
14651470
'last-event-id': lastEventId
14661471
}
14671472
});
@@ -1565,7 +1570,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
15651570
method: 'GET',
15661571
headers: {
15671572
Accept: 'text/event-stream',
1568-
'mcp-protocol-version': '2025-03-26'
1573+
'mcp-protocol-version': '2025-11-25'
15691574
}
15701575
});
15711576
expect(stream1.status).toBe(200);
@@ -1575,7 +1580,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
15751580
method: 'GET',
15761581
headers: {
15771582
Accept: 'text/event-stream',
1578-
'mcp-protocol-version': '2025-03-26'
1583+
'mcp-protocol-version': '2025-11-25'
15791584
}
15801585
});
15811586
expect(stream2.status).toBe(409); // Conflict - only one stream allowed
@@ -1692,12 +1697,12 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
16921697
baseUrl = result.baseUrl;
16931698
mcpServer = result.mcpServer;
16941699

1695-
// Initialize to get session ID
1696-
const initResponse = await sendPostRequest(baseUrl, TEST_MESSAGES.initialize);
1700+
// Initialize with OLD protocol version to get session ID
1701+
const initResponse = await sendPostRequest(baseUrl, TEST_MESSAGES.initializeOldVersion);
16971702
sessionId = initResponse.headers.get('mcp-session-id') as string;
16981703
expect(sessionId).toBeDefined();
16991704

1700-
// Send a tool call request with OLD protocol version
1705+
// Send a tool call request with the same OLD protocol version
17011706
const toolCallRequest: JSONRPCMessage = {
17021707
jsonrpc: '2.0',
17031708
id: 100,
@@ -1932,12 +1937,12 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
19321937
return { content: [{ type: 'text', text: 'Done' }] };
19331938
});
19341939

1935-
// Initialize to get session ID
1936-
const initResponse = await sendPostRequest(baseUrl, TEST_MESSAGES.initialize);
1940+
// Initialize with OLD protocol version to get session ID
1941+
const initResponse = await sendPostRequest(baseUrl, TEST_MESSAGES.initializeOldVersion);
19371942
sessionId = initResponse.headers.get('mcp-session-id') as string;
19381943
expect(sessionId).toBeDefined();
19391944

1940-
// Call the tool with OLD protocol version
1945+
// Call the tool with the same OLD protocol version
19411946
const toolCallRequest: JSONRPCMessage = {
19421947
jsonrpc: '2.0',
19431948
id: 200,
@@ -2009,7 +2014,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
20092014
'Content-Type': 'application/json',
20102015
Accept: 'text/event-stream, application/json',
20112016
'mcp-session-id': sessionId,
2012-
'mcp-protocol-version': '2025-03-26'
2017+
'mcp-protocol-version': '2025-11-25'
20132018
},
20142019
body: JSON.stringify(toolCallRequest)
20152020
});
@@ -2307,7 +2312,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
23072312
method: 'DELETE',
23082313
headers: {
23092314
'mcp-session-id': tempSessionId || '',
2310-
'mcp-protocol-version': '2025-03-26'
2315+
'mcp-protocol-version': '2025-11-25'
23112316
}
23122317
});
23132318

@@ -2367,7 +2372,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
23672372
method: 'DELETE',
23682373
headers: {
23692374
'mcp-session-id': 'invalid-session-id',
2370-
'mcp-protocol-version': '2025-03-26'
2375+
'mcp-protocol-version': '2025-11-25'
23712376
}
23722377
});
23732378

@@ -2415,7 +2420,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
24152420
method: 'DELETE',
24162421
headers: {
24172422
'mcp-session-id': sessionId1 || '',
2418-
'mcp-protocol-version': '2025-03-26'
2423+
'mcp-protocol-version': '2025-11-25'
24192424
}
24202425
});
24212426

@@ -2428,7 +2433,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
24282433
method: 'DELETE',
24292434
headers: {
24302435
'mcp-session-id': sessionId2 || '',
2431-
'mcp-protocol-version': '2025-03-26'
2436+
'mcp-protocol-version': '2025-11-25'
24322437
}
24332438
});
24342439

@@ -2527,7 +2532,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
25272532
method: 'DELETE',
25282533
headers: {
25292534
'mcp-session-id': tempSessionId || '',
2530-
'mcp-protocol-version': '2025-03-26'
2535+
'mcp-protocol-version': '2025-11-25'
25312536
}
25322537
});
25332538

@@ -2588,7 +2593,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
25882593
method: 'DELETE',
25892594
headers: {
25902595
'mcp-session-id': tempSessionId || '',
2591-
'mcp-protocol-version': '2025-03-26'
2596+
'mcp-protocol-version': '2025-11-25'
25922597
}
25932598
});
25942599

@@ -2632,7 +2637,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
26322637
method: 'DELETE',
26332638
headers: {
26342639
'mcp-session-id': tempSessionId || '',
2635-
'mcp-protocol-version': '2025-03-26'
2640+
'mcp-protocol-version': '2025-11-25'
26362641
}
26372642
});
26382643

0 commit comments

Comments
 (0)