Skip to content

Commit 580cdf3

Browse files
committed
fix: reject non-JSON Content-Type with 415 and validate protocol version on initialize
HttpServletStreamableServerTransportProvider and HttpServletStatelessServerTransport accepted POST requests regardless of Content-Type, processing text/plain and form-encoded bodies as if they were application/json. Add an early Content-Type guard in doPost() on both transports that returns HTTP 415 Unsupported Media Type when Content-Type is absent or does not start with application/json. Also validate on initialize requests that the MCP-Protocol-Version HTTP header, when present, is consistent with the protocolVersion field in the JSON-RPC body. A mismatch returns HTTP 400 with a JSON-RPC INVALID_REQUEST error. Fixes #961 Fixes #963 Signed-off-by: Gorre Surya <suryateja.g13@gmail.com>
1 parent c09ee67 commit 580cdf3

2 files changed

Lines changed: 23 additions & 0 deletions

File tree

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
142142
return;
143143
}
144144

145+
String contentType = request.getContentType();
146+
if (contentType == null || !contentType.startsWith(APPLICATION_JSON)) {
147+
response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, "Content-Type must be application/json");
148+
return;
149+
}
150+
145151
McpTransportContext transportContext = this.contextExtractor.extract(request);
146152

147153
String accept = request.getHeader(ACCEPT);

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,12 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
415415
return;
416416
}
417417

418+
String contentType = request.getContentType();
419+
if (contentType == null || !contentType.startsWith(APPLICATION_JSON)) {
420+
response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, "Content-Type must be application/json");
421+
return;
422+
}
423+
418424
List<String> badRequestErrors = new ArrayList<>();
419425

420426
String accept = request.getHeader(ACCEPT);
@@ -450,6 +456,17 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
450456
McpSchema.InitializeRequest initializeRequest = jsonMapper.convertValue(jsonrpcRequest.params(),
451457
new TypeRef<McpSchema.InitializeRequest>() {
452458
});
459+
460+
String headerVersion = request.getHeader(HttpHeaders.PROTOCOL_VERSION);
461+
if (headerVersion != null && !headerVersion.equals(initializeRequest.protocolVersion())) {
462+
this.responseError(response, HttpServletResponse.SC_BAD_REQUEST, McpError
463+
.builder(McpSchema.ErrorCodes.INVALID_REQUEST)
464+
.message("MCP-Protocol-Version header '" + headerVersion
465+
+ "' does not match body protocolVersion '" + initializeRequest.protocolVersion() + "'")
466+
.build());
467+
return;
468+
}
469+
453470
McpStreamableServerSession.McpStreamableServerSessionInit init = this.sessionFactory
454471
.startSession(initializeRequest);
455472
this.sessions.put(init.session().getId(), init.session());

0 commit comments

Comments
 (0)