CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Spring Framework integration for Model Context Protocol (MCP), providing Spring AI function calling capabilities and Spring-friendly abstractions for MCP clients and MCP servers

Overview
Eval results
Files

client-customization.mddocs/reference/

Client Customization

Customize MCP client configuration for both synchronous and asynchronous clients through customizer interfaces.

Import

import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;
import org.springframework.ai.mcp.customizer.McpAsyncClientCustomizer;
import io.modelcontextprotocol.client.McpClient;

Synchronous Client Customization

McpSyncClientCustomizer Interface

@FunctionalInterface
public interface McpSyncClientCustomizer {
    void customize(String name, McpClient.SyncSpec spec);
}

Functional interface for customizing synchronous MCP client specifications before they are built.

Parameters

  • name: The name of the client being customized
  • spec: The McpClient.SyncSpec to customize

Usage Example

import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;
import org.springframework.stereotype.Component;

@Component
public class CustomSyncClientCustomizer implements McpSyncClientCustomizer {

    @Override
    public void customize(String name, McpClient.SyncSpec spec) {
        System.out.println("Customizing sync client: " + name);

        // Add custom configuration to the sync spec
        // The McpClient.SyncSpec provides methods for configuring
        // the synchronous MCP client
    }
}

Asynchronous Client Customization

McpAsyncClientCustomizer Interface

@FunctionalInterface
public interface McpAsyncClientCustomizer {
    void customize(String name, McpClient.AsyncSpec spec);
}

Functional interface for customizing asynchronous MCP client specifications before they are built.

Parameters

  • name: The name of the client being customized
  • spec: The McpClient.AsyncSpec to customize

Usage Example

import org.springframework.ai.mcp.customizer.McpAsyncClientCustomizer;
import org.springframework.stereotype.Component;

@Component
public class CustomAsyncClientCustomizer implements McpAsyncClientCustomizer {

    @Override
    public void customize(String name, McpClient.AsyncSpec spec) {
        System.out.println("Customizing async client: " + name);

        // Add custom configuration to the async spec
        // The McpClient.AsyncSpec provides methods for configuring
        // the asynchronous MCP client
    }
}

Lambda Customizers

Sync Client Lambda

McpSyncClientCustomizer syncCustomizer = (name, spec) -> {
    if (name.contains("production")) {
        // Production-specific configuration
        System.out.println("Configuring production sync client: " + name);
        // Apply production settings to spec
    } else {
        // Development configuration
        System.out.println("Configuring development sync client: " + name);
        // Apply development settings to spec
    }
};

Async Client Lambda

McpAsyncClientCustomizer asyncCustomizer = (name, spec) -> {
    if (name.contains("high-latency")) {
        // Configure for high-latency environments
        System.out.println("Configuring async client for high latency: " + name);
        // Adjust timeouts, retry policies, etc.
    }
};

Spring Bean Customizers

Sync Client Bean

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;

@Configuration
public class McpSyncCustomizerConfig {

    @Bean
    public McpSyncClientCustomizer productionSyncCustomizer() {
        return (name, spec) -> {
            // Global customization for all sync clients
            System.out.println("Applying global sync customization for: " + name);

            // Configure connection settings
            // Configure timeouts
            // Configure security settings
            // etc.
        };
    }

    @Bean
    public McpSyncClientCustomizer environmentSpecificCustomizer() {
        String environment = System.getenv("ENVIRONMENT");

        return (name, spec) -> {
            if ("production".equals(environment)) {
                // Production settings
            } else if ("staging".equals(environment)) {
                // Staging settings
            } else {
                // Development settings
            }
        };
    }
}

Async Client Bean

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ai.mcp.customizer.McpAsyncClientCustomizer;

@Configuration
public class McpAsyncCustomizerConfig {

    @Bean
    public McpAsyncClientCustomizer reactiveCustomizer() {
        return (name, spec) -> {
            System.out.println("Customizing async client: " + name);

            // Configure reactive settings
            // Configure schedulers
            // Configure backpressure
            // etc.
        };
    }
}

Complete Example

import org.springframework.ai.mcp.customizer.*;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Value;
import io.modelcontextprotocol.client.McpClient;

@Component
public class ComprehensiveMcpCustomizers {

    @Value("${mcp.timeout:30000}")
    private int defaultTimeout;

    @Value("${mcp.max-retries:3}")
    private int maxRetries;

    public McpSyncClientCustomizer syncCustomizer() {
        return (name, spec) -> {
            System.out.println("Customizing sync MCP client: " + name);

            // Apply timeout settings based on client name
            if (name.contains("slow-server")) {
                // Longer timeout for slow servers
                System.out.println("  - Using extended timeout for slow server");
            } else {
                // Standard timeout
                System.out.println("  - Using standard timeout: " + defaultTimeout + "ms");
            }

            // Apply retry configuration
            System.out.println("  - Max retries: " + maxRetries);

            // Apply security settings
            if (name.contains("production")) {
                System.out.println("  - Applying production security settings");
            }
        };
    }

