CtrlK
CommunityDocumentationLog inGet started
Tessl Logo

tessl/maven-org-springframework-ai--spring-ai-starter-mcp-server

Spring Boot Starter for building Model Context Protocol (MCP) servers with auto-configuration, annotation-based tool/resource/prompt definitions, and support for STDIO, SSE, and Streamable-HTTP transports

Overview
Eval results
Files

client-integration.mddocs/reference/

Client Integration

Integration components for using MCP servers as clients in Spring AI applications. These components allow Spring AI applications to consume tools from remote MCP servers.

Package Information

Note: This functionality is for client-side integration - using this starter to connect to remote MCP servers and consume their tools in your Spring AI application.

Capabilities

SyncMcpToolCallback

Synchronous adapter that wraps an MCP tool from a remote server as a Spring AI ToolCallback.

/**
 * Synchronous adapter for MCP tools to Spring AI ToolCallback
 */
class SyncMcpToolCallback implements ToolCallback {
    static Builder builder() { ... }

    /**
     * Get the tool definition
     */
    ToolDefinition getToolDefinition();

    /**
     * Get the original MCP tool name
     */
    String getOriginalToolName();

    /**
     * Execute the tool
     */
    String call(String toolCallInput);

    /**
     * Execute the tool with context
     */
    String call(String toolCallInput, ToolContext toolContext);

    interface Builder {
        Builder mcpClient(McpSyncClient client);
        Builder tool(Tool tool);
        Builder prefixedToolName(String name);
        Builder toolContextToMcpMetaConverter(ToolContextToMcpMetaConverter converter);
        SyncMcpToolCallback build();
    }
}

Usage Example:

import org.springframework.ai.mcp.SyncMcpToolCallback;
import org.springaicommunity.mcp.client.McpSyncClient;

@Configuration
public class ClientToolConfig {

    @Bean
    public ToolCallback remoteCalculator(McpSyncClient calculatorServer) {
        // Get tool definition from remote server
        Tool addTool = calculatorServer.listTools().stream()
            .filter(t -> "add".equals(t.name()))
            .findFirst()
            .orElseThrow();

        // Wrap as Spring AI ToolCallback
        return SyncMcpToolCallback.builder()
            .mcpClient(calculatorServer)
            .tool(addTool)
            .build();
    }
}

AsyncMcpToolCallback

Asynchronous adapter for MCP tools with reactive execution.

/**
 * Asynchronous adapter for MCP tools to Spring AI ToolCallback
 */
class AsyncMcpToolCallback implements ToolCallback {
    static Builder builder() { ... }

    ToolDefinition getToolDefinition();
    String getOriginalToolName();
    String call(String toolCallInput);
    String call(String toolCallInput, ToolContext toolContext);

    interface Builder {
        Builder mcpClient(McpAsyncClient client);
        Builder tool(Tool tool);
        Builder prefixedToolName(String name);
        Builder toolContextToMcpMetaConverter(ToolContextToMcpMetaConverter converter);
        AsyncMcpToolCallback build();
    }
}

SyncMcpToolCallbackProvider

Discovers and provides tools from multiple MCP servers synchronously.

/**
 * Provides tool callbacks from multiple sync MCP servers
 */
class SyncMcpToolCallbackProvider implements ToolCallbackProvider, ApplicationListener<McpToolsChangedEvent> {
    static Builder builder() { ... }

    /**
     * Get all discovered tool callbacks
     */
    ToolCallback[] getToolCallbacks();

    /**
     * Invalidate cache and force re-discovery
     */
    void invalidateCache();

    /**
     * Static helper to get callbacks from clients
     */
    static List<ToolCallback> syncToolCallbacks(List<McpSyncClient> clients);

    interface Builder {
        Builder mcpClients(List<McpSyncClient> clients);
        Builder mcpClients(McpSyncClient... clients);
        Builder addMcpClient(McpSyncClient client);
        Builder toolFilter(McpToolFilter filter);
        Builder toolNamePrefixGenerator(McpToolNamePrefixGenerator generator);
        Builder toolContextToMcpMetaConverter(ToolContextToMcpMetaConverter converter);
        SyncMcpToolCallbackProvider build();
    }
}

Usage Example:

@Configuration
public class MultiServerConfig {

