diff --git a/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/McpClientAutoConfiguration.java b/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/McpClientAutoConfiguration.java
index b89b70b66be..7b6da8eb2db 100644
--- a/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/McpClientAutoConfiguration.java
+++ b/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/McpClientAutoConfiguration.java
@@ -1,334 +1,341 @@
-/*
- * Copyright 2025-2025 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.ai.autoconfigure.mcp.client;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import io.modelcontextprotocol.client.McpAsyncClient;
-import io.modelcontextprotocol.client.McpClient;
-import io.modelcontextprotocol.client.McpSyncClient;
-import io.modelcontextprotocol.spec.McpSchema;
-
-import org.springframework.ai.autoconfigure.mcp.client.configurer.McpAsyncClientConfigurer;
-import org.springframework.ai.autoconfigure.mcp.client.configurer.McpSyncClientConfigurer;
-import org.springframework.ai.autoconfigure.mcp.client.properties.McpClientCommonProperties;
-import org.springframework.ai.mcp.AsyncMcpToolCallbackProvider;
-import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
-import org.springframework.ai.mcp.customizer.McpAsyncClientCustomizer;
-import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;
-import org.springframework.ai.tool.ToolCallback;
-import org.springframework.ai.tool.ToolCallbackProvider;
-import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.util.CollectionUtils;
-
-/**
- * Auto-configuration for Model Context Protocol (MCP) client support.
- *
- *
- * This configuration class sets up the necessary beans for MCP client functionality,
- * including both synchronous and asynchronous clients along with their respective tool
- * callbacks. It is automatically enabled when the required classes are present on the
- * classpath and can be explicitly disabled through properties.
- *
- *
- * Configuration Properties:
- *
- * - {@code spring.ai.mcp.client.enabled} - Enable/disable MCP client support (default:
- * true)
- *
- {@code spring.ai.mcp.client.type} - Client type: SYNC or ASYNC (default: SYNC)
- *
- {@code spring.ai.mcp.client.name} - Client implementation name
- *
- {@code spring.ai.mcp.client.version} - Client implementation version
- *
- {@code spring.ai.mcp.client.request-timeout} - Request timeout duration
- *
- {@code spring.ai.mcp.client.initialized} - Whether to initialize clients on
- * creation
- *
- *
- *
- * The configuration is activated after the transport-specific auto-configurations (Stdio,
- * SSE HTTP, and SSE WebFlux) to ensure proper initialization order. At least one
- * transport must be available for the clients to be created.
- *
- *
- * Key features:
- *
- * - Synchronous and Asynchronous Client Support:
- *
- * - Creates and configures MCP clients based on available transports
- *
- Supports both blocking (sync) and non-blocking (async) operations
- *
- Automatic client initialization if enabled
- *
- * - Integration Support:
- *
- * - Sets up tool callbacks for Spring AI integration
- *
- Supports multiple named transports
- *
- Proper lifecycle management with automatic cleanup
- *
- * - Customization Options:
- *
- * - Extensible through {@link McpSyncClientCustomizer} and
- * {@link McpAsyncClientCustomizer}
- *
- Configurable timeouts and client information
- *
- Support for custom transport implementations
- *
- *
- *
- * @see McpSyncClient
- * @see McpAsyncClient
- * @see McpClientCommonProperties
- * @see McpSyncClientCustomizer
- * @see McpAsyncClientCustomizer
- * @see StdioTransportAutoConfiguration
- * @see SseHttpClientTransportAutoConfiguration
- * @see SseWebFluxTransportAutoConfiguration
- */
-@AutoConfiguration(after = { StdioTransportAutoConfiguration.class, SseHttpClientTransportAutoConfiguration.class,
- SseWebFluxTransportAutoConfiguration.class })
-@ConditionalOnClass({ McpSchema.class })
-@EnableConfigurationProperties(McpClientCommonProperties.class)
-@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true",
- matchIfMissing = true)
-public class McpClientAutoConfiguration {
-
- /**
- * Create a dynamic client name based on the client name and the name of the server
- * connection.
- * @param clientName the client name as defined by the configuration
- * @param serverConnectionName the name of the server connection being used by the
- * client
- * @return the connected client name
- */
- private String connectedClientName(String clientName, String serverConnectionName) {
- return clientName + " - " + serverConnectionName;
- }
-
- /**
- * Creates a list of {@link McpSyncClient} instances based on the available
- * transports.
- *
- *
- * Each client is configured with:
- *
- * - Client information (name and version) from common properties
- *
- Request timeout settings
- *
- Custom configurations through {@link McpSyncClientConfigurer}
- *
- *
- *
- * If initialization is enabled in properties, the clients are automatically
- * initialized.
- * @param mcpSyncClientConfigurer the configurer for customizing client creation
- * @param commonProperties common MCP client properties
- * @param transportsProvider provider of named MCP transports
- * @return list of configured MCP sync clients
- */
- @Bean
- @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
- matchIfMissing = true)
- public List mcpSyncClients(McpSyncClientConfigurer mcpSyncClientConfigurer,
- McpClientCommonProperties commonProperties,
- ObjectProvider> transportsProvider) {
-
- List mcpSyncClients = new ArrayList<>();
-
- List namedTransports = transportsProvider.stream().flatMap(List::stream).toList();
-
- if (!CollectionUtils.isEmpty(namedTransports)) {
- for (NamedClientMcpTransport namedTransport : namedTransports) {
-
- McpSchema.Implementation clientInfo = new McpSchema.Implementation(
- this.connectedClientName(commonProperties.getName(), namedTransport.name()),
- commonProperties.getVersion());
-
- McpClient.SyncSpec syncSpec = McpClient.sync(namedTransport.transport())
- .clientInfo(clientInfo)
- .requestTimeout(commonProperties.getRequestTimeout());
-
- syncSpec = mcpSyncClientConfigurer.configure(namedTransport.name(), syncSpec);
-
- var syncClient = syncSpec.build();
-
- if (commonProperties.isInitialized()) {
- syncClient.initialize();
- }
-
- mcpSyncClients.add(syncClient);
- }
- }
-
- return mcpSyncClients;
- }
-
- /**
- * Creates tool callbacks for all configured MCP clients.
- *
- *
- * These callbacks enable integration with Spring AI's tool execution framework,
- * allowing MCP tools to be used as part of AI interactions.
- * @param mcpClientsProvider provider of MCP sync clients
- * @return list of tool callbacks for MCP integration
- */
- @Bean
- @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
- matchIfMissing = true)
- public ToolCallbackProvider toolCallbacks(ObjectProvider> mcpClientsProvider) {
- List mcpClients = mcpClientsProvider.stream().flatMap(List::stream).toList();
- return new SyncMcpToolCallbackProvider(mcpClients);
- }
-
- /**
- * @deprecated replaced by {@link #toolCallbacks(ObjectProvider)} that returns a
- * {@link ToolCallbackProvider} instead of a list of {@link ToolCallback}
- */
- @Deprecated
- @Bean
- @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
- matchIfMissing = true)
- public List toolCallbacksDeprecated(ObjectProvider> mcpClientsProvider) {
- List mcpClients = mcpClientsProvider.stream().flatMap(List::stream).toList();
- return List.of(new SyncMcpToolCallbackProvider(mcpClients).getToolCallbacks());
- }
-
- /**
- * Record class that implements {@link AutoCloseable} to ensure proper cleanup of MCP
- * clients.
- *
- *
- * This class is responsible for closing all MCP sync clients when the application
- * context is closed, preventing resource leaks.
- */
- public record CloseableMcpSyncClients(List clients) implements AutoCloseable {
-
- @Override
- public void close() {
- this.clients.forEach(McpSyncClient::close);
- }
- }
-
- /**
- * Creates a closeable wrapper for MCP sync clients to ensure proper resource cleanup.
- * @param clients the list of MCP sync clients to manage
- * @return a closeable wrapper for the clients
- */
- @Bean
- @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
- matchIfMissing = true)
- public CloseableMcpSyncClients makeSyncClientsClosable(List clients) {
- return new CloseableMcpSyncClients(clients);
- }
-
- /**
- * Creates the default {@link McpSyncClientConfigurer} if none is provided.
- *
- *
- * This configurer aggregates all available {@link McpSyncClientCustomizer} instances
- * to allow for customization of MCP sync client creation.
- * @param customizerProvider provider of MCP sync client customizers
- * @return the configured MCP sync client configurer
- */
- @Bean
- @ConditionalOnMissingBean
- @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
- matchIfMissing = true)
- McpSyncClientConfigurer mcpSyncClientConfigurer(ObjectProvider customizerProvider) {
- return new McpSyncClientConfigurer(customizerProvider.orderedStream().toList());
- }
-
- // Async client configuration
-
- @Bean
- @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
- public List mcpAsyncClients(McpAsyncClientConfigurer mcpSyncClientConfigurer,
- McpClientCommonProperties commonProperties,
- ObjectProvider> transportsProvider) {
-
- List mcpSyncClients = new ArrayList<>();
-
- List namedTransports = transportsProvider.stream().flatMap(List::stream).toList();
-
- if (!CollectionUtils.isEmpty(namedTransports)) {
- for (NamedClientMcpTransport namedTransport : namedTransports) {
-
- McpSchema.Implementation clientInfo = new McpSchema.Implementation(
- this.connectedClientName(commonProperties.getName(), namedTransport.name()),
- commonProperties.getVersion());
-
- McpClient.AsyncSpec syncSpec = McpClient.async(namedTransport.transport())
- .clientInfo(clientInfo)
- .requestTimeout(commonProperties.getRequestTimeout());
-
- syncSpec = mcpSyncClientConfigurer.configure(namedTransport.name(), syncSpec);
-
- var syncClient = syncSpec.build();
-
- if (commonProperties.isInitialized()) {
- syncClient.initialize().block();
- }
-
- mcpSyncClients.add(syncClient);
- }
- }
-
- return mcpSyncClients;
- }
-
- /**
- * @deprecated replaced by {@link #asyncToolCallbacks(ObjectProvider)} that returns a
- * {@link ToolCallbackProvider} instead of a list of {@link ToolCallback}
- */
- @Deprecated
- @Bean
- @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
- public List asyncToolCallbacksDeprecated(ObjectProvider> mcpClientsProvider) {
- List mcpClients = mcpClientsProvider.stream().flatMap(List::stream).toList();
- return List.of(new AsyncMcpToolCallbackProvider(mcpClients).getToolCallbacks());
- }
-
- @Bean
- @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
- public ToolCallbackProvider asyncToolCallbacks(ObjectProvider> mcpClientsProvider) {
- List mcpClients = mcpClientsProvider.stream().flatMap(List::stream).toList();
- return new AsyncMcpToolCallbackProvider(mcpClients);
- }
-
- public record CloseableMcpAsyncClients(List clients) implements AutoCloseable {
- @Override
- public void close() {
- this.clients.forEach(McpAsyncClient::close);
- }
- }
-
- @Bean
- @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
- public CloseableMcpAsyncClients makeAsynClientsClosable(List clients) {
- return new CloseableMcpAsyncClients(clients);
- }
-
- @Bean
- @ConditionalOnMissingBean
- @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
- McpAsyncClientConfigurer mcpAsyncClientConfigurer(ObjectProvider customizerProvider) {
- return new McpAsyncClientConfigurer(customizerProvider.orderedStream().toList());
- }
-
-}
+/*
+ * Copyright 2025-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.ai.autoconfigure.mcp.client;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.modelcontextprotocol.client.McpAsyncClient;
+import io.modelcontextprotocol.client.McpClient;
+import io.modelcontextprotocol.client.McpSyncClient;
+import io.modelcontextprotocol.spec.McpSchema;
+
+import org.springframework.ai.autoconfigure.mcp.client.configurer.McpAsyncClientConfigurer;
+import org.springframework.ai.autoconfigure.mcp.client.configurer.McpSyncClientConfigurer;
+import org.springframework.ai.autoconfigure.mcp.client.properties.McpClientCommonProperties;
+import org.springframework.ai.mcp.AsyncMcpToolCallbackProvider;
+import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
+import org.springframework.ai.mcp.customizer.McpAsyncClientCustomizer;
+import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;
+import org.springframework.ai.tool.ToolCallback;
+import org.springframework.ai.tool.ToolCallbackProvider;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * Auto-configuration for Model Context Protocol (MCP) client support.
+ *
+ *
+ * This configuration class sets up the necessary beans for MCP client functionality,
+ * including both synchronous and asynchronous clients along with their respective tool
+ * callbacks. It is automatically enabled when the required classes are present on the
+ * classpath and can be explicitly disabled through properties.
+ *
+ *
+ * Configuration Properties:
+ *
+ * - {@code spring.ai.mcp.client.enabled} - Enable/disable MCP client support (default:
+ * true)
+ *
- {@code spring.ai.mcp.client.type} - Client type: SYNC or ASYNC (default: SYNC)
+ *
- {@code spring.ai.mcp.client.name} - Client implementation name
+ *
- {@code spring.ai.mcp.client.version} - Client implementation version
+ *
- {@code spring.ai.mcp.client.request-timeout} - Request timeout duration
+ *
- {@code spring.ai.mcp.client.initialized} - Whether to initialize clients on
+ * creation
+ *
+ *
+ *
+ * The configuration is activated after the transport-specific auto-configurations (Stdio,
+ * SSE HTTP, and SSE WebFlux) to ensure proper initialization order. At least one
+ * transport must be available for the clients to be created.
+ *
+ *
+ * Key features:
+ *
+ * - Synchronous and Asynchronous Client Support:
+ *
+ * - Creates and configures MCP clients based on available transports
+ *
- Supports both blocking (sync) and non-blocking (async) operations
+ *
- Automatic client initialization if enabled
+ *
+ * - Integration Support:
+ *
+ * - Sets up tool callbacks for Spring AI integration
+ *
- Supports multiple named transports
+ *
- Proper lifecycle management with automatic cleanup
+ *
+ * - Customization Options:
+ *
+ * - Extensible through {@link McpSyncClientCustomizer} and
+ * {@link McpAsyncClientCustomizer}
+ *
- Configurable timeouts and client information
+ *
- Support for custom transport implementations
+ *
+ *
+ *
+ * @see McpSyncClient
+ * @see McpAsyncClient
+ * @see McpClientCommonProperties
+ * @see McpSyncClientCustomizer
+ * @see McpAsyncClientCustomizer
+ * @see StdioTransportAutoConfiguration
+ * @see SseHttpClientTransportAutoConfiguration
+ * @see SseWebFluxTransportAutoConfiguration
+ */
+@AutoConfiguration(after = {
+ StdioTransportAutoConfiguration.class,
+ SseWebFluxTransportAutoConfiguration.class, // WebFlux
+ SseHttpClientTransportAutoConfiguration.class // HTTP Client
+})
+@ConditionalOnClass({ McpSchema.class })
+@EnableConfigurationProperties(McpClientCommonProperties.class)
+@ConditionalOnProperty(
+ prefix = McpClientCommonProperties.CONFIG_PREFIX,
+ name = "enabled",
+ havingValue = "true",
+ matchIfMissing = true
+)
+public class McpClientAutoConfiguration {
+
+ /**
+ * Create a dynamic client name based on the client name and the name of the server
+ * connection.
+ * @param clientName the client name as defined by the configuration
+ * @param serverConnectionName the name of the server connection being used by the
+ * client
+ * @return the connected client name
+ */
+ private String connectedClientName(String clientName, String serverConnectionName) {
+ return clientName + " - " + serverConnectionName;
+ }
+
+ /**
+ * Creates a list of {@link McpSyncClient} instances based on the available
+ * transports.
+ *
+ *
+ * Each client is configured with:
+ *
+ * - Client information (name and version) from common properties
+ *
- Request timeout settings
+ *
- Custom configurations through {@link McpSyncClientConfigurer}
+ *
+ *
+ *
+ * If initialization is enabled in properties, the clients are automatically
+ * initialized.
+ * @param mcpSyncClientConfigurer the configurer for customizing client creation
+ * @param commonProperties common MCP client properties
+ * @param transportsProvider provider of named MCP transports
+ * @return list of configured MCP sync clients
+ */
+ @Bean
+ @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
+ matchIfMissing = true)
+ public List mcpSyncClients(McpSyncClientConfigurer mcpSyncClientConfigurer,
+ McpClientCommonProperties commonProperties,
+ ObjectProvider> transportsProvider) {
+
+ List mcpSyncClients = new ArrayList<>();
+
+ List namedTransports = transportsProvider.stream().flatMap(List::stream).toList();
+
+ if (!CollectionUtils.isEmpty(namedTransports)) {
+ for (NamedClientMcpTransport namedTransport : namedTransports) {
+
+ McpSchema.Implementation clientInfo = new McpSchema.Implementation(
+ this.connectedClientName(commonProperties.getName(), namedTransport.name()),
+ commonProperties.getVersion());
+
+ McpClient.SyncSpec syncSpec = McpClient.sync(namedTransport.transport())
+ .clientInfo(clientInfo)
+ .requestTimeout(commonProperties.getRequestTimeout());
+
+ syncSpec = mcpSyncClientConfigurer.configure(namedTransport.name(), syncSpec);
+
+ var syncClient = syncSpec.build();
+
+ if (commonProperties.isInitialized()) {
+ syncClient.initialize();
+ }
+
+ mcpSyncClients.add(syncClient);
+ }
+ }
+
+ return mcpSyncClients;
+ }
+
+ /**
+ * Creates tool callbacks for all configured MCP clients.
+ *
+ *
+ * These callbacks enable integration with Spring AI's tool execution framework,
+ * allowing MCP tools to be used as part of AI interactions.
+ * @param mcpClientsProvider provider of MCP sync clients
+ * @return list of tool callbacks for MCP integration
+ */
+ @Bean
+ @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
+ matchIfMissing = true)
+ public ToolCallbackProvider toolCallbacks(ObjectProvider> mcpClientsProvider) {
+ List mcpClients = mcpClientsProvider.stream().flatMap(List::stream).toList();
+ return new SyncMcpToolCallbackProvider(mcpClients);
+ }
+
+ /**
+ * @deprecated replaced by {@link #toolCallbacks(ObjectProvider)} that returns a
+ * {@link ToolCallbackProvider} instead of a list of {@link ToolCallback}
+ */
+ @Deprecated
+ @Bean
+ @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
+ matchIfMissing = true)
+ public List toolCallbacksDeprecated(ObjectProvider> mcpClientsProvider) {
+ List mcpClients = mcpClientsProvider.stream().flatMap(List::stream).toList();
+ return List.of(new SyncMcpToolCallbackProvider(mcpClients).getToolCallbacks());
+ }
+
+ /**
+ * Record class that implements {@link AutoCloseable} to ensure proper cleanup of MCP
+ * clients.
+ *
+ *
+ * This class is responsible for closing all MCP sync clients when the application
+ * context is closed, preventing resource leaks.
+ */
+ public record CloseableMcpSyncClients(List clients) implements AutoCloseable {
+
+ @Override
+ public void close() {
+ this.clients.forEach(McpSyncClient::close);
+ }
+ }
+
+ /**
+ * Creates a closeable wrapper for MCP sync clients to ensure proper resource cleanup.
+ * @param clients the list of MCP sync clients to manage
+ * @return a closeable wrapper for the clients
+ */
+ @Bean
+ @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
+ matchIfMissing = true)
+ public CloseableMcpSyncClients makeSyncClientsClosable(List clients) {
+ return new CloseableMcpSyncClients(clients);
+ }
+
+ /**
+ * Creates the default {@link McpSyncClientConfigurer} if none is provided.
+ *
+ *
+ * This configurer aggregates all available {@link McpSyncClientCustomizer} instances
+ * to allow for customization of MCP sync client creation.
+ * @param customizerProvider provider of MCP sync client customizers
+ * @return the configured MCP sync client configurer
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
+ matchIfMissing = true)
+ McpSyncClientConfigurer mcpSyncClientConfigurer(ObjectProvider customizerProvider) {
+ return new McpSyncClientConfigurer(customizerProvider.orderedStream().toList());
+ }
+
+ // Async client configuration
+
+ @Bean
+ @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
+ public List mcpAsyncClients(McpAsyncClientConfigurer mcpSyncClientConfigurer,
+ McpClientCommonProperties commonProperties,
+ ObjectProvider> transportsProvider) {
+
+ List mcpSyncClients = new ArrayList<>();
+
+ List namedTransports = transportsProvider.stream().flatMap(List::stream).toList();
+
+ if (!CollectionUtils.isEmpty(namedTransports)) {
+ for (NamedClientMcpTransport namedTransport : namedTransports) {
+
+ McpSchema.Implementation clientInfo = new McpSchema.Implementation(
+ this.connectedClientName(commonProperties.getName(), namedTransport.name()),
+ commonProperties.getVersion());
+
+ McpClient.AsyncSpec syncSpec = McpClient.async(namedTransport.transport())
+ .clientInfo(clientInfo)
+ .requestTimeout(commonProperties.getRequestTimeout());
+
+ syncSpec = mcpSyncClientConfigurer.configure(namedTransport.name(), syncSpec);
+
+ var syncClient = syncSpec.build();
+
+ if (commonProperties.isInitialized()) {
+ syncClient.initialize().block();
+ }
+
+ mcpSyncClients.add(syncClient);
+ }
+ }
+
+ return mcpSyncClients;
+ }
+
+ /**
+ * @deprecated replaced by {@link #asyncToolCallbacks(ObjectProvider)} that returns a
+ * {@link ToolCallbackProvider} instead of a list of {@link ToolCallback}
+ */
+ @Deprecated
+ @Bean
+ @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
+ public List asyncToolCallbacksDeprecated(ObjectProvider> mcpClientsProvider) {
+ List mcpClients = mcpClientsProvider.stream().flatMap(List::stream).toList();
+ return List.of(new AsyncMcpToolCallbackProvider(mcpClients).getToolCallbacks());
+ }
+
+ @Bean
+ @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
+ public ToolCallbackProvider asyncToolCallbacks(ObjectProvider> mcpClientsProvider) {
+ List mcpClients = mcpClientsProvider.stream().flatMap(List::stream).toList();
+ return new AsyncMcpToolCallbackProvider(mcpClients);
+ }
+
+ public record CloseableMcpAsyncClients(List clients) implements AutoCloseable {
+ @Override
+ public void close() {
+ this.clients.forEach(McpAsyncClient::close);
+ }
+ }
+
+ @Bean
+ @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
+ public CloseableMcpAsyncClients makeAsynClientsClosable(List clients) {
+ return new CloseableMcpAsyncClients(clients);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
+ McpAsyncClientConfigurer mcpAsyncClientConfigurer(ObjectProvider customizerProvider) {
+ return new McpAsyncClientConfigurer(customizerProvider.orderedStream().toList());
+ }
+
+}
diff --git a/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/SseHttpClientTransportAutoConfiguration.java b/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/SseHttpClientTransportAutoConfiguration.java
index 0fe02a9dc20..ffea6aa5f6c 100644
--- a/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/SseHttpClientTransportAutoConfiguration.java
+++ b/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/SseHttpClientTransportAutoConfiguration.java
@@ -16,28 +16,26 @@
package org.springframework.ai.autoconfigure.mcp.client;
-import java.net.http.HttpClient;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
-
import org.springframework.ai.autoconfigure.mcp.client.properties.McpClientCommonProperties;
import org.springframework.ai.autoconfigure.mcp.client.properties.McpSseClientProperties;
import org.springframework.ai.autoconfigure.mcp.client.properties.McpSseClientProperties.SseParameters;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
+import java.net.http.HttpClient;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
/**
* Auto-configuration for Server-Sent Events (SSE) HTTP client transport in the Model
* Context Protocol (MCP).
@@ -59,6 +57,10 @@
* Supports multiple named server connections with different URLs
*
*
+ * @author Christian Tzolov
+ * @author qjc
+ * @description Added SSE transport mode configuration to control HTTP Client implementation
+ * @Email qjc1024@aliyun.com
* @see HttpClientSseClientTransport
* @see McpSseClientProperties
*/
@@ -66,8 +68,11 @@
@ConditionalOnClass({ McpSchema.class, McpSyncClient.class })
@ConditionalOnMissingClass("io.modelcontextprotocol.client.transport.WebFluxSseClientTransport")
@EnableConfigurationProperties({ McpSseClientProperties.class, McpClientCommonProperties.class })
-@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true",
- matchIfMissing = true)
+@ConditionalOnProperty(
+ prefix = McpSseClientProperties.CONFIG_PREFIX,
+ name = "transport-mode",
+ havingValue = "HTTP_CLIENT"
+)
public class SseHttpClientTransportAutoConfiguration {
/**
diff --git a/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/SseWebFluxTransportAutoConfiguration.java b/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/SseWebFluxTransportAutoConfiguration.java
index 8c6496fc72e..8afa9eb443d 100644
--- a/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/SseWebFluxTransportAutoConfiguration.java
+++ b/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/SseWebFluxTransportAutoConfiguration.java
@@ -16,13 +16,8 @@
package org.springframework.ai.autoconfigure.mcp.client;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
-
import org.springframework.ai.autoconfigure.mcp.client.properties.McpClientCommonProperties;
import org.springframework.ai.autoconfigure.mcp.client.properties.McpSseClientProperties;
import org.springframework.ai.autoconfigure.mcp.client.properties.McpSseClientProperties.SseParameters;
@@ -34,6 +29,10 @@
import org.springframework.context.annotation.Bean;
import org.springframework.web.reactive.function.client.WebClient;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
/**
* Auto-configuration for WebFlux-based Server-Sent Events (SSE) client transport in the
* Model Context Protocol (MCP).
@@ -52,14 +51,22 @@
* Supports multiple named server connections with different base URLs
*
*
+ * @author Christian Tzolov
+ * @author qjc
+ * @description Added SSE transport mode configuration to control WebFlux vs HTTP Client implementation
+ * @Email qjc1024@aliyun.com
* @see WebFluxSseClientTransport
* @see McpSseClientProperties
*/
@AutoConfiguration
@ConditionalOnClass(WebFluxSseClientTransport.class)
@EnableConfigurationProperties({ McpSseClientProperties.class, McpClientCommonProperties.class })
-@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true",
- matchIfMissing = true)
+@ConditionalOnProperty(
+ prefix = McpSseClientProperties.CONFIG_PREFIX,
+ name = "transport-mode",
+ havingValue = "WEBFLUX",
+ matchIfMissing = true // 默认使用 WebFlux
+)
public class SseWebFluxTransportAutoConfiguration {
/**
diff --git a/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/properties/McpSseClientProperties.java b/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/properties/McpSseClientProperties.java
index ed5575a1422..511868564da 100644
--- a/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/properties/McpSseClientProperties.java
+++ b/auto-configurations/spring-ai-mcp-client/src/main/java/org/springframework/ai/autoconfigure/mcp/client/properties/McpSseClientProperties.java
@@ -15,11 +15,11 @@
*/
package org.springframework.ai.autoconfigure.mcp.client.properties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
import java.util.HashMap;
import java.util.Map;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
/**
* Configuration properties for Server-Sent Events (SSE) based MCP client connections.
*
@@ -38,6 +38,7 @@
*
*
* @author Christian Tzolov
+ * @author qjc
* @since 1.0.0
* @see SseParameters
*/
@@ -62,6 +63,30 @@ public record SseParameters(String url) {
*/
private final Map connections = new HashMap<>();
+ /**
+ * The transport mode for SSE connections. Defaults to WEBFLUX.
+ */
+ private SseTransportMode transportMode = SseTransportMode.WEBFLUX;
+
+ /**
+ * SSE transport mode for MCP client.
+ *
+ * @author qjc
+ * @description Controls which transport implementation to use for SSE connections
+ * @Email qjc1024@aliyun.com
+ */
+ public enum SseTransportMode {
+ /**
+ * Use WebFlux for SSE transport (default).
+ */
+ WEBFLUX,
+
+ /**
+ * Use HTTP Client for SSE transport.
+ */
+ HTTP_CLIENT
+ }
+
/**
* Returns the map of configured SSE connections.
* @return map of connection names to their SSE parameters
@@ -70,4 +95,12 @@ public Map getConnections() {
return this.connections;
}
+ public SseTransportMode getTransportMode() {
+ return transportMode;
+ }
+
+ public void setTransportMode(SseTransportMode transportMode) {
+ this.transportMode = transportMode;
+ }
+
}
diff --git a/auto-configurations/spring-ai-mcp-client/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/auto-configurations/spring-ai-mcp-client/src/main/resources/META-INF/additional-spring-configuration-metadata.json
new file mode 100644
index 00000000000..e77f5d7dc07
--- /dev/null
+++ b/auto-configurations/spring-ai-mcp-client/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -0,0 +1,26 @@
+{
+ "properties": [
+ {
+ "name": "spring.ai.mcp.client.sse.transport-mode",
+ "type": "org.springframework.ai.autoconfigure.mcp.client.properties.McpSseClientProperties$SseTransportMode",
+ "description": "The transport mode for SSE connections. Can be either 'WEBFLUX' (default) or 'HTTP_CLIENT'.",
+ "defaultValue": "WEBFLUX",
+ "sourceType": "org.springframework.ai.autoconfigure.mcp.client.properties.McpSseClientProperties"
+ }
+ ],
+ "hints": [
+ {
+ "name": "spring.ai.mcp.client.sse.transport-mode",
+ "values": [
+ {
+ "value": "WEBFLUX",
+ "description": "Use WebFlux for SSE transport (default). Provides reactive streaming support."
+ },
+ {
+ "value": "HTTP_CLIENT",
+ "description": "Use HTTP Client for SSE transport. Traditional blocking HTTP client implementation."
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file