    public McpAsyncClientCustomizer asyncCustomizer() {
        return (name, spec) -> {
            System.out.println("Customizing async MCP client: " + name);

            // Configure reactive execution
            System.out.println("  - Configuring reactive execution model");

            // Configure backpressure strategy
            if (name.contains("high-throughput")) {
                System.out.println("  - Using high-throughput backpressure strategy");
            } else {
                System.out.println("  - Using standard backpressure strategy");
            }

            // Apply timeout and retry for async operations
            System.out.println("  - Async timeout: " + defaultTimeout + "ms");
            System.out.println("  - Async retries: " + maxRetries);
        };
    }
}

Conditional Customization

import java.util.Map;

public class ConditionalCustomizers {

    private static final Map<String, McpSyncClientCustomizer> SYNC_CUSTOMIZERS = Map.of(
        "weather", (name, spec) -> {
            // Weather service specific customization
            System.out.println("Weather service customization");
        },
        "database", (name, spec) -> {
            // Database service specific customization
            System.out.println("Database service customization");
        },
        "filesystem", (name, spec) -> {
            // Filesystem service specific customization
            System.out.println("Filesystem service customization");
        }
    );

    public static McpSyncClientCustomizer forService(String serviceType) {
        return SYNC_CUSTOMIZERS.getOrDefault(serviceType,
            (name, spec) -> System.out.println("Default customization for: " + name));
    }

    public static McpAsyncClientCustomizer asyncForService(String serviceType) {
        return (name, spec) -> {
            switch (serviceType) {
                case "high-latency":
                    System.out.println("High-latency async customization");
                    break;
                case "low-latency":
                    System.out.println("Low-latency async customization");
                    break;
                default:
                    System.out.println("Standard async customization");
            }
        };
    }
}

Multiple Customizers

import java.util.List;

public class CompositeCustomizers {

    public static McpSyncClientCustomizer composeSyncCustomizers(
            List<McpSyncClientCustomizer> customizers) {
        return (name, spec) -> {
            for (McpSyncClientCustomizer customizer : customizers) {
                customizer.customize(name, spec);
            }
        };
    }

    public static McpAsyncClientCustomizer composeAsyncCustomizers(
            List<McpAsyncClientCustomizer> customizers) {
        return (name, spec) -> {
            for (McpAsyncClientCustomizer customizer : customizers) {
                customizer.customize(name, spec);
            }
        };
    }
}

// Usage
McpSyncClientCustomizer composite = CompositeCustomizers.composeSyncCustomizers(
    List.of(
        (name, spec) -> System.out.println("First customizer"),
        (name, spec) -> System.out.println("Second customizer"),
        (name, spec) -> System.out.println("Third customizer")
    )
);

Environment-Based Customization

@Component
public class EnvironmentBasedCustomizer {

    private final String environment;

    public EnvironmentBasedCustomizer(@Value("${spring.profiles.active:default}") String environment) {
        this.environment = environment;
    }

    public McpSyncClientCustomizer getSyncCustomizer() {
        return (name, spec) -> {
            switch (environment) {
                case "production":
                    applyProductionSettings(name, spec);
                    break;
                case "staging":
                    applyStagingSettings(name, spec);
                    break;
                case "development":
                    applyDevelopmentSettings(name, spec);
                    break;
                default:
                    applyDefaultSettings(name, spec);
            }
        };
    }

    private void applyProductionSettings(String name, McpClient.SyncSpec spec) {
        System.out.println("Production settings for: " + name);
        // Strict timeouts, security, monitoring
    }

    private void applyStagingSettings(String name, McpClient.SyncSpec spec) {
        System.out.println("Staging settings for: " + name);
        // Similar to production but with debugging enabled
    }

    private void applyDevelopmentSettings(String name, McpClient.SyncSpec spec) {
        System.out.println("Development settings for: " + name);
        // Relaxed timeouts, verbose logging
    }

    private void applyDefaultSettings(String name, McpClient.SyncSpec spec) {
        System.out.println("Default settings for: " + name);
    }
}

Related Components

Note: These customizers are typically used during MCP client creation. The spring-ai-mcp library provides the interfaces but the actual client configuration is handled by the MCP SDK client builders (McpSyncClient, McpAsyncClient).

For typical usage with spring-ai-mcp tool callbacks and providers, customization happens during client creation rather than through the spring-ai-mcp library itself.

Install with Tessl CLI

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

docs

index.md

tile.json