From 6561d16ebc3fa07b159f5aef3eeb449cb837b667 Mon Sep 17 00:00:00 2001 From: or-givati Date: Mon, 24 Mar 2025 14:41:07 +0200 Subject: [PATCH 1/5] replace path matching from `getPathInfo` to `getRequestURI`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `getRequestURI()` → full request path (without query). `getPathInfo()` → extra path after the servlet's mapping, or null if none. So if I am configuring my Servlet to be mapped on `/somePath` and initiating the Servlet: ``` new HttpServletSseServerTransport(new ObjectMapper(), "/somePath/message", "/somePath/sse") ``` it will work and won't fail. `getPathInfo` will return "/message" and "/sse". while `getRequestURI` will return "/somePath/message" and "/somePath/sse" and will not fail on the validation. --- .../transport/HttpServletSseServerTransportProvider.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletSseServerTransportProvider.java b/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletSseServerTransportProvider.java index 152462b1d..64a1752d7 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletSseServerTransportProvider.java +++ b/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletSseServerTransportProvider.java @@ -170,8 +170,8 @@ public Mono notifyClients(String method, Map params) { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - String pathInfo = request.getPathInfo(); - if (!sseEndpoint.equals(pathInfo)) { + String requestURI = request.getRequestURI(); + if (!sseEndpoint.equals(requestURI)) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } @@ -225,8 +225,8 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) return; } - String pathInfo = request.getPathInfo(); - if (!messageEndpoint.equals(pathInfo)) { + String requestURI = request.getRequestURI(); + if (!messageEndpoint.equals(requestURI)) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } From 39b426ebda02b5fcde3d1a03f263b14ebb16b965 Mon Sep 17 00:00:00 2001 From: or-givati Date: Fri, 25 Apr 2025 11:21:40 +0300 Subject: [PATCH 2/5] feat(McpAsyncClient): handle ping request --- .../client/McpAsyncClient.java | 7 +++++ .../McpAsyncClientResponseHandlerTests.java | 28 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java b/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java index e3a997ba3..49abb448d 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()); @@ -486,6 +489,10 @@ private RequestHandler rootsListRequestHandler() { return Mono.just(new McpSchema.ListRootsResult(roots)); }; } + + 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 4510b1529..9b9be0a0d 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java @@ -349,4 +349,32 @@ 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(); + } + } From b48b63e41659f14c6f2163ef3b3f0cc3de502715 Mon Sep 17 00:00:00 2001 From: or-givati Date: Fri, 25 Apr 2025 11:28:59 +0300 Subject: [PATCH 3/5] fix styles --- .../io/modelcontextprotocol/client/McpAsyncClient.java | 2 +- .../client/McpAsyncClientResponseHandlerTests.java | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java b/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java index 49abb448d..4a2c05726 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java +++ b/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java @@ -489,7 +489,7 @@ private RequestHandler rootsListRequestHandler() { return Mono.just(new McpSchema.ListRootsResult(roots)); }; } - + private RequestHandler pingRequestHandler() { return params -> Mono.just(Map.of()); } diff --git a/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java b/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java index 9b9be0a0d..210f0aef9 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java @@ -349,19 +349,15 @@ void testSamplingCreateMessageRequestHandlingWithNullHandler() { .hasMessage("Sampling handler must not be null when client capabilities include sampling"); } - @Test + @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 - ); + McpSchema.JSONRPCRequest pingRequest = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, + McpSchema.METHOD_PING, "ping-id", null); transport.simulateIncomingMessage(pingRequest); // Verify response From e4446c97210a9cbcd201fe132d034af19d75a5cf Mon Sep 17 00:00:00 2001 From: or-givati Date: Fri, 25 Apr 2025 14:11:20 +0300 Subject: [PATCH 4/5] add comment --- .../java/io/modelcontextprotocol/client/McpAsyncClient.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java b/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java index 4a2c05726..0a0945442 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java +++ b/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java @@ -490,6 +490,10 @@ private RequestHandler rootsListRequestHandler() { }; } + + // -------------------------- + // Ping - The receiver MUST respond promptly with an empty response + // -------------------------- private RequestHandler pingRequestHandler() { return params -> Mono.just(Map.of()); } From 1925137c2cd54cb70c096900ba1aa2b9f0a2c322 Mon Sep 17 00:00:00 2001 From: or-givati Date: Fri, 25 Apr 2025 14:19:36 +0300 Subject: [PATCH 5/5] fix format --- .../main/java/io/modelcontextprotocol/client/McpAsyncClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java b/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java index 0a0945442..5042f3b40 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java +++ b/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java @@ -490,7 +490,6 @@ private RequestHandler rootsListRequestHandler() { }; } - // -------------------------- // Ping - The receiver MUST respond promptly with an empty response // --------------------------