diff --git a/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java b/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java index e3a997ba..5042f3b4 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java +++ b/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java @@ -175,6 +175,9 @@ public class McpAsyncClient { // Request Handlers Map> requestHandlers = new HashMap<>(); + // Ping Request Handler + requestHandlers.put(McpSchema.METHOD_PING, pingRequestHandler()); + // Roots List Request Handler if (this.clientCapabilities.roots() != null) { requestHandlers.put(McpSchema.METHOD_ROOTS_LIST, rootsListRequestHandler()); @@ -487,6 +490,13 @@ private RequestHandler rootsListRequestHandler() { }; } + // -------------------------- + // Ping - The receiver MUST respond promptly with an empty response + // -------------------------- + private RequestHandler pingRequestHandler() { + return params -> Mono.just(Map.of()); + } + // -------------------------- // Sampling // -------------------------- diff --git a/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java b/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java index 4510b152..210f0aef 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java @@ -349,4 +349,28 @@ void testSamplingCreateMessageRequestHandlingWithNullHandler() { .hasMessage("Sampling handler must not be null when client capabilities include sampling"); } + @Test + void testPingMessageRequestHandling() { + MockMcpClientTransport transport = initializationEnabledTransport(); + + McpAsyncClient asyncMcpClient = McpClient.async(transport).build(); + + // Simulate incoming ping request from server + McpSchema.JSONRPCRequest pingRequest = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, + McpSchema.METHOD_PING, "ping-id", null); + transport.simulateIncomingMessage(pingRequest); + + // Verify response + McpSchema.JSONRPCMessage sentMessage = transport.getLastSentMessage(); + assertThat(sentMessage).isInstanceOf(McpSchema.JSONRPCResponse.class); + + McpSchema.JSONRPCResponse response = (McpSchema.JSONRPCResponse) sentMessage; + assertThat(response.id()).isEqualTo("ping-id"); + assertThat(response.error()).isNull(); + assertThat(response.result()).isInstanceOf(Map.class); + assertThat(((Map) response.result())).isEmpty(); + + asyncMcpClient.closeGracefully(); + } + }