From f776b24b28f7e7005ecf1e96d23dcbefe2ca7718 Mon Sep 17 00:00:00 2001 From: Luca Chang Date: Mon, 19 May 2025 16:11:07 -0700 Subject: [PATCH 1/3] chore: implement integration tests for resources --- .../client/StdioMcpSyncClientTests.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java b/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java index 706aa9b2..a4c77952 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java @@ -12,12 +12,14 @@ import io.modelcontextprotocol.client.transport.ServerParameters; import io.modelcontextprotocol.client.transport.StdioClientTransport; import io.modelcontextprotocol.spec.McpClientTransport; +import io.modelcontextprotocol.spec.McpSchema; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import reactor.core.publisher.Sinks; import reactor.test.StepVerifier; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; /** * Tests for the {@link McpSyncClient} with {@link StdioClientTransport}. @@ -67,6 +69,67 @@ void customErrorHandlerShouldReceiveErrors() throws InterruptedException { StepVerifier.create(transport.closeGracefully()).expectComplete().verify(Duration.ofSeconds(5)); } + @Test + void testListReadResources() { + McpClientTransport transport = createMcpTransport(); + + withClient(transport, client -> { + client.initialize(); + + int i = 0; + String nextCursor = null; + do { + McpSchema.ListResourcesResult result = client.listResources(nextCursor); + nextCursor = result.nextCursor(); + + for (McpSchema.Resource resource : result.resources()) { + McpSchema.ReadResourceResult resourceResult = client.readResource(resource); + + if (i % 2 == 0) { + assertThat(resourceResult.contents()).allSatisfy(content -> { + McpSchema.TextResourceContents text = assertInstanceOf(McpSchema.TextResourceContents.class, content); + assertThat(text.mimeType()).isEqualTo("text/plain"); + assertThat(text.uri()).isNotEmpty(); + assertThat(text.text()).isNotEmpty(); + }); + } else { + assertThat(resourceResult.contents()).allSatisfy(content -> { + McpSchema.BlobResourceContents blob = assertInstanceOf(McpSchema.BlobResourceContents.class, content); + assertThat(blob.mimeType()).isEqualTo("application/octet-stream"); + assertThat(blob.uri()).isNotEmpty(); + assertThat(blob.blob()).isNotEmpty(); + }); + } + + i++; + } + } while (nextCursor != null); + }); + } + + @Test + void testListResourceTemplates() { + McpClientTransport transport = createMcpTransport(); + + withClient(transport, client -> { + client.initialize(); + + String nextCursor = null; + do { + McpSchema.ListResourceTemplatesResult result = client.listResourceTemplates(nextCursor); + nextCursor = result.nextCursor(); + + for (McpSchema.ResourceTemplate resourceTemplate : result.resourceTemplates()) { + // mimeType is null in @modelcontextprotocol/server-everything, but we don't assert that it's + // null in case they change that later. + assertThat(resourceTemplate.uriTemplate()).isNotEmpty(); + assertThat(resourceTemplate.name()).isNotEmpty(); + assertThat(resourceTemplate.description()).isNotEmpty(); + } + } while (nextCursor != null); + }); + } + protected Duration getInitializationTimeout() { return Duration.ofSeconds(6); } From 17c551ccdd5f1aa27ca3f849da3e7dbc1d1606d9 Mon Sep 17 00:00:00 2001 From: Luca Chang Date: Tue, 20 May 2025 13:51:20 -0700 Subject: [PATCH 2/3] chore: implement integration test for embedded resources --- .../client/StdioMcpSyncClientTests.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java b/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java index a4c77952..5dfec995 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java @@ -5,6 +5,7 @@ package io.modelcontextprotocol.client; import java.time.Duration; +import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -130,6 +131,30 @@ void testListResourceTemplates() { }); } + @Test + void testEmbeddedResources() { + McpClientTransport transport = createMcpTransport(); + + withClient(transport, client -> { + client.initialize(); + + McpSchema.CallToolResult result = client.callTool(new McpSchema.CallToolRequest("getResourceReference", + Map.of( + "resourceId", 1 + ))); + + assertThat(result.content()).hasAtLeastOneElementOfType(McpSchema.EmbeddedResource.class); + assertThat(result.content()).allSatisfy(content -> { + if (!(content instanceof McpSchema.EmbeddedResource resource)) return; + + McpSchema.TextResourceContents text = assertInstanceOf(McpSchema.TextResourceContents.class, resource.resource()); + assertThat(text.mimeType()).isEqualTo("text/plain"); + assertThat(text.uri()).isNotEmpty(); + assertThat(text.text()).isNotEmpty(); + }); + }); + } + protected Duration getInitializationTimeout() { return Duration.ofSeconds(6); } From 2c0f20539078b8e12c345054a00ddf12e2544a3e Mon Sep 17 00:00:00 2001 From: Luca Chang Date: Tue, 20 May 2025 13:52:14 -0700 Subject: [PATCH 3/3] chore: fix test formatting --- .../client/StdioMcpSyncClientTests.java | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java b/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java index 5dfec995..a7745125 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java @@ -88,14 +88,17 @@ void testListReadResources() { if (i % 2 == 0) { assertThat(resourceResult.contents()).allSatisfy(content -> { - McpSchema.TextResourceContents text = assertInstanceOf(McpSchema.TextResourceContents.class, content); + McpSchema.TextResourceContents text = assertInstanceOf(McpSchema.TextResourceContents.class, + content); assertThat(text.mimeType()).isEqualTo("text/plain"); assertThat(text.uri()).isNotEmpty(); assertThat(text.text()).isNotEmpty(); }); - } else { + } + else { assertThat(resourceResult.contents()).allSatisfy(content -> { - McpSchema.BlobResourceContents blob = assertInstanceOf(McpSchema.BlobResourceContents.class, content); + McpSchema.BlobResourceContents blob = assertInstanceOf(McpSchema.BlobResourceContents.class, + content); assertThat(blob.mimeType()).isEqualTo("application/octet-stream"); assertThat(blob.uri()).isNotEmpty(); assertThat(blob.blob()).isNotEmpty(); @@ -104,7 +107,8 @@ void testListReadResources() { i++; } - } while (nextCursor != null); + } + while (nextCursor != null); }); } @@ -121,13 +125,15 @@ void testListResourceTemplates() { nextCursor = result.nextCursor(); for (McpSchema.ResourceTemplate resourceTemplate : result.resourceTemplates()) { - // mimeType is null in @modelcontextprotocol/server-everything, but we don't assert that it's + // mimeType is null in @modelcontextprotocol/server-everything, but we + // don't assert that it's // null in case they change that later. assertThat(resourceTemplate.uriTemplate()).isNotEmpty(); assertThat(resourceTemplate.name()).isNotEmpty(); assertThat(resourceTemplate.description()).isNotEmpty(); } - } while (nextCursor != null); + } + while (nextCursor != null); }); } @@ -138,16 +144,16 @@ void testEmbeddedResources() { withClient(transport, client -> { client.initialize(); - McpSchema.CallToolResult result = client.callTool(new McpSchema.CallToolRequest("getResourceReference", - Map.of( - "resourceId", 1 - ))); + McpSchema.CallToolResult result = client + .callTool(new McpSchema.CallToolRequest("getResourceReference", Map.of("resourceId", 1))); assertThat(result.content()).hasAtLeastOneElementOfType(McpSchema.EmbeddedResource.class); assertThat(result.content()).allSatisfy(content -> { - if (!(content instanceof McpSchema.EmbeddedResource resource)) return; + if (!(content instanceof McpSchema.EmbeddedResource resource)) + return; - McpSchema.TextResourceContents text = assertInstanceOf(McpSchema.TextResourceContents.class, resource.resource()); + McpSchema.TextResourceContents text = assertInstanceOf(McpSchema.TextResourceContents.class, + resource.resource()); assertThat(text.mimeType()).isEqualTo("text/plain"); assertThat(text.uri()).isNotEmpty(); assertThat(text.text()).isNotEmpty();