Spring Boot starter providing auto-configuration for Model Context Protocol (MCP) client with Spring WebFlux, enabling reactive AI applications to connect to MCP servers via SSE and Streamable HTTP transports
Integration between MCP clients and Spring AI's tool execution framework through automatic tool callback providers.
The MCP Client WebFlux starter automatically converts MCP clients into Spring AI ToolCallbackProviders. This integration enables:
package org.springframework.ai.mcp.client.common.autoconfigure;
/**
* Auto-configuration that converts MCP clients into Spring AI ToolCallbackProviders.
* Runs after McpClientAutoConfiguration to ensure clients are available.
* Creates ToolCallbackProvider beans that integrate MCP tools with Spring AI.
* Thread-safe - tool callbacks can be used concurrently.
*
* Enabled when:
* - spring.ai.mcp.client.enabled=true (default)
* - spring.ai.mcp.client.toolcallback.enabled=true (default)
*/
@org.springframework.boot.autoconfigure.AutoConfiguration(
after = McpClientAutoConfiguration.class
)
@org.springframework.boot.context.properties.EnableConfigurationProperties(
org.springframework.ai.mcp.client.common.autoconfigure.properties.McpClientCommonProperties.class
)
@org.springframework.boot.autoconfigure.condition.ConditionalOnProperty(
prefix = "spring.ai.mcp.client.toolcallback",
name = "enabled",
havingValue = "true",
matchIfMissing = true
)
public class McpToolCallbackAutoConfiguration {
}This auto-configuration is enabled when both:
spring.ai.mcp.client.enabled=true (default)spring.ai.mcp.client.toolcallback.enabled=true (default)package org.springframework.ai.mcp.client.common.autoconfigure;
/**
* Creates a synchronous MCP tool callback provider for Spring AI integration.
* Automatically converts MCP tools into Spring AI ToolCallbacks.
* Listens to McpToolsChangedEvent to refresh tools when servers update.
* Thread-safe with internal caching.
*
* Created only when spring.ai.mcp.client.type=SYNC (default).
*
* @param syncClientsToolFilter Optional tool filter for filtering discovered tools (may be absent)
* @param syncMcpClients Provider of MCP sync clients (must provide at least empty list)
* @param mcpToolNamePrefixGenerator Tool name prefix generator for handling name collisions
* @param toolContextToMcpMetaConverter Converter for Spring AI ToolContext to MCP metadata
* @return Synchronous MCP tool callback provider (never null)
*/
@org.springframework.context.annotation.Bean
@org.springframework.boot.autoconfigure.condition.ConditionalOnProperty(
prefix = "spring.ai.mcp.client",
name = "type",
havingValue = "SYNC",
matchIfMissing = true
)
public org.springframework.ai.mcp.SyncMcpToolCallbackProvider mcpToolCallbacks(
org.springframework.beans.factory.ObjectProvider<org.springframework.ai.mcp.McpToolFilter> syncClientsToolFilter,
org.springframework.beans.factory.ObjectProvider<java.util.List<io.modelcontextprotocol.client.McpSyncClient>> syncMcpClients,
org.springframework.beans.factory.ObjectProvider<org.springframework.ai.mcp.McpToolNamePrefixGenerator> mcpToolNamePrefixGenerator,
org.springframework.beans.factory.ObjectProvider<org.springframework.ai.mcp.ToolContextToMcpMetaConverter> toolContextToMcpMetaConverter
);package org.springframework.ai.mcp.client.common.autoconfigure;
/**
* Creates an asynchronous MCP tool callback provider for Spring AI integration.
* Automatically converts MCP tools into Spring AI ToolCallbacks.
* Uses reactive execution but blocks for Spring AI compatibility.
* Listens to McpToolsChangedEvent to refresh tools when servers update.
* Thread-safe with internal caching.
*
* Created only when spring.ai.mcp.client.type=ASYNC.
*
* @param asyncClientsToolFilter Optional tool filter for filtering discovered tools (may be absent)
* @param mcpClientsProvider Provider of MCP async clients (must provide at least empty list)
* @param toolNamePrefixGenerator Tool name prefix generator for handling name collisions
* @param toolContextToMcpMetaConverter Converter for Spring AI ToolContext to MCP metadata
* @return Asynchronous MCP tool callback provider (never null)
*/
@org.springframework.context.annotation.Bean
@org.springframework.boot.autoconfigure.condition.ConditionalOnProperty(
prefix = "spring.ai.mcp.client",
name = "type",
havingValue = "ASYNC"
)
public org.springframework.ai.mcp.AsyncMcpToolCallbackProvider mcpAsyncToolCallbacks(
org.springframework.beans.factory.ObjectProvider<org.springframework.ai.mcp.McpToolFilter> asyncClientsToolFilter,
org.springframework.beans.factory.ObjectProvider<java.util.List<io.modelcontextprotocol.client.McpAsyncClient>> mcpClientsProvider,
org.springframework.beans.factory.ObjectProvider<org.springframework.ai.mcp.McpToolNamePrefixGenerator> toolNamePrefixGenerator,
org.springframework.beans.factory.ObjectProvider<org.springframework.ai.mcp.ToolContextToMcpMetaConverter> toolContextToMcpMetaConverter
);spring.ai.mcp.client:
toolcallback:
enabled: true # default: trueTo disable tool callback integration while keeping MCP clients active:
spring.ai.mcp.client:
enabled: true
toolcallback:
enabled: falseThe tool callback provider automatically integrates with Spring AI's chat client:
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;
/**
* Service demonstrating Spring AI integration with MCP tools.
* MCP tools are automatically available to the AI.
* No manual tool registration needed.
*/
@Service
public class AiService {
private final ChatClient chatClient;
/**
* Constructor injection of chat client.
* ToolCallbackProvider is automatically registered by Spring AI.
* All MCP tools are available for the AI to use.
*
* @param chatClientBuilder Spring AI chat client builder
*/
public AiService(ChatClient.Builder chatClientBuilder) {
// ToolCallbackProvider is automatically registered
// All MCP tools are available for the AI to use
this.chatClient = chatClientBuilder.build();
}
/**
* Ask question that may use MCP tools.
* AI automatically discovers and uses MCP tools as needed.
*
* @param question User question
* @return AI response (may include tool execution results)
*/
public String askWithTools(String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
}
}With MCP servers providing tools like get_weather and search_database:
// The AI can automatically discover and use MCP tools
String response = aiService.askWithTools(
"What's the weather in San Francisco and find users in the database with that city?"
);
// The AI will:
// 1. Recognize it needs weather data
// 2. Call get_weather tool via MCP (automatically)
// 3. Recognize it needs database query
// 4. Call search_database tool via MCP (automatically)
// 5. Synthesize the results into a natural language responseImplement McpToolFilter to selectively include/exclude tools:
package org.springframework.ai.mcp;
/**
* Filter for selectively including MCP tools.
*
* Functional interface extending BiPredicate for filtering tools
* based on connection information and tool metadata.
* Thread-safe - must not maintain mutable state.
* Applied during tool discovery and when tools change.
*/
@FunctionalInterface
public interface McpToolFilter
extends java.util.function.BiPredicate<McpConnectionInfo, io.modelcontextprotocol.spec.McpSchema.Tool> {
/**
* Tests whether the tool should be included.
* Called for each tool discovered from MCP servers.
* May be called multiple times for the same tool.
*
* @param connectionInfo Information about the MCP connection (never null)
* @param tool The MCP tool to evaluate (never null)
* @return true to include the tool, false to exclude it
*/
boolean test(McpConnectionInfo connectionInfo, io.modelcontextprotocol.spec.McpSchema.Tool tool);
}import org.springframework.ai.mcp.McpToolFilter;
import org.springframework.ai.mcp.McpConnectionInfo;
import io.modelcontextprotocol.spec.McpSchema;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configuration providing custom tool filter.
* Filters tools based on server, tool name, and other criteria.
*/
@Configuration
public class ToolFilterConfig {
/**
* Custom tool filter for security and quality control.
* Excludes dangerous tools, tools from untrusted servers, etc.
* Thread-safe - no mutable state.
*
* @return Tool filter bean
*/
@Bean
public McpToolFilter mcpToolFilter() {
return (McpConnectionInfo connectionInfo, McpSchema.Tool tool) -> {
// Only include tools from specific servers
String serverName = connectionInfo.initializeResult().serverInfo().name();
if (serverName.contains("untrusted")) {
return false; // Exclude all tools from untrusted servers
}
// Exclude dangerous tools (security)
String toolName = tool.name();
if (toolName.startsWith("delete_") || toolName.startsWith("drop_")) {
return false; // Exclude destructive operations
}
// Only include tools with descriptions (quality)
if (tool.description() == null || tool.description().isEmpty()) {
return false; // Exclude poorly documented tools
}
// Exclude tools with complex schemas (optional - for simplicity)
if (isComplexSchema(tool.inputSchema())) {
return false;
}
return true; // Include tool
};
}
private boolean isComplexSchema(Object schema) {
// Logic to detect overly complex schemas
return false; // Placeholder
}
}Filter by server capabilities:
@Bean
public McpToolFilter capabilityBasedFilter() {
return (connectionInfo, tool) -> {
// Only include tools from servers with specific capabilities
var serverCaps = connectionInfo.initializeResult().capabilities();
// Example: Only tools from servers supporting logging
return serverCaps.logging() != null;
};
}Filter by tool parameters:
@Bean
public McpToolFilter parameterBasedFilter() {
return (connectionInfo, tool) -> {
// Examine tool input schema
Object schema = tool.inputSchema();
// Example: Exclude tools with too many parameters
int paramCount = countParameters(schema);
return paramCount <= 5;
};
}Handle tool name collisions across multiple MCP servers:
package org.springframework.ai.mcp;
/**
* Strategy for generating prefixed tool names to avoid collisions.
* Used when multiple MCP servers provide tools with the same name.
* Thread-safe - implementations must not maintain mutable state.
*/
public interface McpToolNamePrefixGenerator {
/**
* Generate a prefixed tool name.
* Called for each tool to create unique name for Spring AI.
* Should be deterministic - same input should produce same output.
*
* @param mcpConnectionInfo Information about the MCP connection (never null)
* @param tool The tool to generate a name for (never null)
* @return The prefixed tool name (never null, must be unique)
*/
String prefixedToolName(McpConnectionInfo mcpConnectionInfo, io.modelcontextprotocol.spec.McpSchema.Tool tool);
/**
* Factory method for a no-prefix strategy.
* Uses tool names as-is - may cause collisions if multiple servers have same tool names.
*
* @return No-prefix generator
*/
static McpToolNamePrefixGenerator noPrefix();
}package org.springframework.ai.mcp;
/**
* Default implementation that ensures unique tool names by appending
* counters for duplicates (e.g., "alt_1_toolName", "alt_2_toolName").
* Thread-safe with internal synchronization.
* Stateful - maintains counter for duplicate detection.
*/
public class DefaultMcpToolNamePrefixGenerator implements McpToolNamePrefixGenerator {
/**
* Generate prefixed tool name.
* First occurrence of a tool name is used as-is.
* Subsequent occurrences get "alt_N_" prefix where N is counter.
*
* @param mcpConnectionInfo Connection info (used for logging)
* @param tool Tool to name
* @return Unique tool name
*/
@Override
public String prefixedToolName(McpConnectionInfo mcpConnectionInfo, io.modelcontextprotocol.spec.McpSchema.Tool tool);
}The default bean created by auto-configuration:
package org.springframework.ai.mcp.client.common.autoconfigure;
/**
* Creates default tool name prefix generator.
* Handles name collisions automatically.
* Can be overridden with custom implementation.
*
* @return Default prefix generator
*/
@org.springframework.context.annotation.Bean
@org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
public McpToolNamePrefixGenerator defaultMcpToolNamePrefixGenerator();import org.springframework.ai.mcp.McpToolNamePrefixGenerator;
import org.springframework.ai.mcp.McpConnectionInfo;
import io.modelcontextprotocol.spec.McpSchema;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configuration providing custom tool naming strategy.
* Prefixes tools with server name for clarity.
*/
@Configuration
public class ToolNamingConfig {
/**
* Custom prefix generator that includes server name.
* Makes tool origin clear in tool names.
* Thread-safe - no mutable state.
*
* @return Custom prefix generator
*/
@Bean
public McpToolNamePrefixGenerator customPrefixGenerator() {
return (McpConnectionInfo connectionInfo, McpSchema.Tool tool) -> {
// Prefix with server name
String serverName = connectionInfo.initializeResult()
.serverInfo()
.name()
.replaceAll("[^a-zA-Z0-9]", "_"); // Sanitize for tool name
return serverName + "_" + tool.name();
};
}
}Convert Spring AI ToolContext to MCP metadata:
package org.springframework.ai.mcp;
/**
* Strategy for converting Spring AI ToolContext to MCP metadata.
* Allows passing Spring AI context to MCP tool executions.
* Thread-safe - implementations must not maintain mutable state.
*/
public interface ToolContextToMcpMetaConverter {
/**
* Convert ToolContext to MCP metadata map.
* Called before each tool execution to extract metadata.
* Returned map is passed to MCP server with tool call.
*
* @param toolContext The Spring AI tool context (never null)
* @return Map of MCP metadata (never null, may be empty)
*/
java.util.Map<String, Object> convert(org.springframework.ai.model.function.ToolContext toolContext);
/**
* Default converter that extracts context data.
* Converts ToolContext.getContext() to MCP metadata.
*
* @return Default converter
*/
static ToolContextToMcpMetaConverter defaultConverter();
/**
* No-op converter that returns an empty map.
* Use when MCP metadata is not needed.
*
* @return No-op converter
*/
static ToolContextToMcpMetaConverter noOp();
}import org.springframework.ai.mcp.ToolContextToMcpMetaConverter;
import org.springframework.ai.model.function.ToolContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
import java.util.HashMap;
/**
* Configuration providing custom metadata converter.
* Extracts specific context fields for MCP tools.
*/
@Configuration
public class MetadataConverterConfig {
/**
* Custom metadata converter for MCP tool executions.
* Extracts relevant context information.
* Thread-safe - no mutable state.
*
* @return Custom metadata converter
*/
@Bean
public ToolContextToMcpMetaConverter customMetadataConverter() {
return (ToolContext toolContext) -> {
Map<String, Object> metadata = new HashMap<>();
// Add timestamp
metadata.put("timestamp", System.currentTimeMillis());
// Extract user context
metadata.put("requestId", toolContext.getContext().get("requestId"));
metadata.put("userId", toolContext.getContext().get("userId"));
metadata.put("sessionId", toolContext.getContext().get("sessionId"));
// Add application context
metadata.put("application", "my-app");
metadata.put("environment", System.getProperty("spring.profiles.active"));
return metadata;
};
}
}Type used by filters and generators:
package org.springframework.ai.mcp;
/**
* Information about an MCP connection.
* Immutable value object containing client and server information.
* Thread-safe.
*
* @param clientCapabilities The client's capabilities advertised to server
* @param clientInfo The client implementation information
* @param initializeResult The server's initialization result including capabilities
*/
public record McpConnectionInfo(
io.modelcontextprotocol.spec.McpSchema.ClientCapabilities clientCapabilities,
io.modelcontextprotocol.spec.McpSchema.Implementation clientInfo,
io.modelcontextprotocol.spec.McpSchema.InitializeResult initializeResult
) {
/**
* Create a builder for McpConnectionInfo.
* Useful for programmatic construction.
*
* @return Builder instance
*/
public static Builder builder();
/**
* Builder for McpConnectionInfo.
* Mutable builder for constructing immutable connection info.
*/
public static class Builder {
/**
* Set client capabilities.
*
* @param capabilities Client capabilities
* @return This builder
*/
public Builder clientCapabilities(io.modelcontextprotocol.spec.McpSchema.ClientCapabilities capabilities);
/**
* Set client info.
*
* @param info Client implementation info
* @return This builder
*/
public Builder clientInfo(io.modelcontextprotocol.spec.McpSchema.Implementation info);
/**
* Set initialization result.
*
* @param result Server initialization result
* @return This builder
*/
public Builder initializeResult(io.modelcontextprotocol.spec.McpSchema.InitializeResult result);
/**
* Build immutable connection info.
*
* @return Connection info instance
* @throws IllegalStateException if required fields not set
*/
public McpConnectionInfo build();
}
}Usage example:
McpToolFilter filter = (McpConnectionInfo info, McpSchema.Tool tool) -> {
// Access server information
String serverName = info.initializeResult().serverInfo().name();
String serverVersion = info.initializeResult().serverInfo().version();
// Access server capabilities
McpSchema.ServerCapabilities serverCaps = info.initializeResult().capabilities();
boolean supportsProgress = serverCaps.logging() != null;
// Access client information
String clientName = info.clientInfo().name();
// Filter based on this information
return !serverName.contains("beta") && supportsProgress;
};package org.springframework.ai.mcp;
/**
* Individual tool callback implementation for synchronous MCP clients.
* Implements Spring AI's ToolCallback interface.
* Thread-safe for concurrent execution.
* Blocking - executes tool synchronously.
*/
public class SyncMcpToolCallback implements org.springframework.ai.model.function.ToolCallback {
/**
* Get the tool definition for this callback.
* Used by Spring AI to understand tool parameters and usage.
*
* @return ToolDefinition for Spring AI (never null)
*/
public org.springframework.ai.model.function.ToolDefinition getToolDefinition();
/**
* Get the original MCP tool name (without any prefix modifications).
* Useful for logging and debugging.
*
* @return Original tool name from MCP server (never null)
*/
public String getOriginalToolName();
/**
* Execute the tool with the given input.
* Blocks until MCP tool execution completes.
* Thread-safe - can be called concurrently.
*
* @param toolCallInput JSON string with tool arguments (never null)
* @return Tool execution result as JSON string (never null)
* @throws RuntimeException if tool execution fails
*/
public String call(String toolCallInput);
/**
* Execute the tool with the given input and context.
* Converts context to MCP metadata and passes to tool.
* Blocks until MCP tool execution completes.
* Thread-safe - can be called concurrently.
*
* @param toolCallInput JSON string with tool arguments (never null)
* @param toolContext Spring AI tool context (never null)
* @return Tool execution result as JSON string (never null)
* @throws RuntimeException if tool execution fails
*/
public String call(String toolCallInput, org.springframework.ai.model.function.ToolContext toolContext);
/**
* Builder for creating SyncMcpToolCallback instances.
* Not typically used directly - created by ToolCallbackProvider.
*
* @return Builder instance
*/
public static Builder builder();
/**
* Builder for SyncMcpToolCallback.
*/
public static class Builder {
public Builder mcpClient(io.modelcontextprotocol.client.McpSyncClient client);
public Builder tool(io.modelcontextprotocol.spec.McpSchema.Tool tool);
public Builder prefixedToolName(String prefixedName);
public Builder toolContextToMcpMetaConverter(ToolContextToMcpMetaConverter converter);
public SyncMcpToolCallback build();
}
}package org.springframework.ai.mcp;
/**
* Individual tool callback implementation for asynchronous MCP clients.
* Implements Spring AI's ToolCallback interface.
* Thread-safe for concurrent execution.
* Uses reactive execution but blocks for Spring AI compatibility.
*/
public class AsyncMcpToolCallback implements org.springframework.ai.model.function.ToolCallback {
/**
* Get the tool definition for this callback.
* Used by Spring AI to understand tool parameters and usage.
*
* @return ToolDefinition for Spring AI (never null)
*/
public org.springframework.ai.model.function.ToolDefinition getToolDefinition();
/**
* Get the original MCP tool name (without any prefix modifications).
* Useful for logging and debugging.
*
* @return Original tool name from MCP server (never null)
*/
public String getOriginalToolName();
/**
* Execute the tool with the given input (blocks on async operation).
* Uses reactive MCP client but blocks for Spring AI compatibility.
* Thread-safe - can be called concurrently.
*
* @param toolCallInput JSON string with tool arguments (never null)
* @return Tool execution result as JSON string (never null)
* @throws RuntimeException if tool execution fails
*/
public String call(String toolCallInput);
/**
* Execute the tool with the given input and context (blocks on async operation).
* Converts context to MCP metadata and passes to tool.
* Uses reactive MCP client but blocks for Spring AI compatibility.
* Thread-safe - can be called concurrently.
*
* @param toolCallInput JSON string with tool arguments (never null)
* @param toolContext Spring AI tool context (never null)
* @return Tool execution result as JSON string (never null)
* @throws RuntimeException if tool execution fails
*/
public String call(String toolCallInput, org.springframework.ai.model.function.ToolContext toolContext);
/**
* Builder for creating AsyncMcpToolCallback instances.
* Not typically used directly - created by ToolCallbackProvider.
*
* @return Builder instance
*/
public static Builder builder();
/**
* Builder for AsyncMcpToolCallback.
*/
public static class Builder {
public Builder mcpClient(io.modelcontextprotocol.client.McpAsyncClient client);
public Builder tool(io.modelcontextprotocol.spec.McpSchema.Tool tool);
public Builder prefixedToolName(String prefixedName);
public Builder toolContextToMcpMetaConverter(ToolContextToMcpMetaConverter converter);
public AsyncMcpToolCallback build();
}
}package org.springframework.ai.mcp;
/**
* Synchronous tool callback provider for MCP.
* Implements Spring AI's ToolCallbackProvider interface and ApplicationListener for tool changes.
* Thread-safe with internal caching.
* Caches tool list for performance - invalidated on tool change events.
*/
public class SyncMcpToolCallbackProvider
implements org.springframework.ai.model.function.ToolCallbackProvider,
org.springframework.context.ApplicationListener<McpToolsChangedEvent> {
/**
* Get all tool callbacks from the provider.
* Returns cached list of tool callbacks.
* Thread-safe - returns defensive copy.
*
* @return Array of tool callbacks (never null, may be empty)
*/
public org.springframework.ai.model.function.ToolCallback[] getToolCallbacks();
/**
* Invalidate the tool cache, forcing a refresh from MCP clients.
* Called automatically when McpToolsChangedEvent is received.
* Can be called manually to force refresh.
* Thread-safe - synchronized internally.
*/
public void invalidateCache();
/**
* Handle tool list changed events.
* Automatically invalidates cache when tools change.
* Thread-safe - synchronized with cache access.
*
* @param event The tools changed event (never null)
*/
public void onApplicationEvent(McpToolsChangedEvent event);
/**
* Static helper method to create tool callbacks from sync clients.
* Not typically called directly - used by auto-configuration.
*
* @param mcpClients List of sync MCP clients
* @return List of tool callbacks
*/
public static java.util.List<org.springframework.ai.model.function.ToolCallback> syncToolCallbacks(
java.util.List<io.modelcontextprotocol.client.McpSyncClient> mcpClients
);
/**
* Builder for creating SyncMcpToolCallbackProvider instances.
* Not typically used directly - created by auto-configuration.
*
* @return Builder instance
*/
public static Builder builder();
/**
* Builder for SyncMcpToolCallbackProvider.
*/
public static class Builder {
public Builder mcpClients(java.util.List<io.modelcontextprotocol.client.McpSyncClient> clients);
public Builder addMcpClient(io.modelcontextprotocol.client.McpSyncClient client);
public Builder toolFilter(McpToolFilter filter);
public Builder toolNamePrefixGenerator(McpToolNamePrefixGenerator generator);
public Builder toolContextToMcpMetaConverter(ToolContextToMcpMetaConverter converter);
public SyncMcpToolCallbackProvider build();
}
}package org.springframework.ai.mcp;
/**
* Asynchronous tool callback provider for MCP.
* Implements Spring AI's ToolCallbackProvider interface and ApplicationListener for tool changes.
* Thread-safe with internal caching.
* Caches tool list for performance - invalidated on tool change events.
* Uses reactive clients but provides blocking API for Spring AI compatibility.
*/
public class AsyncMcpToolCallbackProvider
implements org.springframework.ai.model.function.ToolCallbackProvider,
org.springframework.context.ApplicationListener<McpToolsChangedEvent> {
/**
* Get all tool callbacks from the provider.
* Returns cached list of tool callbacks.
* Thread-safe - returns defensive copy.
*
* @return Array of tool callbacks (never null, may be empty)
*/
public org.springframework.ai.model.function.ToolCallback[] getToolCallbacks();
/**
* Invalidate the tool cache, forcing a refresh from MCP clients.
* Called automatically when McpToolsChangedEvent is received.
* Can be called manually to force refresh.
* Thread-safe - synchronized internally.
*/
public void invalidateCache();
/**
* Handle tool list changed events.
* Automatically invalidates cache when tools change.
* Thread-safe - synchronized with cache access.
*
* @param event The tools changed event (never null)
*/
public void onApplicationEvent(McpToolsChangedEvent event);
/**
* Static helper method to create reactive tool callbacks from async clients.
* Not typically called directly - used by auto-configuration.
*
* @param mcpClients List of async MCP clients
* @return Flux of tool callbacks
*/
public static reactor.core.publisher.Flux<org.springframework.ai.model.function.ToolCallback> asyncToolCallbacks(
java.util.List<io.modelcontextprotocol.client.McpAsyncClient> mcpClients
);
/**
* Builder for creating AsyncMcpToolCallbackProvider instances.
* Not typically used directly - created by auto-configuration.
*
* @return Builder instance
*/
public static Builder builder();
/**
* Builder for AsyncMcpToolCallbackProvider.
*/
public static class Builder {
public Builder mcpClients(java.util.List<io.modelcontextprotocol.client.McpAsyncClient> clients);
public Builder toolFilter(McpToolFilter filter);
public Builder toolNamePrefixGenerator(McpToolNamePrefixGenerator generator);
public Builder toolContextToMcpMetaConverter(ToolContextToMcpMetaConverter converter);
public AsyncMcpToolCallbackProvider build();
}
}spring.ai.mcp.client:
enabled: true
type: SYNC
toolcallback:
enabled: true
sse:
connections:
weather-api:
url: http://localhost:8080
database-api:
url: http://localhost:9000With custom beans:
import org.springframework.ai.mcp.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
/**
* Configuration for MCP tool integration.
* Customizes filtering, naming, and metadata conversion.
*/
@Configuration
public class McpToolConfiguration {
/**
* Custom tool filter for safety and quality.
* Excludes dangerous and poorly documented tools.
*
* @return Tool filter bean
*/
@Bean
public McpToolFilter safeToolFilter() {
return (connectionInfo, tool) -> {
// Only safe, read-only tools
boolean isSafe = !tool.name().matches("(delete|drop|update|insert).*");
// Must have description
boolean hasDescription = tool.description() != null && !tool.description().isEmpty();
// Not from beta servers
boolean isStable = !connectionInfo.initializeResult().serverInfo().name().contains("beta");
return isSafe && hasDescription && isStable;
};
}
/**
* Custom prefix generator with server name.
* Makes tool origin clear.
*
* @return Prefix generator bean
*/
@Bean
public McpToolNamePrefixGenerator serverPrefixGenerator() {
return (connectionInfo, tool) -> {
String serverName = connectionInfo.initializeResult()
.serverInfo()
.name()
.toLowerCase()
.replaceAll("[^a-z0-9]", "_");
return serverName + "__" + tool.name();
};
}
/**
* Custom metadata converter.
* Adds application context to tool calls.
*
* @return Metadata converter bean
*/
@Bean
public ToolContextToMcpMetaConverter contextConverter() {
return toolContext -> {
return Map.of(
"timestamp", System.currentTimeMillis(),
"source", "spring-ai",
"requestId", toolContext.getContext().getOrDefault("requestId", "unknown"),
"userId", toolContext.getContext().getOrDefault("userId", "anonymous")
);
};
}
}If MCP tools aren't available to Spring AI:
spring.ai.mcp.client.toolcallback.enabled=trueIf you see tool name conflicts:
If tools fail to execute:
If tool execution is slow:
tessl i tessl/maven-org-springframework-ai--spring-ai-starter-mcp-client-webflux@1.1.0