diff --git a/mcp-test/src/main/java/io/modelcontextprotocol/AbstractMcpClientServerIntegrationTests.java b/mcp-test/src/main/java/io/modelcontextprotocol/AbstractMcpClientServerIntegrationTests.java index 9698691..80a711d 100644 --- a/mcp-test/src/main/java/io/modelcontextprotocol/AbstractMcpClientServerIntegrationTests.java +++ b/mcp-test/src/main/java/io/modelcontextprotocol/AbstractMcpClientServerIntegrationTests.java @@ -12,7 +12,6 @@ import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -52,9 +51,7 @@ import io.modelcontextprotocol.spec.McpSchema.TextContent; import io.modelcontextprotocol.spec.McpSchema.Tool; import io.modelcontextprotocol.util.Utils; import net.javacrumbs.jsonunit.core.Option; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import org.junit.jupiter.params.provider.ValueSource; +import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; import static io.modelcontextprotocol.util.ToolsUtils.EMPTY_JSON_SCHEMA; @@ -72,26 +69,20 @@ import static org.mockito.Mockito.mock; public abstract class AbstractMcpClientServerIntegrationTests { - protected ConcurrentHashMap clientBuilders = new ConcurrentHashMap<>(); - - abstract protected void prepareClients(int port, String mcpEndpoint); - abstract protected McpServer.AsyncSpecification prepareAsyncServerBuilder(); abstract protected McpServer.SyncSpecification prepareSyncServerBuilder(); - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void simple(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); + abstract protected McpClient.SyncSpec getMcpClientBuilder(); + @Test + void simple() { var server = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") .requestTimeout(Duration.ofSeconds(1000)) .build(); try ( // Create client without sampling capabilities - var client = clientBuilder + var client = getMcpClientBuilder() .clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build()) .requestTimeout(Duration.ofSeconds(1000)) .build()) { @@ -107,12 +98,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { // --------------------------------------- // Sampling Tests // --------------------------------------- - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateMessageWithoutSamplingCapabilities(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateMessageWithoutSamplingCapabilities() { McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder() .tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build()) .callHandler((exchange, request) -> { @@ -125,7 +112,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { try ( // Create client without sampling capabilities - var client = clientBuilder + var client = getMcpClientBuilder() .clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build()) .build()) { @@ -144,12 +131,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateMessageSuccess(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateMessageSuccess() { Function samplingHandler = request -> { assertThat(request.messages()).hasSize(1); assertThat(request.messages().get(0).content()).isInstanceOf(McpSchema.TextContent.class); @@ -190,7 +173,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build(); - try (var mcpClient = clientBuilder + try (var mcpClient = getMcpClientBuilder() .clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build()) .capabilities(ClientCapabilities.builder().sampling().build()) .sampling(samplingHandler) @@ -219,14 +202,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateMessageWithRequestTimeoutSuccess(String clientType) throws InterruptedException { - - // Client - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateMessageWithRequestTimeoutSuccess() { Function samplingHandler = request -> { assertThat(request.messages()).hasSize(1); assertThat(request.messages().get(0).content()).isInstanceOf(McpSchema.TextContent.class); @@ -276,7 +253,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .requestTimeout(Duration.ofSeconds(4)) .tools(tool) .build(); - try (var mcpClient = clientBuilder + try (var mcpClient = getMcpClientBuilder() .clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build()) .capabilities(ClientCapabilities.builder().sampling().build()) .sampling(samplingHandler) @@ -305,12 +282,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateMessageWithRequestTimeoutFail(String clientType) throws InterruptedException { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateMessageWithRequestTimeoutFail() { Function samplingHandler = request -> { assertThat(request.messages()).hasSize(1); assertThat(request.messages().get(0).content()).isInstanceOf(McpSchema.TextContent.class); @@ -355,7 +328,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool) .build(); - try (var mcpClient = clientBuilder + try (var mcpClient = getMcpClientBuilder() .clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build()) .capabilities(ClientCapabilities.builder().sampling().build()) .sampling(samplingHandler) @@ -376,12 +349,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { // --------------------------------------- // Elicitation Tests // --------------------------------------- - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateElicitationWithoutElicitationCapabilities(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateElicitationWithoutElicitationCapabilities() { McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder() .tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build()) .callHandler((exchange, request) -> exchange.createElicitation(mock(McpSchema.ElicitFormRequest.class)) @@ -391,7 +360,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { var server = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build(); // Create client without elicitation capabilities - try (var client = clientBuilder.clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build()) + try (var client = getMcpClientBuilder() + .clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build()) .build()) { assertThat(client.initialize()).isNotNull(); @@ -409,12 +379,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateElicitationSuccess(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateElicitationSuccess() { Function formElicitationHandler = request -> { assertThat(request.message()).isNotEmpty(); assertThat(request.requestedSchema()).isNotNull(); @@ -447,7 +413,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build(); - try (var mcpClient = clientBuilder + try (var mcpClient = getMcpClientBuilder() .clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build()) .capabilities(ClientCapabilities.builder().elicitation().build()) .elicitation(formElicitationHandler) @@ -472,12 +438,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateElicitationWithApplyDefaults(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateElicitationWithApplyDefaults() { // Client handler returns empty content — SDK should apply defaults Function elicitationHandler = request -> { assertThat(request.message()).isNotEmpty(); @@ -511,7 +473,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build(); - try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0")) + try (var mcpClient = getMcpClientBuilder().clientInfo(new McpSchema.Implementation("Sample client", "0.0.0")) .capabilities(ClientCapabilities.builder().elicitation(true, false).build()) .elicitation(elicitationHandler) .applyElicitationDefaults(true) @@ -537,12 +499,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateElicitationWithApplyDefaultsAndUnmodifiableMap(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateElicitationWithApplyDefaultsAndUnmodifiableMap() { // Client handler returns an unmodifiable map (Map.of()) — SDK must copy into a // mutable map before applying defaults. Function elicitationHandler = request -> new McpSchema.ElicitResult( @@ -573,7 +531,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build(); - try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0")) + try (var mcpClient = getMcpClientBuilder().clientInfo(new McpSchema.Implementation("Sample client", "0.0.0")) .capabilities(ClientCapabilities.builder().elicitation(true, false).build()) .elicitation(elicitationHandler) .applyElicitationDefaults(true) @@ -597,12 +555,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateElicitationApplyDefaultsDisabledLeavesContentUntouched(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateElicitationApplyDefaultsDisabledLeavesContentUntouched() { Function elicitationHandler = request -> new McpSchema.ElicitResult( McpSchema.ElicitResult.Action.ACCEPT, new HashMap<>()); @@ -629,7 +583,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build(); // applyElicitationDefaults intentionally NOT called — default false. - try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0")) + try (var mcpClient = getMcpClientBuilder().clientInfo(new McpSchema.Implementation("Sample client", "0.0.0")) .capabilities(ClientCapabilities.builder().elicitation(true, false).build()) .elicitation(elicitationHandler) .build()) { @@ -651,12 +605,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateElicitationApplyDefaultsSkippedOnDecline(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateElicitationApplyDefaultsSkippedOnDecline() { Function elicitationHandler = request -> new McpSchema.ElicitResult( McpSchema.ElicitResult.Action.DECLINE, new HashMap<>()); @@ -682,7 +632,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build(); - try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0")) + try (var mcpClient = getMcpClientBuilder().clientInfo(new McpSchema.Implementation("Sample client", "0.0.0")) .capabilities(ClientCapabilities.builder().elicitation(true, false).build()) .elicitation(elicitationHandler) .applyElicitationDefaults(true) @@ -705,12 +655,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateElicitationApplyDefaultsPreservesMeta(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateElicitationApplyDefaultsPreservesMeta() { Map meta = Map.of("trace-id", "abc-123"); Function elicitationHandler = request -> new McpSchema.ElicitResult( McpSchema.ElicitResult.Action.ACCEPT, new HashMap<>(), meta); @@ -737,7 +683,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build(); - try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0")) + try (var mcpClient = getMcpClientBuilder().clientInfo(new McpSchema.Implementation("Sample client", "0.0.0")) .capabilities(ClientCapabilities.builder().elicitation(true, false).build()) .elicitation(elicitationHandler) .applyElicitationDefaults(true) @@ -761,12 +707,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateElicitationWithRequestTimeoutSuccess(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCreateElicitationWithRequestTimeoutSuccess() { Function elicitationHandler = request -> { assertThat(request.message()).isNotEmpty(); assertThat(((McpSchema.ElicitFormRequest) request).requestedSchema()).isNotNull(); @@ -801,7 +743,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool) .build(); - try (var mcpClient = clientBuilder + try (var mcpClient = getMcpClientBuilder() .clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build()) .capabilities(ClientCapabilities.builder().elicitation().build()) .elicitation(elicitationHandler) @@ -826,14 +768,10 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateElicitationWithRequestTimeoutFail(String clientType) { - + @Test + void testCreateElicitationWithRequestTimeoutFail() { var latch = new CountDownLatch(1); - var clientBuilder = clientBuilders.get(clientType); - Function elicitationHandler = request -> { assertThat(request.message()).isNotEmpty(); assertThat(request.requestedSchema()).isNotNull(); @@ -877,7 +815,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool) .build(); - try (var mcpClient = clientBuilder + try (var mcpClient = getMcpClientBuilder() .clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build()) .capabilities(ClientCapabilities.builder().elicitation().build()) .elicitation(elicitationHandler) @@ -898,15 +836,12 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testCreateUrlElicitationSuccess(String clientType) { + @Test + void testCreateUrlElicitationSuccess() { var elicitationRequest = McpSchema.ElicitUrlRequest .builder("Test message", "https://example.com/auth", "elicitation-123") .build(); - var clientBuilder = clientBuilders.get(clientType); - Function urlElicitationHandler = request -> { assertThat(request.message()).isEqualTo("Test message"); assertThat(request.url()).isEqualTo("https://example.com/auth"); @@ -930,7 +865,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build(); - try (var mcpClient = clientBuilder + try (var mcpClient = getMcpClientBuilder() .clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build()) .capabilities(ClientCapabilities.builder().elicitation(false, true).build()) .urlElicitation(urlElicitationHandler) @@ -950,12 +885,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testElicitationCompleteNotification(String clientType) throws InterruptedException { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testElicitationCompleteNotification() throws InterruptedException { CountDownLatch notificationLatch = new CountDownLatch(1); AtomicReference notificationRef = new AtomicReference<>(); AtomicReference sessionId = new AtomicReference<>(); @@ -980,7 +911,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build(); - try (var mcpClient = clientBuilder + try (var mcpClient = getMcpClientBuilder() .clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build()) .elicitationCompleteConsumer(elicitationCompleteConsumer) // enable elicitation so that we can register an elicitation complete consumer @@ -1006,12 +937,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testElicitationRequiredError(String clientType) throws InterruptedException { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testElicitationRequiredError() { // Capture the session ID so we can trigger an "elicitation complete" notification McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder() .tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build()) @@ -1027,7 +954,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { Function elicitationHandler = request -> ElicitResult .builder(ElicitResult.Action.ACCEPT) .build(); - try (var mcpClient = clientBuilder + try (var mcpClient = getMcpClientBuilder() .clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build()) .urlElicitation(elicitationHandler) .build()) { @@ -1060,11 +987,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { // --------------------------------------- // Roots Tests // --------------------------------------- - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testRootsSuccess(String clientType) { - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testRootsSuccess() { List roots = List.of(Root.builder("uri1://").name("root1").build(), Root.builder("uri2://").name("root2").build()); @@ -1074,7 +998,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .rootsChangeHandler((exchange, rootsUpdate) -> rootsRef.set(rootsUpdate)) .build(); - try (var mcpClient = clientBuilder.capabilities(ClientCapabilities.builder().roots(true).build()) + try (var mcpClient = getMcpClientBuilder().capabilities(ClientCapabilities.builder().roots(true).build()) .roots(roots) .build()) { @@ -1109,12 +1033,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testRootsWithoutCapability(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testRootsWithoutCapability() { McpServerFeatures.SyncToolSpecification tool = McpServerFeatures.SyncToolSpecification.builder() .tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build()) .callHandler((exchange, request) -> { @@ -1131,7 +1051,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { try ( // Create client without roots capability // No roots capability - var mcpClient = clientBuilder.capabilities(ClientCapabilities.builder().build()).build()) { + var mcpClient = getMcpClientBuilder().capabilities(ClientCapabilities.builder().build()).build()) { assertThat(mcpClient.initialize()).isNotNull(); @@ -1148,19 +1068,15 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testRootsNotificationWithEmptyRootsList(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testRootsNotificationWithEmptyRootsList() { AtomicReference> rootsRef = new AtomicReference<>(); var mcpServer = prepareSyncServerBuilder() .rootsChangeHandler((exchange, rootsUpdate) -> rootsRef.set(rootsUpdate)) .build(); - try (var mcpClient = clientBuilder.capabilities(ClientCapabilities.builder().roots(true).build()) + try (var mcpClient = getMcpClientBuilder().capabilities(ClientCapabilities.builder().roots(true).build()) .roots(List.of()) // Empty roots list .build()) { @@ -1178,12 +1094,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testRootsWithMultipleHandlers(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testRootsWithMultipleHandlers() { List roots = List.of(Root.builder("uri1://").name("root1").build()); AtomicReference> rootsRef1 = new AtomicReference<>(); @@ -1194,7 +1106,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .rootsChangeHandler((exchange, rootsUpdate) -> rootsRef2.set(rootsUpdate)) .build(); - try (var mcpClient = clientBuilder.capabilities(ClientCapabilities.builder().roots(true).build()) + try (var mcpClient = getMcpClientBuilder().capabilities(ClientCapabilities.builder().roots(true).build()) .roots(roots) .build()) { @@ -1212,12 +1124,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testRootsServerCloseWithActiveSubscription(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testRootsServerCloseWithActiveSubscription() { List roots = List.of(Root.builder("uri1://").name("root1").build()); AtomicReference> rootsRef = new AtomicReference<>(); @@ -1226,7 +1134,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .rootsChangeHandler((exchange, rootsUpdate) -> rootsRef.set(rootsUpdate)) .build(); - try (var mcpClient = clientBuilder.capabilities(ClientCapabilities.builder().roots(true).build()) + try (var mcpClient = getMcpClientBuilder().capabilities(ClientCapabilities.builder().roots(true).build()) .roots(roots) .build()) { @@ -1247,12 +1155,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { // --------------------------------------- // Tools Tests // --------------------------------------- - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testToolCallSuccess(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testToolCallSuccess() { var responseBodyIsNullOrBlank = new AtomicBoolean(false); var callResponse = McpSchema.CallToolResult.builder() .addContent(McpSchema.TextContent.builder("CALL RESPONSE; ctx=importantValue").build()) @@ -1283,7 +1187,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool1) .build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { InitializeResult initResult = mcpClient.initialize(); assertThat(initResult).isNotNull(); @@ -1301,12 +1205,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testThrowingToolCallIsCaughtBeforeTimeout(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testThrowingToolCallIsCaughtBeforeTimeout() { McpSyncServer mcpServer = prepareSyncServerBuilder() .capabilities(ServerCapabilities.builder().tools(true).build()) .tools(McpServerFeatures.SyncToolSpecification.builder() @@ -1319,7 +1219,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .build()) .build(); - try (var mcpClient = clientBuilder.requestTimeout(Duration.ofMillis(6666)).build()) { + try (var mcpClient = getMcpClientBuilder().requestTimeout(Duration.ofMillis(6666)).build()) { InitializeResult initResult = mcpClient.initialize(); assertThat(initResult).isNotNull(); @@ -1334,12 +1234,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testToolCallSuccessWithTranportContextExtraction(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testToolCallSuccessWithTranportContextExtraction() { var transportContextIsNull = new AtomicBoolean(false); var transportContextIsEmpty = new AtomicBoolean(false); var responseBodyIsNullOrBlank = new AtomicBoolean(false); @@ -1374,7 +1270,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool1) .build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { InitializeResult initResult = mcpClient.initialize(); assertThat(initResult).isNotNull(); @@ -1394,11 +1290,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testToolWithNonAsciiCharacters(String clientType) { - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testToolWithNonAsciiCharacters() { String inputSchema = """ { "type": "object", @@ -1423,7 +1316,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(nonAsciiTool) .build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { InitializeResult initResult = mcpClient.initialize(); assertThat(initResult).isNotNull(); @@ -1446,12 +1339,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testToolListChangeHandlingSuccess(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testToolListChangeHandlingSuccess() { var callResponse = McpSchema.CallToolResult.builder() .addContent(McpSchema.TextContent.builder("CALL RESPONSE").build()) .build(); @@ -1483,7 +1372,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool1) .build(); - try (var mcpClient = clientBuilder.toolsChangeConsumer(toolsUpdate -> { + try (var mcpClient = getMcpClientBuilder().toolsChangeConsumer(toolsUpdate -> { // perform a blocking call to a remote service try { HttpResponse response = HttpClient.newHttpClient() @@ -1538,15 +1427,11 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testInitialize(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testInitialize() { var mcpServer = prepareSyncServerBuilder().build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { InitializeResult initResult = mcpClient.initialize(); assertThat(initResult).isNotNull(); @@ -1559,16 +1444,13 @@ public abstract class AbstractMcpClientServerIntegrationTests { // --------------------------------------- // Logging Tests // --------------------------------------- - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testLoggingNotification(String clientType) throws InterruptedException { + @Test + void testLoggingNotification() throws InterruptedException { int expectedNotificationsCount = 3; CountDownLatch latch = new CountDownLatch(expectedNotificationsCount); // Create a list to store received logging notifications List receivedNotifications = new CopyOnWriteArrayList<>(); - var clientBuilder = clientBuilders.get(clientType); - // Create server with a tool that sends logging notifications McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder() .tool(Tool.builder("logging-test", EMPTY_JSON_SCHEMA).description("Test logging notifications").build()) @@ -1617,7 +1499,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { try ( // Create client with logging notification handler - var mcpClient = clientBuilder.loggingConsumer(notification -> { + var mcpClient = getMcpClientBuilder().loggingConsumer(notification -> { receivedNotifications.add(notification); latch.countDown(); }).build()) { @@ -1667,17 +1549,14 @@ public abstract class AbstractMcpClientServerIntegrationTests { // --------------------------------------- // Progress Tests // --------------------------------------- - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testProgressNotification(String clientType) throws InterruptedException { + @Test + void testProgressNotification() throws InterruptedException { int expectedNotificationsCount = 4; // 3 notifications + 1 for another progress // token CountDownLatch latch = new CountDownLatch(expectedNotificationsCount); // Create a list to store received logging notifications List receivedNotifications = new CopyOnWriteArrayList<>(); - var clientBuilder = clientBuilders.get(clientType); - // Create server with a tool that sends logging notifications McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder() .tool(McpSchema.Tool.builder("progress-test", EMPTY_JSON_SCHEMA) @@ -1720,7 +1599,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { try ( // Create client with progress notification handler - var mcpClient = clientBuilder.progressConsumer(notification -> { + var mcpClient = getMcpClientBuilder().progressConsumer(notification -> { receivedNotifications.add(notification); latch.countDown(); }).build()) { @@ -1781,11 +1660,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { // --------------------------------------- // Completion Tests // --------------------------------------- - @ParameterizedTest(name = "{0} : Completion call") - @MethodSource("clientsForTesting") - void testCompletionShouldReturnExpectedSuggestions(String clientType) { - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testCompletionShouldReturnExpectedSuggestions() { var expectedValues = List.of("python", "pytorch", "pyside"); var completionResponse = new McpSchema.CompleteResult( new CompleteResult.CompleteCompletion(expectedValues, 10, true)); @@ -1811,7 +1687,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { McpSchema.PromptReference.builder("code_review").title("Code review").build(), completionHandler)) .build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { InitializeResult initResult = mcpClient.initialize(); assertThat(initResult).isNotNull(); @@ -1837,12 +1713,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { // --------------------------------------- // Ping Tests // --------------------------------------- - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testPingSuccess(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testPingSuccess() { // Create server with a tool that uses ping functionality AtomicReference executionOrder = new AtomicReference<>(""); @@ -1876,7 +1748,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool) .build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { // Initialize client InitializeResult initResult = mcpClient.initialize(); @@ -1900,11 +1772,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { // --------------------------------------- // Tool Structured Output Schema Tests // --------------------------------------- - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testStructuredOutputValidationSuccess(String clientType) { - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testStructuredOutputValidationSuccess() { // Create a tool with output schema Map outputSchema = Map.of( "type", "object", "properties", Map.of("result", Map.of("type", "number"), "operation", @@ -1933,7 +1802,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool) .build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { InitializeResult initResult = mcpClient.initialize(); assertThat(initResult).isNotNull(); @@ -1973,11 +1842,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @ValueSource(strings = { "httpclient" }) - void testStructuredOutputOfObjectArrayValidationSuccess(String clientType) { - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testStructuredOutputOfObjectArrayValidationSuccess() { // Create a tool with output schema that returns an array of objects Map outputSchema = Map .of( // @formatter:off @@ -2008,7 +1874,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool) .build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { assertThat(mcpClient.initialize()).isNotNull(); // Call tool with valid structured output of type array @@ -2032,11 +1898,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @ValueSource(strings = { "httpclient" }) - void testStructuredOutputWithInHandlerError(String clientType) { - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testStructuredOutputWithInHandlerError() { // Create a tool with output schema Map outputSchema = Map.of( "type", "object", "properties", Map.of("result", Map.of("type", "number"), "operation", @@ -2062,7 +1925,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool) .build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { InitializeResult initResult = mcpClient.initialize(); assertThat(initResult).isNotNull(); @@ -2088,12 +1951,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @ValueSource(strings = { "httpclient" }) - void testStructuredOutputValidationFailure(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testStructuredOutputValidationFailure() { // Create a tool with output schema Map outputSchema = Map.of("type", "object", "properties", Map.of("result", Map.of("type", "number"), "operation", Map.of("type", "string")), "required", @@ -2121,7 +1980,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool) .build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { InitializeResult initResult = mcpClient.initialize(); assertThat(initResult).isNotNull(); @@ -2142,12 +2001,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testStructuredOutputMissingStructuredContent(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testStructuredOutputMissingStructuredContent() { // Create a tool with output schema Map outputSchema = Map.of("type", "object", "properties", Map.of("result", Map.of("type", "number")), "required", List.of("result")); @@ -2170,7 +2025,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .tools(tool) .build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { InitializeResult initResult = mcpClient.initialize(); assertThat(initResult).isNotNull(); @@ -2192,18 +2047,14 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testStructuredOutputRuntimeToolAddition(String clientType) { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testStructuredOutputRuntimeToolAddition() { // Start server without tools var mcpServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0") .capabilities(ServerCapabilities.builder().tools(true).build()) .build(); - try (var mcpClient = clientBuilder.build()) { + try (var mcpClient = getMcpClientBuilder().build()) { InitializeResult initResult = mcpClient.initialize(); assertThat(initResult).isNotNull(); @@ -2273,12 +2124,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { // Resource Subscription Tests // --------------------------------------- - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testResourceSubscription(String clientType) throws InterruptedException { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testResourceSubscription() throws InterruptedException { String resourceUri = "test://subscribable-resource"; var receivedContents = new AtomicReference>(); var latch = new CountDownLatch(1); @@ -2296,7 +2143,7 @@ public abstract class AbstractMcpClientServerIntegrationTests { .resources(resourceSpec) .build(); - try (var mcpClient = clientBuilder.resourcesUpdateConsumer(contents -> { + try (var mcpClient = getMcpClientBuilder().resourcesUpdateConsumer(contents -> { receivedContents.set(contents); latch.countDown(); }).build()) { @@ -2317,12 +2164,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { } } - @ParameterizedTest(name = "{0} : {displayName} ") - @MethodSource("clientsForTesting") - void testResourceSubscription_afterUnsubscribe_noNotification(String clientType) throws InterruptedException { - - var clientBuilder = clientBuilders.get(clientType); - + @Test + void testResourceSubscription_afterUnsubscribe_noNotification() { String resourceUri = "test://subscribable-resource-unsub"; var notificationCount = new java.util.concurrent.atomic.AtomicInteger(0); @@ -2337,7 +2180,8 @@ public abstract class AbstractMcpClientServerIntegrationTests { .resources(resourceSpec) .build(); - try (var mcpClient = clientBuilder.resourcesUpdateConsumer(contents -> notificationCount.incrementAndGet()) + try (var mcpClient = getMcpClientBuilder() + .resourcesUpdateConsumer(contents -> notificationCount.incrementAndGet()) .build()) { mcpClient.initialize(); diff --git a/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletSseIntegrationTests.java b/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletSseIntegrationTests.java index 5841c13..5b861ed 100644 --- a/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletSseIntegrationTests.java +++ b/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletSseIntegrationTests.java @@ -61,12 +61,6 @@ class HttpServletSseIntegrationTests extends AbstractMcpClientServerIntegrationT catch (Exception e) { throw new RuntimeException("Failed to start Tomcat", e); } - - clientBuilders - .put("httpclient", - McpClient.sync(HttpClientSseClientTransport.builder("http://localhost:" + PORT) - .sseEndpoint(CUSTOM_SSE_ENDPOINT) - .build()).requestTimeout(Duration.ofHours(10))); } @Override @@ -79,6 +73,15 @@ class HttpServletSseIntegrationTests extends AbstractMcpClientServerIntegrationT return McpServer.sync(this.mcpServerTransportProvider); } + @Override + protected McpClient.SyncSpec getMcpClientBuilder() { + return McpClient + .sync(HttpClientSseClientTransport.builder("http://localhost:" + PORT) + .sseEndpoint(CUSTOM_SSE_ENDPOINT) + .build()) + .requestTimeout(Duration.ofHours(10)); + } + @AfterEach public void after() { if (mcpServerTransportProvider != null) { @@ -95,10 +98,6 @@ class HttpServletSseIntegrationTests extends AbstractMcpClientServerIntegrationT } } - @Override - protected void prepareClients(int port, String mcpEndpoint) { - } - static McpTransportContextExtractor TEST_CONTEXT_EXTRACTOR = (r) -> McpTransportContext .create(Map.of("important", "value")); diff --git a/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStreamableIntegrationTests.java b/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStreamableIntegrationTests.java index 5b934e4..83779d2 100644 --- a/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStreamableIntegrationTests.java +++ b/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStreamableIntegrationTests.java @@ -59,12 +59,6 @@ class HttpServletStreamableIntegrationTests extends AbstractMcpClientServerInteg catch (Exception e) { throw new RuntimeException("Failed to start Tomcat", e); } - - clientBuilders - .put("httpclient", - McpClient.sync(HttpClientStreamableHttpTransport.builder("http://localhost:" + PORT) - .endpoint(MESSAGE_ENDPOINT) - .build()).requestTimeout(Duration.ofHours(10))); } @Override @@ -77,6 +71,15 @@ class HttpServletStreamableIntegrationTests extends AbstractMcpClientServerInteg return McpServer.sync(this.mcpServerTransportProvider); } + @Override + protected McpClient.SyncSpec getMcpClientBuilder() { + return McpClient + .sync(HttpClientStreamableHttpTransport.builder("http://localhost:" + PORT) + .endpoint(MESSAGE_ENDPOINT) + .build()) + .requestTimeout(Duration.ofHours(10)); + } + @AfterEach public void after() { if (mcpServerTransportProvider != null) { @@ -93,10 +96,6 @@ class HttpServletStreamableIntegrationTests extends AbstractMcpClientServerInteg } } - @Override - protected void prepareClients(int port, String mcpEndpoint) { - } - static McpTransportContextExtractor TEST_CONTEXT_EXTRACTOR = (r) -> McpTransportContext .create(Map.of("important", "value"));