From c32f385d58ada525d0b234542a7ca36f0100b3b0 Mon Sep 17 00:00:00 2001 From: Anna Geitz Date: Sat, 3 Oct 2026 13:44:05 +0000 Subject: [PATCH] fix: reject invalid JSON-RPC response versions --- .../modelcontextprotocol/spec/McpSchema.java | 1 + .../spec/JsonRpcDispatchTests.java | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpSchema.java b/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpSchema.java index 648be8b4b..0780938d7 100644 --- a/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpSchema.java +++ b/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpSchema.java @@ -320,6 +320,7 @@ public record JSONRPCResponse( // @formatter:off public JSONRPCResponse { Assert.hasText(jsonrpc, "jsonrpc must not be empty"); + Assert.isTrue(JSONRPC_VERSION.equals(jsonrpc), "jsonrpc must be 2.0"); Assert.notNull(id, "MCP responses MUST include an ID - null IDs are not allowed"); Assert.isTrue(id instanceof String || id instanceof Integer || id instanceof Long, "MCP responses MUST have an ID that is either a string or integer"); diff --git a/mcp-test/src/test/java/io/modelcontextprotocol/spec/JsonRpcDispatchTests.java b/mcp-test/src/test/java/io/modelcontextprotocol/spec/JsonRpcDispatchTests.java index 6e5a6efb2..6a0e13015 100644 --- a/mcp-test/src/test/java/io/modelcontextprotocol/spec/JsonRpcDispatchTests.java +++ b/mcp-test/src/test/java/io/modelcontextprotocol/spec/JsonRpcDispatchTests.java @@ -6,6 +6,7 @@ import static io.modelcontextprotocol.util.McpJsonMapperUtils.JSON_MAPPER; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.io.IOException; import java.util.Map; @@ -81,6 +82,28 @@ void dispatchesErrorResponse() throws IOException { assertThat(resp.result()).isNull(); } + @Test + void rejectsSuccessResponseWithInvalidJsonRpcVersion() { + String json = """ + {"jsonrpc":"1.0","id":"req-1","result":{"content":[{"type":"text","text":"hi"}]}} + """; + + assertThatThrownBy(() -> McpSchema.deserializeJsonRpcMessage(mapper, json)).rootCause() + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("jsonrpc must be 2.0"); + } + + @Test + void rejectsErrorResponseWithInvalidJsonRpcVersion() { + String json = """ + {"jsonrpc":"1.0","id":"req-1","error":{"code":-32601,"message":"Method not found"}} + """; + + assertThatThrownBy(() -> McpSchema.deserializeJsonRpcMessage(mapper, json)).rootCause() + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("jsonrpc must be 2.0"); + } + @Test void paramsMapSurvivesConvertValue() throws IOException { String json = """