feat: add ping functionality to MCP server exchanges (#347)

- Add ping() method to McpAsyncServerExchange that sends ping requests to clients
- Add ping() method to McpSyncServerExchange as synchronous wrapper
- Add OBJECT_TYPE_REF constant for ping response type handling
- Create McpSyncServerExchangeTests.java with full test coverage
- Add ping integration tests across WebFlux, WebMVC, and HttpServlet transports

Follow up of #203

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
Christian Tzolov 2025-06-28 09:22:22 +02:00
commit d7bcb237b8
2 changed files with 1040 additions and 6 deletions

View file

@ -1023,4 +1023,61 @@ class WebFluxSseIntegrationTests {
mcpServer.close();
}
}
// ---------------------------------------
// Ping Tests
// ---------------------------------------
@ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient", "webflux" })
void testPingSuccess(String clientType) {
var clientBuilder = clientBuilders.get(clientType);
// Create server with a tool that uses ping functionality
AtomicReference<String> executionOrder = new AtomicReference<>("");
McpServerFeatures.AsyncToolSpecification tool = new McpServerFeatures.AsyncToolSpecification(
new McpSchema.Tool("ping-async-test", "Test ping async behavior", emptyJsonSchema),
(exchange, request) -> {
executionOrder.set(executionOrder.get() + "1");
// Test async ping behavior
return exchange.ping().doOnNext(result -> {
assertThat(result).isNotNull();
// Ping should return an empty object or map
assertThat(result).isInstanceOf(Map.class);
executionOrder.set(executionOrder.get() + "2");
assertThat(result).isNotNull();
}).then(Mono.fromCallable(() -> {
executionOrder.set(executionOrder.get() + "3");
return new CallToolResult("Async ping test completed", false);
}));
});
var mcpServer = McpServer.async(mcpServerTransportProvider)
.serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build())
.tools(tool)
.build();
try (var mcpClient = clientBuilder.build()) {
// Initialize client
InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull();
// Call the tool that tests ping async behavior
CallToolResult result = mcpClient.callTool(new McpSchema.CallToolRequest("ping-async-test", Map.of()));
assertThat(result).isNotNull();
assertThat(result.content().get(0)).isInstanceOf(McpSchema.TextContent.class);
assertThat(((McpSchema.TextContent) result.content().get(0)).text()).isEqualTo("Async ping test completed");
// Verify execution order
assertThat(executionOrder.get()).isEqualTo("123");
}
mcpServer.closeGracefully().block();
}
}

View file

@ -862,4 +862,58 @@ class WebMvcSseIntegrationTests {
mcpServer.close();
}
// ---------------------------------------
// Ping Tests
// ---------------------------------------
@Test
void testPingSuccess() {
// Create server with a tool that uses ping functionality
AtomicReference<String> executionOrder = new AtomicReference<>("");
McpServerFeatures.AsyncToolSpecification tool = new McpServerFeatures.AsyncToolSpecification(
new McpSchema.Tool("ping-async-test", "Test ping async behavior", emptyJsonSchema),
(exchange, request) -> {
executionOrder.set(executionOrder.get() + "1");
// Test async ping behavior
return exchange.ping().doOnNext(result -> {
assertThat(result).isNotNull();
// Ping should return an empty object or map
assertThat(result).isInstanceOf(Map.class);
executionOrder.set(executionOrder.get() + "2");
assertThat(result).isNotNull();
}).then(Mono.fromCallable(() -> {
executionOrder.set(executionOrder.get() + "3");
return new CallToolResult("Async ping test completed", false);
}));
});
var mcpServer = McpServer.async(mcpServerTransportProvider)
.serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build())
.tools(tool)
.build();
try (var mcpClient = clientBuilder.build()) {
// Initialize client
InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull();
// Call the tool that tests ping async behavior
CallToolResult result = mcpClient.callTool(new McpSchema.CallToolRequest("ping-async-test", Map.of()));
assertThat(result).isNotNull();
assertThat(result.content().get(0)).isInstanceOf(McpSchema.TextContent.class);
assertThat(((McpSchema.TextContent) result.content().get(0)).text()).isEqualTo("Async ping test completed");
// Verify execution order
assertThat(executionOrder.get()).isEqualTo("123");
}
mcpServer.close();
}
}