    @Bean
    public SyncMcpToolCallbackProvider allServerTools(
            McpSyncClient weatherServer,
            McpSyncClient calculatorServer,
            McpSyncClient databaseServer) {

        return SyncMcpToolCallbackProvider.builder()
            .mcpClients(weatherServer, calculatorServer, databaseServer)
            .toolFilter((connectionInfo, tool) -> {
                // Filter out internal tools
                return !tool.name().startsWith("internal_");
            })
            .toolNamePrefixGenerator((connectionInfo, tool) -> {
                // Prefix with server name
                String serverName = connectionInfo.clientInfo().name();
                return serverName + "_" + tool.name();
            })
            .build();
    }

    @Bean
    public ChatClient chatClient(ChatClient.Builder builder,
                                  SyncMcpToolCallbackProvider toolProvider) {
        return builder
            .defaultTools(toolProvider.getToolCallbacks())
            .build();
    }
}

AsyncMcpToolCallbackProvider

Discovers and provides tools from multiple MCP servers asynchronously.

/**
 * Provides tool callbacks from multiple async MCP servers
 */
class AsyncMcpToolCallbackProvider implements ToolCallbackProvider, ApplicationListener<McpToolsChangedEvent> {
    static Builder builder() { ... }

    ToolCallback[] getToolCallbacks();
    void invalidateCache();

    /**
     * Reactive stream of tool callbacks
     */
    static Flux<ToolCallback> asyncToolCallbacks(List<McpAsyncClient> clients);

    interface Builder {
        Builder toolFilter(McpToolFilter filter);
        Builder mcpClients(List<McpAsyncClient> clients);
        Builder mcpClients(McpAsyncClient... clients);
        Builder toolNamePrefixGenerator(McpToolNamePrefixGenerator generator);
        Builder toolContextToMcpMetaConverter(ToolContextToMcpMetaConverter converter);
        AsyncMcpToolCallbackProvider build();
    }
}

McpConnectionInfo

Container for MCP connection metadata.

/**
 * Record containing MCP connection metadata
 */
record McpConnectionInfo(
    ClientCapabilities clientCapabilities,
    Implementation clientInfo,
    InitializeResult initializeResult
) {
    static Builder builder() { ... }

    interface Builder {
        Builder clientCapabilities(ClientCapabilities capabilities);
        Builder clientInfo(Implementation info);
        Builder initializeResult(InitializeResult result);
        McpConnectionInfo build();
    }
}

Strategy Interfaces

McpToolFilter

Filter tools during discovery.

/**
 * Functional interface for filtering discovered tools
 */
@FunctionalInterface
interface McpToolFilter extends BiPredicate<McpConnectionInfo, Tool> {
    boolean test(McpConnectionInfo connectionInfo, Tool tool);
}

Usage Examples:

// Filter by name pattern
McpToolFilter nameFilter = (conn, tool) ->
    tool.name().matches("^[a-z_]+$");

// Filter by server
McpToolFilter serverFilter = (conn, tool) ->
    "trusted-server".equals(conn.clientInfo().name());

// Filter by description
McpToolFilter descFilter = (conn, tool) ->
    tool.description() != null && !tool.description().isEmpty();

// Combine filters
McpToolFilter combined = nameFilter.and(descFilter);

McpToolNamePrefixGenerator

Generate prefixed tool names to avoid conflicts.

/**
 * Strategy for generating prefixed tool names
 */
interface McpToolNamePrefixGenerator {
    String prefixedToolName(McpConnectionInfo connectionInfo, Tool tool);

    /**
     * Returns tool name without prefix
     */
    static McpToolNamePrefixGenerator noPrefix();
}

Usage Examples:

// Default: prefix with server name
McpToolNamePrefixGenerator defaultGen = new DefaultMcpToolNamePrefixGenerator();

// No prefix
McpToolNamePrefixGenerator noPrefix = McpToolNamePrefixGenerator.noPrefix();

// Custom prefix with version
McpToolNamePrefixGenerator versionPrefix = (conn, tool) -> {
    String version = conn.clientInfo().version();
    return "v" + version + "_" + tool.name();
};

ToolContextToMcpMetaConverter

Convert Spring AI ToolContext to MCP metadata.

/**
 * Strategy for converting ToolContext to MCP metadata
 */
interface ToolContextToMcpMetaConverter {
    Map<String, Object> convert(ToolContext toolContext);

