diff --git a/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/jackson3/JacksonMcpJsonMapper.java b/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/jackson3/JacksonMcpJsonMapper.java index a0dbdd555..39f323f26 100644 --- a/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/jackson3/JacksonMcpJsonMapper.java +++ b/mcp-json-jackson3/src/main/java/io/modelcontextprotocol/json/jackson3/JacksonMcpJsonMapper.java @@ -87,13 +87,23 @@ public T readValue(byte[] content, TypeRef type) throws IOException { @Override public T convertValue(Object fromValue, Class type) { - return jsonMapper.convertValue(fromValue, type); + try { + return jsonMapper.convertValue(fromValue, type); + } + catch (JacksonException ex) { + throw new IllegalArgumentException(ex); + } } @Override public T convertValue(Object fromValue, TypeRef type) { JavaType javaType = jsonMapper.getTypeFactory().constructType(type.getType()); - return jsonMapper.convertValue(fromValue, javaType); + try { + return jsonMapper.convertValue(fromValue, javaType); + } + catch (JacksonException ex) { + throw new IllegalArgumentException(ex); + } } @Override diff --git a/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStatelessIntegrationTests.java b/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStatelessIntegrationTests.java index f279e1c41..6c6776c2b 100644 --- a/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStatelessIntegrationTests.java +++ b/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStatelessIntegrationTests.java @@ -951,6 +951,26 @@ void rejectsNonJsonContentType(String contentType) throws Exception { assertThat(toolCalled).isFalse(); } + @Test + void rejectsMalformedMessageAsInvalidRequest() throws Exception { + McpServer.sync(mcpStatelessServerTransport).build(); + + // Valid JSON, but "jsonrpc" is an object instead of a string, so it cannot be + // converted into a JSONRPCRequest + var request = HttpRequest.newBuilder() + .uri(URI.create("http://localhost:" + PORT + CUSTOM_MESSAGE_ENDPOINT)) + .header("Content-Type", APPLICATION_JSON) + .header("Accept", APPLICATION_JSON + ", " + TEXT_EVENT_STREAM) + .POST(HttpRequest.BodyPublishers.ofString(""" + {"jsonrpc":{"a":1},"id":1,"method":"tools/list"}""")) + .build(); + + var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); + + assertThat(response.statusCode()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST); + assertThatJson(response.body()).inPath("message").isEqualTo("Invalid message format"); + } + private double evaluateExpression(String expression) { // Simple expression evaluator for testing return switch (expression) {