Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,9 @@ public Mono<Void> sendMessage(McpSchema.JSONRPCMessage sentMessage) {
.firstValue(HttpHeaders.CONTENT_LENGTH)
.orElse(null);

if (contentType.isBlank() || "0".equals(contentLength)) {
// For empty content or HTTP code 202 (ACCEPTED), assume success
if (contentType.isBlank() || "0".equals(contentLength) || statusCode == 202) {
// if (contentType.isBlank() || "0".equals(contentLength)) {
logger.debug("No body returned for POST in session {}", sessionRepresentation);
// No content type means no response body, so we can just
// return an empty stream
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ protected Duration getRequestTimeout() {
}

protected Duration getInitializationTimeout() {
return Duration.ofSeconds(2);
return Duration.ofSeconds(20);
}

McpAsyncClient client(McpClientTransport transport) {
Expand Down Expand Up @@ -503,57 +503,64 @@ void testRemoveNonExistentRoot() {

@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 -> {

for (ReadResourceResult result : readResourceResults) {

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 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();
StepVerifier.create(resources)
.recordWith(ArrayList::new)
.thenConsumeWhile(res -> true)
.consumeRecordedWith(readResourceResults -> {
assertThat(readResourceResults.size()).isEqualTo(resourceCount.get());
for (ReadResourceResult result : readResourceResults) {

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 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}$");
}
else if (content instanceof BlobResourceContents blobContent) {
assertThat(blobContent.blob()).isNotNull();
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();
});
}
Expand Down Expand Up @@ -693,7 +700,6 @@ void testInitializeWithAllCapabilities() {
assertThat(result.capabilities()).isNotNull();
}).verifyComplete());
}

// ---------------------------------------
// Logging Tests
// ---------------------------------------
Expand Down Expand Up @@ -773,7 +779,7 @@ void testSampling() {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ void testSampling() {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ public class HttpClientStreamableHttpAsyncClientTests extends AbstractMcpAsyncCl

private 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()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,9 @@ public class HttpClientStreamableHttpSyncClientTests extends AbstractMcpSyncClie

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()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ public class HttpSseMcpAsyncClientLostConnectionTests {
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 sse")
static GenericContainer<?> container = new GenericContainer<>("docker.io/node:lts-alpine3.23")
.withCommand("npx -y @modelcontextprotocol/server-everything@2025.12.18 sse")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withNetwork(network)
.withNetworkAliases("everything-server")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ class HttpSseMcpAsyncClientTests extends AbstractMcpAsyncClientTests {

private static String host = "http://localhost:3004";

// 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 sse")
static GenericContainer<?> container = new GenericContainer<>("docker.io/node:lts-alpine3.23")
.withCommand("npx -y @modelcontextprotocol/server-everything@2025.12.18 sse")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ class HttpSseMcpSyncClientTests extends AbstractMcpSyncClientTests {

static String host = "http://localhost:3003";

// 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 sse")
static GenericContainer<?> container = new GenericContainer<>("docker.io/node:lts-alpine3.23")
.withCommand("npx -y @modelcontextprotocol/server-everything@2025.12.18 sse")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ private ServerParameterUtils() {
public static ServerParameters createServerParameters() {
if (System.getProperty("os.name").toLowerCase().contains("win")) {
return ServerParameters.builder("cmd.exe")
.args("/c", "npx.cmd", "-y", "@modelcontextprotocol/server-everything", "stdio")
.args("/c", "npx.cmd", "-y", "@modelcontextprotocol/server-everything@2025.12.18", "stdio")
.build();
}
return ServerParameters.builder("npx").args("-y", "@modelcontextprotocol/server-everything", "stdio").build();
return ServerParameters.builder("npx")
.args("-y", "@modelcontextprotocol/server-everything@2025.12.18", "stdio")
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ class HttpClientSseClientTransportTests {
static String host = "http://localhost:3001";

@SuppressWarnings("resource")
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v3")
.withCommand("node dist/index.js sse")
static GenericContainer<?> container = new GenericContainer<>("docker.io/node:lts-alpine3.23")
.withCommand("npx -y @modelcontextprotocol/server-everything@2025.12.18 sse")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ class HttpClientStreamableHttpTransportTest {
.create(Map.of("test-transport-context-key", "some-value"));

@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()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,8 @@ public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {
long contentLength = response.headers().contentLength().orElse(-1);
// Existing SDKs consume notifications with no response body nor
// content type
if (contentType.isEmpty() || contentLength == 0) {
if (contentType.isEmpty() || contentLength == 0
|| response.statusCode().equals(HttpStatus.ACCEPTED)) {
logger.trace("Message was successfully sent via POST for session {}",
sessionRepresentation);
// signal the caller that the message was successfully
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ public class WebClientStreamableHttpAsyncClientTests extends AbstractMcpAsyncCli

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()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ public class WebClientStreamableHttpSyncClientTests extends AbstractMcpSyncClien

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()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,12 @@ class WebFluxSseMcpAsyncClientTests extends AbstractMcpAsyncClientTests {

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 sse")
static GenericContainer<?> container = new GenericContainer<>("docker.io/node:lts-alpine3.23")
.withCommand("npx -y @modelcontextprotocol/server-everything@2025.12.18 sse")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
.waitingFor(Wait.forHttp("/").forStatusCode(404).forPort(3001));

@Override
protected McpClientTransport createMcpTransport() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ class WebFluxSseMcpSyncClientTests extends AbstractMcpSyncClientTests {

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 sse")
static GenericContainer<?> container = new GenericContainer<>("docker.io/node:lts-alpine3.23")
.withCommand("npx -y @modelcontextprotocol/server-everything@2025.12.18 sse")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class WebClientStreamableHttpTransportTest {
static WebClient.Builder builder;

@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()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ class WebFluxSseClientTransportTests {
static String host = "http://localhost:3001";

@SuppressWarnings("resource")
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v3")
.withCommand("node dist/index.js sse")
static GenericContainer<?> container = new GenericContainer<>("docker.io/node:lts-alpine3.23")
.withCommand("npx -y @modelcontextprotocol/server-everything@2025.12.18 sse")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withExposedPorts(3001)
.waitingFor(Wait.forHttp("/").forStatusCode(404));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Loading