    /**
     * Default converter extracting common metadata
     */
    static ToolContextToMcpMetaConverter defaultConverter();

    /**
     * No-op converter returning empty map
     */
    static ToolContextToMcpMetaConverter noOp();
}

Usage Examples:

// Default converter
ToolContextToMcpMetaConverter defaultConv =
    ToolContextToMcpMetaConverter.defaultConverter();

// No-op
ToolContextToMcpMetaConverter noOp =
    ToolContextToMcpMetaConverter.noOp();

// Custom converter
ToolContextToMcpMetaConverter custom = (toolContext) -> {
    Map<String, Object> meta = new HashMap<>();
    meta.put("timestamp", System.currentTimeMillis());
    meta.put("user", toolContext.getContext().get("user"));
    meta.put("session", toolContext.getContext().get("session"));
    return meta;
};

Events

McpToolsChangedEvent

Event published when tools change on an MCP server.

/**
 * Event published when MCP tools change for a connection
 */
class McpToolsChangedEvent extends ApplicationEvent {
    McpToolsChangedEvent(String connectionName, List<Tool> tools);

    /**
     * Get the connection name where tools changed
     */
    String getConnectionName();

    /**
     * Get the updated list of tools
     */
    List<Tool> getTools();
}

Usage Example:

@Component
public class ToolChangeHandler {

    @EventListener
    public void onToolsChanged(McpToolsChangedEvent event) {
        String connection = event.getConnectionName();
        List<Tool> tools = event.getTools();

        System.out.println("Tools updated for: " + connection);
        System.out.println("Available tools: " + tools.size());

        // Invalidate caches, update UI, etc.
        toolCache.invalidate(connection);
    }
}

Complete Integration Example

@Configuration
public class McpClientIntegrationConfig {

    // Define MCP client connections
    @Bean
    public McpSyncClient weatherServer() {
        return McpClient.sync()
            .transport(StdioServerTransport.builder()
                .command("weather-mcp-server")
                .build())
            .build();
    }

    @Bean
    public McpSyncClient calculatorServer() {
        return McpClient.sync()
            .transport(SseClientTransport.builder()
                .url("http://calculator-server.example.com/sse")
                .build())
            .build();
    }

    // Provide tools from all servers
    @Bean
    public SyncMcpToolCallbackProvider toolProvider(
            List<McpSyncClient> clients) {

        return SyncMcpToolCallbackProvider.builder()
            .mcpClients(clients)
            .toolFilter((conn, tool) -> !tool.name().startsWith("_"))
            .toolNamePrefixGenerator(new DefaultMcpToolNamePrefixGenerator())
            .toolContextToMcpMetaConverter(
                ToolContextToMcpMetaConverter.defaultConverter())
            .build();
    }

    // Configure Spring AI ChatClient with MCP tools
    @Bean
    public ChatClient chatClient(
            ChatClient.Builder builder,
            SyncMcpToolCallbackProvider toolProvider) {

        return builder
            .defaultTools(toolProvider.getToolCallbacks())
            .build();
    }

    // Listen for tool changes
    @EventListener
    public void handleToolChanges(McpToolsChangedEvent event) {
        System.out.println("Tools changed: " + event.getConnectionName());
        // Handle tool updates
    }
}

Tool Discovery Flow

  1. Connection - MCP clients connect to remote servers
  2. Discovery - Clients list available tools from each server
  3. Filtering - McpToolFilter applies filtering rules
  4. Naming - McpToolNamePrefixGenerator creates unique names
  5. Wrapping - Tools are wrapped as Spring AI ToolCallbacks
  6. Registration - ToolCallbacks are provided to Spring AI
  7. Change Tracking - McpToolsChangedEvent published on updates
  8. Invalidation - Caches are invalidated and tools re-discovered

Client vs Server Usage

This starter provides both server and client capabilities:

AspectServer UsageClient Usage
PurposeExpose your tools via MCPConsume remote MCP tools
Components@McpTool annotations, specificationsToolCallback adapters, providers
Configurationspring.ai.mcp.server.*MCP client beans
IntegrationStandalone MCP serverSpring AI ChatClient
TransportSTDIO, SSE, Streamable HTTPClient transports

Most applications will use either server or client functionality, not both.

tessl i tessl/maven-org-springframework-ai--spring-ai-starter-mcp-server@1.1.0

docs

index.md

tile.json