6565 * .requestTimeout(Duration.ofSeconds(5))
6666 * .build();
6767 * }</pre>
68- *
68+ *
6969 * Example of creating a basic asynchronous client: <pre>{@code
7070 * McpClient.async(transport)
7171 * .requestTimeout(Duration.ofSeconds(5))
114114 */
115115public interface McpClient {
116116
117+ /**
118+ * Start building a synchronous MCP client with the specified transport layer. The
119+ * synchronous MCP client provides blocking operations. Synchronous clients wait for
120+ * each operation to complete before returning, making them simpler to use but
121+ * potentially less performant for concurrent operations. The transport layer handles
122+ * the low-level communication between client and server using protocols like stdio or
123+ * Server-Sent Events (SSE).
124+ * @param transport The transport layer implementation for MCP communication. Common
125+ * implementations include {@code StdioClientTransport} for stdio-based communication
126+ * and {@code SseClientTransport} for SSE-based communication.
127+ * @return A new builder instance for configuring the client
128+ * @throws IllegalArgumentException if transport is null
129+ */
130+ static SyncSpec sync (ClientMcpTransport transport ) {
131+ return new SyncSpec (transport );
132+ }
133+
134+ /**
135+ * Start building an asynchronous MCP client with the specified transport layer. The
136+ * asynchronous MCP client provides non-blocking operations. Asynchronous clients
137+ * return reactive primitives (Mono/Flux) immediately, allowing for concurrent
138+ * operations and reactive programming patterns. The transport layer handles the
139+ * low-level communication between client and server using protocols like stdio or
140+ * Server-Sent Events (SSE).
141+ * @param transport The transport layer implementation for MCP communication. Common
142+ * implementations include {@code StdioClientTransport} for stdio-based communication
143+ * and {@code SseClientTransport} for SSE-based communication.
144+ * @return A new builder instance for configuring the client
145+ * @throws IllegalArgumentException if transport is null
146+ */
147+ static AsyncSpec async (ClientMcpTransport transport ) {
148+ return new AsyncSpec (transport );
149+ }
150+
117151 /**
118152 * Start building an MCP client with the specified transport layer. The transport
119153 * layer handles the low-level communication between client and server using protocols
@@ -371,7 +405,20 @@ public McpAsyncClient async() {
371405 }
372406
373407 /**
374- * Synchronous client specification.
408+ * Synchronous client specification. This class follows the builder pattern to provide
409+ * a fluent API for setting up clients with custom configurations.
410+ *
411+ * <p>
412+ * The builder supports configuration of:
413+ * <ul>
414+ * <li>Transport layer for client-server communication
415+ * <li>Request timeouts for operation boundaries
416+ * <li>Client capabilities for feature negotiation
417+ * <li>Client implementation details for version tracking
418+ * <li>Root URIs for resource access
419+ * <li>Change notification handlers for tools, resources, and prompts
420+ * <li>Custom message sampling logic
421+ * </ul>
375422 */
376423 class SyncSpec {
377424
@@ -381,21 +428,22 @@ class SyncSpec {
381428
382429 private ClientCapabilities capabilities ;
383430
384- private Implementation clientInfo = new Implementation ("Spring AI MCP Client" , "0.3.1 " );
431+ private Implementation clientInfo = new Implementation ("Spring AI MCP Client" , "1.0.0 " );
385432
386- private Map <String , Root > roots = new HashMap <>();
433+ private final Map <String , Root > roots = new HashMap <>();
387434
388- private List <Consumer <List <McpSchema .Tool >>> toolsChangeConsumers = new ArrayList <>();
435+ private final List <Consumer <List <McpSchema .Tool >>> toolsChangeConsumers = new ArrayList <>();
389436
390- private List <Consumer <List <McpSchema .Resource >>> resourcesChangeConsumers = new ArrayList <>();
437+ private final List <Consumer <List <McpSchema .Resource >>> resourcesChangeConsumers = new ArrayList <>();
391438
392- private List <Consumer <List <McpSchema .Prompt >>> promptsChangeConsumers = new ArrayList <>();
439+ private final List <Consumer <List <McpSchema .Prompt >>> promptsChangeConsumers = new ArrayList <>();
393440
394- private List <Consumer <McpSchema .LoggingMessageNotification >> loggingConsumers = new ArrayList <>();
441+ private final List <Consumer <McpSchema .LoggingMessageNotification >> loggingConsumers = new ArrayList <>();
395442
396443 private Function <CreateMessageRequest , CreateMessageResult > samplingHandler ;
397444
398445 private SyncSpec (ClientMcpTransport transport ) {
446+ Assert .notNull (transport , "Transport must not be null" );
399447 this .transport = transport ;
400448 }
401449
@@ -581,7 +629,20 @@ public McpSyncClient build() {
581629 }
582630
583631 /**
584- * Asynchronous client specification.
632+ * Asynchronous client specification. This class follows the builder pattern to
633+ * provide a fluent API for setting up clients with custom configurations.
634+ *
635+ * <p>
636+ * The builder supports configuration of:
637+ * <ul>
638+ * <li>Transport layer for client-server communication
639+ * <li>Request timeouts for operation boundaries
640+ * <li>Client capabilities for feature negotiation
641+ * <li>Client implementation details for version tracking
642+ * <li>Root URIs for resource access
643+ * <li>Change notification handlers for tools, resources, and prompts
644+ * <li>Custom message sampling logic
645+ * </ul>
585646 */
586647 class AsyncSpec {
587648
@@ -593,19 +654,20 @@ class AsyncSpec {
593654
594655 private Implementation clientInfo = new Implementation ("Spring AI MCP Client" , "0.3.1" );
595656
596- private Map <String , Root > roots = new HashMap <>();
657+ private final Map <String , Root > roots = new HashMap <>();
597658
598- private List <Function <List <McpSchema .Tool >, Mono <Void >>> toolsChangeConsumers = new ArrayList <>();
659+ private final List <Function <List <McpSchema .Tool >, Mono <Void >>> toolsChangeConsumers = new ArrayList <>();
599660
600- private List <Function <List <McpSchema .Resource >, Mono <Void >>> resourcesChangeConsumers = new ArrayList <>();
661+ private final List <Function <List <McpSchema .Resource >, Mono <Void >>> resourcesChangeConsumers = new ArrayList <>();
601662
602- private List <Function <List <McpSchema .Prompt >, Mono <Void >>> promptsChangeConsumers = new ArrayList <>();
663+ private final List <Function <List <McpSchema .Prompt >, Mono <Void >>> promptsChangeConsumers = new ArrayList <>();
603664
604- private List <Function <McpSchema .LoggingMessageNotification , Mono <Void >>> loggingConsumers = new ArrayList <>();
665+ private final List <Function <McpSchema .LoggingMessageNotification , Mono <Void >>> loggingConsumers = new ArrayList <>();
605666
606667 private Function <CreateMessageRequest , Mono <CreateMessageResult >> samplingHandler ;
607668
608669 private AsyncSpec (ClientMcpTransport transport ) {
670+ Assert .notNull (transport , "Transport must not be null" );
609671 this .transport = transport ;
610672 }
611673
@@ -789,12 +851,4 @@ public McpAsyncClient build() {
789851
790852 }
791853
792- static SyncSpec sync (ClientMcpTransport transport ) {
793- return new SyncSpec (transport );
794- }
795-
796- static AsyncSpec async (ClientMcpTransport transport ) {
797- return new AsyncSpec (transport );
798- }
799-
800854}
0 commit comments