From 0fc1541c617d03ce550c86a70953193b4cc5b575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20J=C4=99drzejczyk?= Date: Wed, 4 Mar 2026 14:38:02 +0100 Subject: [PATCH 1/3] Bind WebFlux servers in IT to 0.0.0.0 interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Dariusz Jędrzejczyk --- .../src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java | 3 +-- .../java/org/springframework/ai/mcp/WebFluxStatelessIT.java | 2 +- .../ai/mcp/WebFluxStreamableHttpVersionNegotiationIT.java | 2 +- .../java/org/springframework/ai/mcp/WebFluxStreamableIT.java | 2 +- .../ai/mcp/common/AsyncServerMcpTransportContextIT.java | 2 +- .../ai/mcp/common/SyncServerMcpTransportContextIT.java | 2 +- .../ai/mcp/security/WebFluxServerTransportSecurityIT.java | 2 +- .../server/webflux/transport/WebFluxSseMcpAsyncServerIT.java | 2 +- .../server/webflux/transport/WebFluxSseMcpSyncServerIT.java | 2 +- .../webflux/transport/WebFluxStreamableMcpAsyncServerIT.java | 2 +- .../webflux/transport/WebFluxStreamableMcpSyncServerIT.java | 2 +- 11 files changed, 11 insertions(+), 12 deletions(-) diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java index f0b68bf4e65..72a75576a1f 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java @@ -44,7 +44,6 @@ import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerRequest; -@Disabled("Flaky test - needs investigation") @Timeout(45) class WebFluxSseIT extends AbstractMcpClientServerIntegrationTests { @@ -102,7 +101,7 @@ public void before() { HttpHandler httpHandler = RouterFunctions.toHttpHandler(this.mcpServerTransportProvider.getRouterFunction()); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - this.httpServer = HttpServer.create().port(0).handle(adapter).bindNow(); + this.httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); prepareClients(this.httpServer.port(), null); } diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStatelessIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStatelessIT.java index ebc54ad5916..b162ee0a329 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStatelessIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStatelessIT.java @@ -86,7 +86,7 @@ public void before() { HttpHandler httpHandler = RouterFunctions.toHttpHandler(this.mcpStreamableServerTransport.getRouterFunction()); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - this.httpServer = HttpServer.create().port(0).handle(adapter).bindNow(); + this.httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); prepareClients(this.httpServer.port(), null); } diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableHttpVersionNegotiationIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableHttpVersionNegotiationIT.java index 79dd3395e47..e4d684c1bc7 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableHttpVersionNegotiationIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableHttpVersionNegotiationIT.java @@ -90,7 +90,7 @@ void setUp() { ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - this.httpServer = HttpServer.create().port(0).handle(adapter).bindNow(); + this.httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); this.port = this.httpServer.port(); } diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableIT.java index d1e05fac4ff..41f524bd4f4 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableIT.java @@ -97,7 +97,7 @@ public void before() { HttpHandler httpHandler = RouterFunctions .toHttpHandler(this.mcpStreamableServerTransportProvider.getRouterFunction()); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - this.httpServer = HttpServer.create().port(0).handle(adapter).bindNow(); + this.httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); prepareClients(this.httpServer.port(), null); } diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/common/AsyncServerMcpTransportContextIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/common/AsyncServerMcpTransportContextIT.java index 4f609a454e9..52287bd10e9 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/common/AsyncServerMcpTransportContextIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/common/AsyncServerMcpTransportContextIT.java @@ -259,7 +259,7 @@ private void startHttpServer(RouterFunction routerFunction) { HttpHandler httpHandler = RouterFunctions.toHttpHandler(routerFunction); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - this.httpServer = HttpServer.create().port(0).handle(adapter).bindNow(); + this.httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); int port = this.httpServer.port(); this.asyncStreamableClient = McpClient .async(WebClientStreamableHttpTransport diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/common/SyncServerMcpTransportContextIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/common/SyncServerMcpTransportContextIT.java index 8708cb24f20..5958f8b6513 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/common/SyncServerMcpTransportContextIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/common/SyncServerMcpTransportContextIT.java @@ -245,7 +245,7 @@ private void startHttpServer(RouterFunction routerFunction) { HttpHandler httpHandler = RouterFunctions.toHttpHandler(routerFunction); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - this.httpServer = HttpServer.create().port(0).handle(adapter).bindNow(); + this.httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); int port = this.httpServer.port(); this.streamableClient = McpClient.sync(WebClientStreamableHttpTransport.builder(WebClient.builder() .baseUrl("http://127.0.0.1:" + port) diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/security/WebFluxServerTransportSecurityIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/security/WebFluxServerTransportSecurityIT.java index f8f986549dd..a96d69b0b56 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/security/WebFluxServerTransportSecurityIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/security/WebFluxServerTransportSecurityIT.java @@ -167,7 +167,7 @@ void messageHostNotAllowed() { private static void startServer(RouterFunction routerFunction) { HttpHandler httpHandler = RouterFunctions.toHttpHandler(routerFunction); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - httpServer = HttpServer.create().port(0).handle(adapter).bindNow(); + httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); baseUrl = "http://localhost:" + httpServer.port(); } diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxSseMcpAsyncServerIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxSseMcpAsyncServerIT.java index 3fdc74cfdf5..2ae484a80a1 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxSseMcpAsyncServerIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxSseMcpAsyncServerIT.java @@ -46,7 +46,7 @@ private McpServerTransportProvider createMcpTransportProvider() { HttpHandler httpHandler = RouterFunctions.toHttpHandler(transportProvider.getRouterFunction()); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - this.httpServer = HttpServer.create().port(0).handle(adapter).bindNow(); + this.httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); return transportProvider; } diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxSseMcpSyncServerIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxSseMcpSyncServerIT.java index a6387083700..1e038db212e 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxSseMcpSyncServerIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxSseMcpSyncServerIT.java @@ -57,7 +57,7 @@ private McpServerTransportProvider createMcpTransportProvider() { protected void onStart() { HttpHandler httpHandler = RouterFunctions.toHttpHandler(this.transportProvider.getRouterFunction()); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - this.httpServer = HttpServer.create().port(0).handle(adapter).bindNow(); + this.httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); } @Override diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxStreamableMcpAsyncServerIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxStreamableMcpAsyncServerIT.java index 5dae985f68d..b833dc167c0 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxStreamableMcpAsyncServerIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxStreamableMcpAsyncServerIT.java @@ -49,7 +49,7 @@ private McpStreamableServerTransportProvider createMcpTransportProvider() { HttpHandler httpHandler = RouterFunctions.toHttpHandler(transportProvider.getRouterFunction()); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - this.httpServer = HttpServer.create().port(0).handle(adapter).bindNow(); + this.httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); return transportProvider; } diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxStreamableMcpSyncServerIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxStreamableMcpSyncServerIT.java index ad51f8830c2..38cf503e11d 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxStreamableMcpSyncServerIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/server/webflux/transport/WebFluxStreamableMcpSyncServerIT.java @@ -49,7 +49,7 @@ private McpStreamableServerTransportProvider createMcpTransportProvider() { HttpHandler httpHandler = RouterFunctions.toHttpHandler(transportProvider.getRouterFunction()); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); - this.httpServer = HttpServer.create().port(0).handle(adapter).bindNow(); + this.httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); return transportProvider; } From a9cbbc697bb13aae3e7e8fbdd3e8d22b596b435e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20J=C4=99drzejczyk?= Date: Wed, 4 Mar 2026 14:42:20 +0100 Subject: [PATCH 2/3] Imports and disabled tests correction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Dariusz Jędrzejczyk --- .../src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java | 1 - .../ai/mcp/WebFluxStreamableHttpVersionNegotiationIT.java | 2 -- 2 files changed, 3 deletions(-) diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java index 72a75576a1f..0d528b50e02 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java @@ -30,7 +30,6 @@ import io.modelcontextprotocol.server.McpTransportContextExtractor; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.provider.Arguments; import reactor.netty.DisposableServer; diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableHttpVersionNegotiationIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableHttpVersionNegotiationIT.java index e4d684c1bc7..57ef4cda0ee 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableHttpVersionNegotiationIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxStreamableHttpVersionNegotiationIT.java @@ -32,7 +32,6 @@ import org.awaitility.Awaitility; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import reactor.netty.DisposableServer; import reactor.netty.http.server.HttpServer; @@ -50,7 +49,6 @@ import static org.assertj.core.api.Assertions.assertThat; -@Disabled("Flaky in CI, needs investigation") class WebFluxStreamableHttpVersionNegotiationIT { private DisposableServer httpServer; From 94062759f327823ce48e4545adfd4f1ccf71f45d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20J=C4=99drzejczyk?= Date: Wed, 4 Mar 2026 15:05:59 +0100 Subject: [PATCH 3/3] Add a temporary sanity check for server start and enable debug logs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Dariusz Jędrzejczyk --- .../springframework/ai/mcp/WebFluxSseIT.java | 36 ++++++++++++++++++- .../src/test/resources/logback.xml | 11 ++---- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java index 0d528b50e02..e331e54740f 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java +++ b/mcp/transport/mcp-spring-webflux/src/test/java/org/springframework/ai/mcp/WebFluxSseIT.java @@ -16,8 +16,11 @@ package org.springframework.ai.mcp; +import java.net.HttpURLConnection; +import java.net.URL; import java.time.Duration; import java.util.Map; +import java.util.concurrent.TimeUnit; import java.util.stream.Stream; import io.modelcontextprotocol.AbstractMcpClientServerIntegrationTests; @@ -28,10 +31,13 @@ import io.modelcontextprotocol.server.McpServer.AsyncSpecification; import io.modelcontextprotocol.server.McpServer.SingleSessionSyncSpecification; import io.modelcontextprotocol.server.McpTransportContextExtractor; +import org.awaitility.Awaitility; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.provider.Arguments; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import reactor.netty.DisposableServer; import reactor.netty.http.server.HttpServer; @@ -46,6 +52,8 @@ @Timeout(45) class WebFluxSseIT extends AbstractMcpClientServerIntegrationTests { + private static final Logger log = LoggerFactory.getLogger(WebFluxSseIT.class); + private static final String CUSTOM_SSE_ENDPOINT = "/somePath/sse"; private static final String CUSTOM_MESSAGE_ENDPOINT = "/otherPath/mcp/message"; @@ -102,7 +110,33 @@ public void before() { ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); this.httpServer = HttpServer.create().port(0).host("0.0.0.0").handle(adapter).bindNow(); - prepareClients(this.httpServer.port(), null); + int port = this.httpServer.port(); + log.info("Reactor Netty server bound to host='{}' port={}", this.httpServer.host(), port); + + String probeUrl = "http://127.0.0.1:" + port + CUSTOM_SSE_ENDPOINT; + Awaitility.await() + .alias("MCP server reachable at " + probeUrl) + .atMost(10, TimeUnit.SECONDS) + .pollInterval(200, TimeUnit.MILLISECONDS) + .untilAsserted(() -> { + HttpURLConnection conn = (HttpURLConnection) new URL(probeUrl).openConnection(); + conn.setConnectTimeout(1000); + conn.setReadTimeout(1000); + conn.setRequestMethod("GET"); + try { + int status = conn.getResponseCode(); + log.info("Sanity probe {} -> HTTP {}", probeUrl, status); + // SSE endpoint returns 200 (it streams); message endpoint returns 4xx + // for a bare GET. Either way, any HTTP response means the server is + // up. + org.assertj.core.api.Assertions.assertThat(status).isGreaterThan(0); + } + finally { + conn.disconnect(); + } + }); + + prepareClients(port, null); } @AfterEach diff --git a/mcp/transport/mcp-spring-webflux/src/test/resources/logback.xml b/mcp/transport/mcp-spring-webflux/src/test/resources/logback.xml index abc831d13bd..ed6f505f12b 100644 --- a/mcp/transport/mcp-spring-webflux/src/test/resources/logback.xml +++ b/mcp/transport/mcp-spring-webflux/src/test/resources/logback.xml @@ -8,15 +8,8 @@ - - - - - - - - - + +