Skip to content

Commit 83a3bca

Browse files
committed
fix: reject unsupported MCP protocol version headers
1 parent c09ee67 commit 83a3bca

2 files changed

Lines changed: 83 additions & 0 deletions

File tree

mcp-core/src/main/java/io/modelcontextprotocol/server/transport/HttpServletStreamableServerTransportProvider.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response)
279279
return;
280280
}
281281

282+
if (!validateProtocolVersion(request, response)) {
283+
return;
284+
}
285+
282286
List<String> badRequestErrors = new ArrayList<>();
283287

284288
String accept = request.getHeader(ACCEPT);
@@ -480,6 +484,10 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
480484
}
481485
}
482486

487+
if (!validateProtocolVersion(request, response)) {
488+
return;
489+
}
490+
483491
String sessionId = request.getHeader(HttpHeaders.MCP_SESSION_ID);
484492

485493
if (sessionId == null || sessionId.isBlank()) {
@@ -596,6 +604,10 @@ protected void doDelete(HttpServletRequest request, HttpServletResponse response
596604
return;
597605
}
598606

607+
if (!validateProtocolVersion(request, response)) {
608+
return;
609+
}
610+
599611
if (this.disallowDelete) {
600612
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
601613
return;
@@ -648,6 +660,22 @@ public void responseError(HttpServletResponse response, int httpCode, McpError m
648660
return;
649661
}
650662

663+
private boolean validateProtocolVersion(HttpServletRequest request, HttpServletResponse response)
664+
throws IOException {
665+
String protocolVersion = request.getHeader(HttpHeaders.PROTOCOL_VERSION);
666+
if (protocolVersion == null || protocolVersion.isBlank()) {
667+
return true;
668+
}
669+
if (protocolVersions().contains(protocolVersion)) {
670+
return true;
671+
}
672+
this.responseError(response, HttpServletResponse.SC_BAD_REQUEST,
673+
McpError.builder(McpSchema.ErrorCodes.INVALID_REQUEST)
674+
.message("Unsupported or invalid MCP protocol version: " + protocolVersion)
675+
.build());
676+
return false;
677+
}
678+
651679
/**
652680
* Sends an SSE event to a client with a specific ID.
653681
* @param writer The writer to send the event through

mcp-test/src/test/java/io/modelcontextprotocol/common/HttpClientStreamableHttpVersionNegotiationIntegrationTests.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
package io.modelcontextprotocol.common;
66

7+
import java.net.URI;
8+
import java.net.http.HttpClient;
9+
import java.net.http.HttpRequest;
10+
import java.net.http.HttpResponse;
711
import java.util.List;
812
import java.util.Map;
913
import java.util.function.BiFunction;
@@ -24,6 +28,8 @@
2428
import org.apache.catalina.startup.Tomcat;
2529
import org.junit.jupiter.api.AfterEach;
2630
import org.junit.jupiter.api.Test;
31+
import org.junit.jupiter.params.ParameterizedTest;
32+
import org.junit.jupiter.params.provider.ValueSource;
2733

2834
import static org.assertj.core.api.Assertions.assertThat;
2935

@@ -122,6 +128,55 @@ void usesServerSupportedVersion() {
122128
mcpServer.close();
123129
}
124130

131+
@ParameterizedTest
132+
@ValueSource(strings = { "1900-01-01", "not-a-version" })
133+
void rejectsUnsupportedProtocolVersionHeaders(String protocolVersion) throws Exception {
134+
startTomcat();
135+
136+
HttpClient httpClient = HttpClient.newHttpClient();
137+
String endpoint = "http://localhost:" + PORT + "/mcp";
138+
139+
HttpResponse<String> initializeResponse = httpClient.send(HttpRequest.newBuilder()
140+
.uri(URI.create(endpoint))
141+
.header("Content-Type", "application/json")
142+
.header("Accept", "application/json, text/event-stream")
143+
.header("MCP-Protocol-Version", ProtocolVersions.MCP_2025_11_25)
144+
.POST(HttpRequest.BodyPublishers.ofString(
145+
"""
146+
{"jsonrpc":"2.0","id":"init-1","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test-client","version":"1.0.0"}}}
147+
"""))
148+
.build(), HttpResponse.BodyHandlers.ofString());
149+
150+
assertThat(initializeResponse.statusCode()).isEqualTo(200);
151+
String sessionId = initializeResponse.headers().firstValue("Mcp-Session-Id").orElseThrow();
152+
153+
HttpResponse<String> initializedResponse = httpClient.send(HttpRequest.newBuilder()
154+
.uri(URI.create(endpoint))
155+
.header("Content-Type", "application/json")
156+
.header("Accept", "application/json, text/event-stream")
157+
.header("MCP-Protocol-Version", ProtocolVersions.MCP_2025_11_25)
158+
.header("Mcp-Session-Id", sessionId)
159+
.POST(HttpRequest.BodyPublishers
160+
.ofString("{\"jsonrpc\":\"2.0\",\"method\":\"notifications/initialized\",\"params\":{}}"))
161+
.build(), HttpResponse.BodyHandlers.ofString());
162+
163+
assertThat(initializedResponse.statusCode()).isEqualTo(202);
164+
165+
HttpResponse<String> badVersionResponse = httpClient.send(HttpRequest.newBuilder()
166+
.uri(URI.create(endpoint))
167+
.header("Content-Type", "application/json")
168+
.header("Accept", "application/json, text/event-stream")
169+
.header("MCP-Protocol-Version", protocolVersion)
170+
.header("Mcp-Session-Id", sessionId)
171+
.POST(HttpRequest.BodyPublishers
172+
.ofString("{\"jsonrpc\":\"2.0\",\"id\":\"bad-version-1\",\"method\":\"tools/list\",\"params\":{}}"))
173+
.build(), HttpResponse.BodyHandlers.ofString());
174+
175+
assertThat(badVersionResponse.statusCode()).isEqualTo(400);
176+
assertThat(badVersionResponse.body()).contains("Unsupported or invalid MCP protocol version");
177+
mcpServer.close();
178+
}
179+
125180
private void startTomcat() {
126181
tomcat = TomcatTestUtil.createTomcatServer("", PORT, transport, requestRecordingFilter);
127182
try {

0 commit comments

Comments
 (0)