Fix everything-server-based integration tests (#756)

* Pin `npx @modelcontextprotocol/server-everything` version to `2025.12.18`.
* Replace `tzolov/mcp-everything-server` Docker image with `node:lts-alpine` + `npx` command.
* Handle HTTP 202 special case.
* Fix test assertions.

The recent rollout of everything-server broke integration tests which take the latest version from the node registry.
This PR unifies the everything-server usage - the Testcontainers Docker setup uses the same version as the STDIO npx-based tests and no longer relies on tzolov/mcp-everything-server.

Signed-off-by: Dariusz Jędrzejczyk <dariusz.jedrzejczyk@broadcom.com>
This commit is contained in:
Dariusz Jędrzejczyk 2026-01-20 16:09:41 +01:00 • committed by GitHub
commit af65356416
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 144 additions and 139 deletions

View file

@ -47,10 +47,9 @@ public abstract class AbstractMcpAsyncClientResiliencyTests {
static Network network = Network.newNetwork();
static String host = "http://localhost:3001";
// Uses the https://github.com/tzolov/mcp-everything-server-docker-image
@SuppressWarnings("resource")
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v3")
.withCommand("node dist/index.js streamableHttp")
static GenericContainer<?> container = new GenericContainer<>("docker.io/node:lts-alpine3.23")
.withCommand("npx -y @modelcontextprotocol/server-everything@2025.12.18 streamableHttp")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withNetwork(network)
.withNetworkAliases("everything-server")

View file

@ -4,6 +4,7 @@
package io.modelcontextprotocol.client;
import static io.modelcontextprotocol.util.McpJsonMapperUtils.JSON_MAPPER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@ -52,8 +53,6 @@ import reactor.core.publisher.Mono;
import reactor.core.publisher.Sinks;
import reactor.test.StepVerifier;
import static io.modelcontextprotocol.util.McpJsonMapperUtils.JSON_MAPPER;
/**
* Test suite for the {@link McpAsyncClient} that can be used with different
* {@link McpTransport} implementations.
@ -72,7 +71,7 @@ public abstract class AbstractMcpAsyncClientTests {
}
protected Duration getInitializationTimeout() {
return Duration.ofSeconds(2);
return Duration.ofSeconds(20);
}
McpAsyncClient client(McpClientTransport transport) {
@ -503,57 +502,64 @@ public abstract class AbstractMcpAsyncClientTests {
@Test
void testReadResource() {
AtomicInteger resourceCount = new AtomicInteger();
withClient(createMcpTransport(), client -> {
Flux<McpSchema.ReadResourceResult> resources = client.initialize()
.then(client.listResources(null))
.flatMapMany(r -> Flux.fromIterable(r.resources()))
.flatMapMany(r -> {
List<Resource> l = r.resources();
resourceCount.set(l.size());
return Flux.fromIterable(l);
})
.flatMap(r -> client.readResource(r));
StepVerifier.create(resources).recordWith(ArrayList::new).consumeRecordedWith(readResourceResults -> {
StepVerifier.create(resources)
.recordWith(ArrayList::new)
.thenConsumeWhile(res -> true)
.consumeRecordedWith(readResourceResults -> {
assertThat(readResourceResults.size()).isEqualTo(resourceCount.get());
for (ReadResourceResult result : readResourceResults) {
for (ReadResourceResult result : readResourceResults) {
assertThat(result).isNotNull();
assertThat(result.contents()).isNotNull().isNotEmpty();
assertThat(result).isNotNull();
assertThat(result.contents()).isNotNull().isNotEmpty();
// Validate each content item
for (ResourceContents content : result.contents()) {
assertThat(content).isNotNull();
assertThat(content.uri()).isNotNull().isNotEmpty();
assertThat(content.mimeType()).isNotNull().isNotEmpty();
// Validate each content item
for (ResourceContents content : result.contents()) {
assertThat(content).isNotNull();
assertThat(content.uri()).isNotNull().isNotEmpty();
assertThat(content.mimeType()).isNotNull().isNotEmpty();
// Validate content based on its type with more comprehensive
// checks
switch (content.mimeType()) {
case "text/plain" -> {
TextResourceContents textContent = assertInstanceOf(TextResourceContents.class,
content);
assertThat(textContent.text()).isNotNull().isNotEmpty();
assertThat(textContent.uri()).isNotEmpty();
}
case "application/octet-stream" -> {
BlobResourceContents blobContent = assertInstanceOf(BlobResourceContents.class,
content);
assertThat(blobContent.blob()).isNotNull().isNotEmpty();
assertThat(blobContent.uri()).isNotNull().isNotEmpty();
// Validate base64 encoding format
assertThat(blobContent.blob()).matches("^[A-Za-z0-9+/]*={0,2}$");
}
default -> {
// Still validate basic properties
if (content instanceof TextResourceContents textContent) {
assertThat(textContent.text()).isNotNull();
// Validate content based on its type with more comprehensive
// checks
switch (content.mimeType()) {
case "text/plain" -> {
TextResourceContents textContent = assertInstanceOf(TextResourceContents.class,
content);
assertThat(textContent.text()).isNotNull().isNotEmpty();
assertThat(textContent.uri()).isNotEmpty();
}
else if (content instanceof BlobResourceContents blobContent) {
assertThat(blobContent.blob()).isNotNull();
case "application/octet-stream" -> {
BlobResourceContents blobContent = assertInstanceOf(BlobResourceContents.class,
content);
assertThat(blobContent.blob()).isNotNull().isNotEmpty();
assertThat(blobContent.uri()).isNotNull().isNotEmpty();
// Validate base64 encoding format
assertThat(blobContent.blob()).matches("^[A-Za-z0-9+/]*={0,2}$");
}
default -> {
// Still validate basic properties
if (content instanceof TextResourceContents textContent) {
assertThat(textContent.text()).isNotNull();
}
else if (content instanceof BlobResourceContents blobContent) {
assertThat(blobContent.blob()).isNotNull();
}
}
}
}
}
}
})
.expectNextCount(10) // Expect 10 elements
})
.verifyComplete();
});
}
@ -673,7 +679,7 @@ public abstract class AbstractMcpAsyncClientTests {
@Test
void testInitializeWithAllCapabilities() {
var capabilities = ClientCapabilities.builder()
.experimental(Map.of("feature", "test"))
.experimental(Map.of("feature", Map.of("featureFlag", true)))
.roots(true)
.sampling()
.build();
@ -693,7 +699,6 @@ public abstract class AbstractMcpAsyncClientTests {
assertThat(result.capabilities()).isNotNull();
}).verifyComplete());
}
// ---------------------------------------
// Logging Tests
// ---------------------------------------
@ -773,7 +778,7 @@ public abstract class AbstractMcpAsyncClientTests {
if (!(content instanceof McpSchema.TextContent text))
return;
assertThat(text.text()).endsWith(response); // Prefixed
assertThat(text.text()).contains(response);
});
// Verify sampling request parameters received in our callback

View file

@ -624,7 +624,7 @@ public abstract class AbstractMcpSyncClientTests {
if (!(content instanceof McpSchema.TextContent text))
return;
assertThat(text.text()).endsWith(response); // Prefixed
assertThat(text.text()).contains(response);
});
// Verify sampling request parameters received in our callback