CtrlK
CommunityDocumentationLog inGet started
Tessl Logo

tessl/maven-org-springframework-ai--spring-ai-starter-mcp-client-webflux

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

Overview
Eval results
Files

tool-callbacks.mddocs/reference/

Spring AI Tool Integration

Integration between MCP clients and Spring AI's tool execution framework through automatic tool callback providers.

Overview

The MCP Client WebFlux starter automatically converts MCP clients into Spring AI ToolCallbackProviders. This integration enables:

  • Automatic Tool Discovery: All MCP tools automatically available to Spring AI
  • Seamless Execution: MCP tools execute within Spring AI chat interactions
  • Tool Filtering: Selectively include/exclude tools with custom filters
  • Name Management: Handle tool name collisions across multiple servers
  • Metadata Conversion: Convert Spring AI context to MCP metadata
  • Dynamic Updates: Tools automatically updated when servers change

Key Features

  • Zero Configuration: Works out of the box with default settings
  • Thread-Safe: All components are thread-safe
  • Caching: Tool lists are cached for performance
  • Event-Driven: Automatically updates when tool lists change
  • Extensible: Customizable through filters and converters

Auto-Configuration

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)

Tool Callback Provider Beans

Synchronous Tool Callback Provider

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
);

Asynchronous Tool Callback Provider

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
);

Configuration

Enable/Disable Tool Callbacks

spring.ai.mcp.client:
  toolcallback:
    enabled: true  # default: true

To disable tool callback integration while keeping MCP clients active:

spring.ai.mcp.client:
  enabled: true
  toolcallback:
    enabled: false

Usage with Spring AI Chat Client

The 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();
    }
}

Example Interaction

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 response

Tool Filtering

Implement 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);
}

Filter Example

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
    }
}

Advanced Filtering Examples

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;
    };
}

Tool Name Prefix Generator

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();
}

Default Prefix Generator

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();

Custom Prefix Generator Example

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();
        };
    }
}

Tool Context to MCP Metadata Converter

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();
}

Custom Converter Example

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;
        };
    }
}

MCP Connection Info

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;
};

Tool Callback Types

SyncMcpToolCallback

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();
    }
}

AsyncMcpToolCallback

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();
    }
}

Provider Types

SyncMcpToolCallbackProvider

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();
    }
}

AsyncMcpToolCallbackProvider

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();
    }
}

Complete Configuration Example

spring.ai.mcp.client:
  enabled: true
  type: SYNC
  toolcallback:
    enabled: true

  sse:
    connections:
      weather-api:
        url: http://localhost:8080
      database-api:
        url: http://localhost:9000

With 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")
            );
        };
    }
}

Best Practices

  1. Use Default Configuration: Start with defaults - they work well for most cases
  2. Filter Carefully: Be conservative with tool filters - don't exclude too much
  3. Meaningful Names: Use descriptive tool names that indicate origin
  4. Metadata Sparingly: Only pass necessary metadata to avoid overhead
  5. Monitor Performance: Watch for slow tool executions
  6. Handle Errors: Implement proper error handling in AI service
  7. Test Tools: Test MCP tools independently before AI integration
  8. Document Tools: Ensure MCP tools have good descriptions for AI understanding
  9. Security First: Filter out dangerous tools in production
  10. Cache Awareness: Understand that tool lists are cached

Troubleshooting

Tools Not Available to AI

If MCP tools aren't available to Spring AI:

  1. Check Configuration: Verify spring.ai.mcp.client.toolcallback.enabled=true
  2. Check Clients: Ensure MCP clients are created and initialized
  3. Check Filters: Verify tool filters aren't excluding all tools
  4. Check Tool List: Use MCP clients directly to verify tools exist
  5. Check Logs: Enable debug logging for tool callback provider

Tool Name Collisions

If you see tool name conflicts:

  1. Custom Prefix Generator: Implement custom generator with server names
  2. Unique Names: Configure servers to use unique tool names
  3. Filter Duplicates: Use filter to exclude duplicate tools
  4. Check Logs: Look for warnings about name collisions

Tool Execution Failures

If tools fail to execute:

  1. Check Arguments: Verify tool arguments match expected schema
  2. Check Permissions: Ensure MCP server has necessary permissions
  3. Check Timeouts: Increase request timeout if needed
  4. Check Metadata: Verify metadata converter doesn't cause issues
  5. Test Directly: Test tool with MCP client directly

Performance Issues

If tool execution is slow:

  1. Check Caching: Verify tool list caching is working
  2. Check Filters: Ensure filters are efficient
  3. Check Network: Verify network latency to MCP servers
  4. Check Timeouts: Ensure timeouts are appropriate
  5. Profile: Use profiling to identify bottlenecks

Related Documentation

  • MCP Clients - Working directly with MCP clients
  • Events - Responding to tool changes
  • Configuration Properties - Complete property reference
  • Customization - Customizing client behavior
tessl i tessl/maven-org-springframework-ai--spring-ai-starter-mcp-client-webflux@1.1.0

docs

index.md

tile.json