This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-mcp-server.git
The following commit(s) were added to refs/heads/master by this push:
new 38dba65 SLING-13210 - McpServerIT.toolIsRegisteredAndCanBeInvoked is
flaky (#19)
38dba65 is described below
commit 38dba65a97ae732ee9576492950ced47862adc1b
Author: Robert Munteanu <[email protected]>
AuthorDate: Wed May 20 16:17:12 2026 +0200
SLING-13210 - McpServerIT.toolIsRegisteredAndCanBeInvoked is flaky (#19)
Make MCP client initialisation more robust.
---
.../org/apache/sling/mcp/server/McpServerIT.java | 38 +++++++++++++++++++---
1 file changed, 34 insertions(+), 4 deletions(-)
diff --git a/src/test/java/org/apache/sling/mcp/server/McpServerIT.java
b/src/test/java/org/apache/sling/mcp/server/McpServerIT.java
index b3b7b10..0a360ee 100644
--- a/src/test/java/org/apache/sling/mcp/server/McpServerIT.java
+++ b/src/test/java/org/apache/sling/mcp/server/McpServerIT.java
@@ -19,11 +19,13 @@
package org.apache.sling.mcp.server;
import java.net.URI;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Base64;
import java.util.Map;
import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpSyncClient;
@@ -47,6 +49,7 @@ class McpServerIT {
private static final Duration AWAIT_TIMEOUT = Duration.ofSeconds(30);
private static final Duration AWAIT_POLL_INTERVAL = Duration.ofMillis(500);
+ private static final String MCP_ENDPOINT = "/bin/mcp";
private static int slingPort;
private static McpItSupportBundle supportBundle;
@@ -70,18 +73,45 @@ class McpServerIT {
supportBundle.install(sling.adaptTo(OsgiConsoleClient.class));
// build the MCP sync client with HTTP Basic Auth for admin access.
- String basicAuthHeader = "Basic " +
Base64.getEncoder().encodeToString("admin:admin".getBytes());
+ String basicAuthHeader =
+ "Basic " +
Base64.getEncoder().encodeToString("admin:admin".getBytes(StandardCharsets.UTF_8));
+ mcpClient = initializeMcpClient(basicAuthHeader);
+ }
+
+ private McpSyncClient initializeMcpClient(String basicAuthHeader) {
+ AtomicReference<McpSyncClient> initializedClient = new
AtomicReference<>();
+
+ await("mcp client initializes")
+ .atMost(AWAIT_TIMEOUT)
+ .pollInterval(AWAIT_POLL_INTERVAL)
+ .ignoreExceptions()
+ .until(() -> {
+ McpSyncClient candidate = buildMcpClient(basicAuthHeader);
+
+ try {
+ candidate.initialize();
+ initializedClient.set(candidate);
+ return true;
+ } catch (RuntimeException e) {
+ candidate.close();
+ throw e;
+ }
+ });
+
+ return initializedClient.get();
+ }
+
+ private McpSyncClient buildMcpClient(String basicAuthHeader) {
HttpClientStreamableHttpTransport transport =
HttpClientStreamableHttpTransport.builder(
"http://localhost:" + slingPort)
- .endpoint("/bin/mcp")
+ .endpoint(MCP_ENDPOINT)
.customizeRequest(rb -> rb.header("Authorization",
basicAuthHeader))
.build();
- mcpClient = McpClient.sync(transport)
+ return McpClient.sync(transport)
.clientInfo(new McpSchema.Implementation("mcp-server-it",
"1.0"))
.requestTimeout(Duration.ofSeconds(30))
.build();
- mcpClient.initialize();
}
@AfterEach