From 57c018ca9f2ecbbd748a4992ee73e60fa840ab8d Mon Sep 17 00:00:00 2001 From: 1fanwang <1fannnw@gmail.com> Date: Thu, 3 Sep 2026 02:29:14 -0400 Subject: [PATCH 1/3] Fix empty client request handler responses Signed-off-by: 1fanwang <1fannnw@gmail.com> --- .../spec/McpClientSession.java | 5 ++++- .../spec/McpClientSessionTests.java | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpClientSession.java b/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpClientSession.java index 3d7154278..abf5b22dc 100644 --- a/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpClientSession.java +++ b/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpClientSession.java @@ -201,7 +201,10 @@ private Mono handleIncomingRequest(McpSchema.JSONRPCR } return handler.handle(request.params()) - .map(result -> McpSchema.JSONRPCResponse.result(request.id(), result)); + .map(result -> McpSchema.JSONRPCResponse.result(request.id(), result)) + .switchIfEmpty(Mono.just(McpSchema.JSONRPCResponse + .error(request.id(), new McpSchema.JSONRPCResponse.JSONRPCError(McpSchema.ErrorCodes.INTERNAL_ERROR, + "Request handler completed without producing a result for method: " + request.method())))); }); } diff --git a/mcp-core/src/test/java/io/modelcontextprotocol/spec/McpClientSessionTests.java b/mcp-core/src/test/java/io/modelcontextprotocol/spec/McpClientSessionTests.java index ae5daf1f4..c62e03e5b 100644 --- a/mcp-core/src/test/java/io/modelcontextprotocol/spec/McpClientSessionTests.java +++ b/mcp-core/src/test/java/io/modelcontextprotocol/spec/McpClientSessionTests.java @@ -151,6 +151,23 @@ void testRequestHandling() { session.close(); } + @Test + void testEmptyRequestHandlerSendsErrorResponse() { + var transport = new MockMcpClientTransport(); + var session = new McpClientSession(TIMEOUT, transport, Map.of(TEST_METHOD, params -> Mono.empty()), Map.of(), + Function.identity()); + + transport.simulateIncomingMessage(new McpSchema.JSONRPCRequest(TEST_METHOD, "test-id")); + + assertThat(transport.getLastSentMessage()).isInstanceOf(McpSchema.JSONRPCResponse.class); + McpSchema.JSONRPCResponse response = (McpSchema.JSONRPCResponse) transport.getLastSentMessage(); + assertThat(response.id()).isEqualTo("test-id"); + assertThat(response.error()).isNotNull(); + assertThat(response.error().code()).isEqualTo(McpSchema.ErrorCodes.INTERNAL_ERROR); + + session.close(); + } + @Test void testNotificationHandling() { Sinks.One receivedParams = Sinks.one(); From 1fe444e963e0e850838558089358edfe7342baa1 Mon Sep 17 00:00:00 2001 From: 1fanwang <1fannnw@gmail.com> Date: Thu, 3 Sep 2026 02:46:23 -0400 Subject: [PATCH 2/3] Add required AI assistance disclosure Signed-off-by: 1fanwang <1fannnw@gmail.com> --- disclosure.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 disclosure.txt diff --git a/disclosure.txt b/disclosure.txt new file mode 100644 index 000000000..5e6f34898 --- /dev/null +++ b/disclosure.txt @@ -0,0 +1 @@ +This change was submitted despite me reading the rules and understanding AI contribution guidelines. From 1a2cb57d636d09308f9ca7eb369d52695f52ff9e Mon Sep 17 00:00:00 2001 From: 1fanwang <1fannnw@gmail.com> Date: Thu, 3 Sep 2026 09:59:06 -0400 Subject: [PATCH 3/3] Align empty client responses with server handling Signed-off-by: 1fanwang <1fannnw@gmail.com> --- .../modelcontextprotocol/spec/McpClientSession.java | 12 +++++++++--- .../spec/McpClientSessionTests.java | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpClientSession.java b/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpClientSession.java index abf5b22dc..30ded5c73 100644 --- a/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpClientSession.java +++ b/mcp-core/src/main/java/io/modelcontextprotocol/spec/McpClientSession.java @@ -202,9 +202,15 @@ private Mono handleIncomingRequest(McpSchema.JSONRPCR return handler.handle(request.params()) .map(result -> McpSchema.JSONRPCResponse.result(request.id(), result)) - .switchIfEmpty(Mono.just(McpSchema.JSONRPCResponse - .error(request.id(), new McpSchema.JSONRPCResponse.JSONRPCError(McpSchema.ErrorCodes.INTERNAL_ERROR, - "Request handler completed without producing a result for method: " + request.method())))); + .switchIfEmpty(Mono.defer(() -> { + logger.warn("Request handler for method '{}' completed without producing a result. " + + "Responding with an internal error to honor JSON-RPC 2.0's " + + "one-response-per-request contract.", request.method()); + return Mono.just(McpSchema.JSONRPCResponse.error(request.id(), + new McpSchema.JSONRPCResponse.JSONRPCError(McpSchema.ErrorCodes.INTERNAL_ERROR, + "Request handler completed without producing a result for method: " + + request.method()))); + })); }); } diff --git a/mcp-core/src/test/java/io/modelcontextprotocol/spec/McpClientSessionTests.java b/mcp-core/src/test/java/io/modelcontextprotocol/spec/McpClientSessionTests.java index c62e03e5b..95b5763e6 100644 --- a/mcp-core/src/test/java/io/modelcontextprotocol/spec/McpClientSessionTests.java +++ b/mcp-core/src/test/java/io/modelcontextprotocol/spec/McpClientSessionTests.java @@ -162,8 +162,10 @@ void testEmptyRequestHandlerSendsErrorResponse() { assertThat(transport.getLastSentMessage()).isInstanceOf(McpSchema.JSONRPCResponse.class); McpSchema.JSONRPCResponse response = (McpSchema.JSONRPCResponse) transport.getLastSentMessage(); assertThat(response.id()).isEqualTo("test-id"); + assertThat(response.result()).isNull(); assertThat(response.error()).isNotNull(); assertThat(response.error().code()).isEqualTo(McpSchema.ErrorCodes.INTERNAL_ERROR); + assertThat(response.error().message()).contains("without producing a result"); session.close(); }