diff --git a/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java b/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java index 706aa9b2..a7745125 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; @@ -12,12 +13,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 +70,97 @@ 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); + }); + } + + @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); }