Spring AI MCP Sampling Examples
This directory contains examples demonstrating the Model Context Protocol (MCP) Sampling capability in Spring AI. MCP Sampling allows an MCP server to delegate certain requests to LLM providers, enabling multi-model interactions and creative content generation.
Overview
The MCP Sampling examples showcase:
- How an MCP server can delegate LLM requests to a client
- How a client can route requests to different LLM providers based on model hints
- Integration with multiple LLM providers (OpenAI and Anthropic)
- Creative content generation using multiple models
- Combining responses from different LLMs into a unified result
Projects
This directory contains two main projects:
- mcp-weather-webmvc-server: An MCP server that provides weather information and uses MCP Sampling to generate creative content
- mcp-sampling-client: An MCP client that handles sampling requests and routes them to different LLM providers
What is MCP Sampling?
MCP Sampling is a powerful capability of the Model Context Protocol that allows:
- An MCP server to delegate certain requests to LLM providers
- Specifying model preferences to target specific LLM providers
- Routing requests based on model hints
- Combining responses from multiple LLMs
This approach enables applications to leverage multiple LLM providers within a single workflow, allowing for creative content generation, model comparison, and specialized task delegation.
How It Works
The MCP Sampling workflow in these examples follows these steps:
-
Client Initialization:
- The client connects to the MCP Weather Server
- It registers a sampling handler that can route requests to different LLM providers
-
User Query:
- The user sends a weather-related query to the client
- The client forwards the query to the MCP Weather Server
-
Server Processing:
- The server retrieves weather data from the Open-Meteo API
- It extracts the
McpSyncServerExchangefrom the tool context - It creates sampling requests with different model preferences:
- One targeting OpenAI with
ModelPreferences.builder().addHint("openai").build() - One targeting Anthropic with
ModelPreferences.builder().addHint("anthropic").build()
- One targeting OpenAI with
-
Sampling Delegation:
- The server sends the sampling requests back to the client
- The client's sampling handler receives the requests
-
Model Routing:
- The client extracts the model hint from each request
- It selects the appropriate LLM provider based on the hint
- It forwards the prompt to the selected LLM
-
Response Generation:
- Each LLM generates a creative response (in this case, a poem about the weather)
- The client returns the responses to the server
-
Result Combination:
- The server combines the responses from different LLMs
- It returns the combined result to the user
Server Implementation
The MCP Weather Server implements the server-side of MCP Sampling:
public String callMcpSampling(ToolContext toolContext, WeatherResponse weatherResponse) {
String openAiWeatherPoem = "<no OpenAI poem>";
String anthropicWeatherPoem = "<no Anthropic poem>";
if (toolContext != null && toolContext.getContext().containsKey("exchange")) {
// Spring AI MCP Auto-configuration injects the McpSyncServerExchange into the ToolContext
McpSyncServerExchange exchange = (McpSyncServerExchange) toolContext.getContext().get("exchange");
if (exchange.getClientCapabilities().sampling() != null) {
var messageRequestBuilder = McpSchema.CreateMessageRequest.builder()
.systemPrompt("You are a poet!")
.messages(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER,
new McpSchema.TextContent(
"Please write a poem about this weather forecast (temperature is in Celsius)..."))));
// Request poem from OpenAI
var openAiLlmMessageRequest = messageRequestBuilder
.modelPreferences(ModelPreferences.builder().addHint("openai").build())
.build();
CreateMessageResult openAiLlmResponse = exchange.createMessage(openAiLlmMessageRequest);
openAiWeatherPoem = ((McpSchema.TextContent) openAiLlmResponse.content()).text();
// Request poem from Anthropic
var anthropicLlmMessageRequest = messageRequestBuilder
.modelPreferences(ModelPreferences.builder().addHint("anthropic").build())
.build();
CreateMessageResult anthropicAiLlmResponse = exchange.createMessage(anthropicLlmMessageRequest);
anthropicWeatherPoem = ((McpSchema.TextContent) anthropicAiLlmResponse.content()).text();
}
}
// Combine responses
return "OpenAI poem about the weather: " + openAiWeatherPoem + "\n\n" +
"Anthropic poem about the weather: " + anthropicWeatherPoem + "\n" +
ModelOptionsUtils.toJsonStringPrettyPrinter(weatherResponse);
}
Client Implementation
The MCP Sampling Client implements the client-side handling of sampling requests:
@Bean
McpSyncClientCustomizer samplingCustomizer(Map<String, ChatClient> chatClients) {
return (name, spec) -> {
spec.sampling(llmRequest -> {
var userPrompt = ((McpSchema.TextContent) llmRequest.messages().get(0).content()).text();
String modelHint = llmRequest.modelPreferences().hints().get(0).name();
// Find the appropriate chat client based on the model hint
ChatClient hintedChatClient = chatClients.entrySet().stream()
.filter(e -> e.getKey().contains(modelHint)).findFirst()
.orElseThrow().getValue();
// Generate response using the selected model
String response = hintedChatClient.prompt()
.system(llmRequest.systemPrompt())
.user(userPrompt)
.call()
.content();
return CreateMessageResult.builder().content(new McpSchema.TextContent(response)).build();
});
};
}
NOTE: To prevent cyclic dependencies you have to disable MCP tool callbacks auto-configuration: spring.ai.mcp.client.toolcallback.enabled=false
Running the Examples
Prerequisites
- Java 17 or later
- Maven 3.6+
- OpenAI API key
- Anthropic API key
Step 1: Start the MCP Weather Server
cd mcp-weather-webmvc-server
./mvnw clean install -DskipTests
java -jar target/mcp-sampling-weather-server-0.0.1-SNAPSHOT.jar
Step 2: Set Environment Variables
export OPENAI_API_KEY=your-openai-key
export ANTHROPIC_API_KEY=your-anthropic-key
Step 3: Run the MCP Sampling Client
cd mcp-sampling-client
./mvnw clean install
java -Dai.user.input='What is the weather in Amsterdam right now?' -jar target/mcp-sampling-client-0.0.1-SNAPSHOT.jar
Sample Output
When you run the application, you'll see creative responses from both OpenAI and Anthropic models, each generating a poem about the current weather in Amsterdam.
Related Projects
Spring AI provides several MCP client and server implementations:
- starter-default-client: A default MCP client implementation using Spring Boot
- starter-webflux-client: An MCP client implementation using Spring WebFlux