|
12 | 12 | import io.modelcontextprotocol.client.transport.ServerParameters; |
13 | 13 | import io.modelcontextprotocol.client.transport.StdioClientTransport; |
14 | 14 | import io.modelcontextprotocol.spec.McpClientTransport; |
| 15 | +import io.modelcontextprotocol.spec.McpSchema; |
15 | 16 | import org.junit.jupiter.api.Test; |
16 | 17 | import org.junit.jupiter.api.Timeout; |
17 | 18 | import reactor.core.publisher.Sinks; |
18 | 19 | import reactor.test.StepVerifier; |
19 | 20 |
|
20 | 21 | import static org.assertj.core.api.Assertions.assertThat; |
| 22 | +import static org.junit.jupiter.api.Assertions.assertInstanceOf; |
21 | 23 |
|
22 | 24 | /** |
23 | 25 | * Tests for the {@link McpSyncClient} with {@link StdioClientTransport}. |
@@ -67,6 +69,67 @@ void customErrorHandlerShouldReceiveErrors() throws InterruptedException { |
67 | 69 | StepVerifier.create(transport.closeGracefully()).expectComplete().verify(Duration.ofSeconds(5)); |
68 | 70 | } |
69 | 71 |
|
| 72 | + @Test |
| 73 | + void testListReadResources() { |
| 74 | + McpClientTransport transport = createMcpTransport(); |
| 75 | + |
| 76 | + withClient(transport, client -> { |
| 77 | + client.initialize(); |
| 78 | + |
| 79 | + int i = 0; |
| 80 | + String nextCursor = null; |
| 81 | + do { |
| 82 | + McpSchema.ListResourcesResult result = client.listResources(nextCursor); |
| 83 | + nextCursor = result.nextCursor(); |
| 84 | + |
| 85 | + for (McpSchema.Resource resource : result.resources()) { |
| 86 | + McpSchema.ReadResourceResult resourceResult = client.readResource(resource); |
| 87 | + |
| 88 | + if (i % 2 == 0) { |
| 89 | + assertThat(resourceResult.contents()).allSatisfy(content -> { |
| 90 | + McpSchema.TextResourceContents text = assertInstanceOf(McpSchema.TextResourceContents.class, content); |
| 91 | + assertThat(text.mimeType()).isEqualTo("text/plain"); |
| 92 | + assertThat(text.uri()).isNotEmpty(); |
| 93 | + assertThat(text.text()).isNotEmpty(); |
| 94 | + }); |
| 95 | + } else { |
| 96 | + assertThat(resourceResult.contents()).allSatisfy(content -> { |
| 97 | + McpSchema.BlobResourceContents blob = assertInstanceOf(McpSchema.BlobResourceContents.class, content); |
| 98 | + assertThat(blob.mimeType()).isEqualTo("application/octet-stream"); |
| 99 | + assertThat(blob.uri()).isNotEmpty(); |
| 100 | + assertThat(blob.blob()).isNotEmpty(); |
| 101 | + }); |
| 102 | + } |
| 103 | + |
| 104 | + i++; |
| 105 | + } |
| 106 | + } while (nextCursor != null); |
| 107 | + }); |
| 108 | + } |
| 109 | + |
| 110 | + @Test |
| 111 | + void testListResourceTemplates() { |
| 112 | + McpClientTransport transport = createMcpTransport(); |
| 113 | + |
| 114 | + withClient(transport, client -> { |
| 115 | + client.initialize(); |
| 116 | + |
| 117 | + String nextCursor = null; |
| 118 | + do { |
| 119 | + McpSchema.ListResourceTemplatesResult result = client.listResourceTemplates(nextCursor); |
| 120 | + nextCursor = result.nextCursor(); |
| 121 | + |
| 122 | + for (McpSchema.ResourceTemplate resourceTemplate : result.resourceTemplates()) { |
| 123 | + // mimeType is null in @modelcontextprotocol/server-everything, but we don't assert that it's |
| 124 | + // null in case they change that later. |
| 125 | + assertThat(resourceTemplate.uriTemplate()).isNotEmpty(); |
| 126 | + assertThat(resourceTemplate.name()).isNotEmpty(); |
| 127 | + assertThat(resourceTemplate.description()).isNotEmpty(); |
| 128 | + } |
| 129 | + } while (nextCursor != null); |
| 130 | + }); |
| 131 | + } |
| 132 | + |
70 | 133 | protected Duration getInitializationTimeout() { |
71 | 134 | return Duration.ofSeconds(6); |
72 | 135 | } |
|
0 commit comments