Adds MCP Sampling implementation that demonstrates how to delegate LLM requests to multiple providers. - add a weather server that retrieves data and uses MCP Sampling to generate creative content - add a client that routes requests to different LLM providers (OpenAI and Anthropic) based on model hints - add README documentation explaining the MCP Sampling workflow and implementation details The MCP Sampling capability enables applications to leverage multiple LLM providers within a single workflow, allowing for creative content generation, model comparison, and specialized task delegation. Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
Spring AI MCP Weather Server Sample with WebMVC Starter and Sampling
This sample project demonstrates how to create an MCP server using the Spring AI MCP Server Boot Starter with WebMVC transport. It implements a weather service that exposes tools for retrieving weather information using the Open-Meteo API and showcases MCP Sampling capabilities.
For more information, see the MCP Server Boot Starter reference documentation.
Overview
The sample showcases:
- Integration with
spring-ai-mcp-server-webmvc-spring-boot-starter - Support for both SSE (Server-Sent Events) and STDIO transports
- Automatic tool registration using Spring AI's
@Toolannotation - MCP Sampling implementation that demonstrates LLM provider routing
- Weather tool that retrieves temperature data and generates creative responses using multiple LLMs
MCP Sampling Implementation
This project demonstrates the MCP Sampling capability, which allows an MCP server to delegate certain requests to LLM providers. The implementation includes:
-
Server-side Sampling: The
WeatherServiceclass implements acallMcpSamplingmethod that:- Extracts the
McpSyncServerExchangefrom the tool context - Creates two separate message requests with different model preferences:
- One targeting OpenAI models with
ModelPreferences.builder().addHint("openai").build() - One targeting Anthropic models with
ModelPreferences.builder().addHint("anthropic").build()
- One targeting OpenAI models with
- Sends both requests to generate creative poems about the weather data
- Combines the responses into a single result
- Extracts the
-
Client-side Sampling: The companion client project (
mcp-sampling-client) implements:- A
McpSyncClientCustomizerthat handles sampling requests - Logic to route requests to the appropriate LLM based on model hints
- Integration with both OpenAI and Anthropic models
- A
This approach demonstrates how MCP can be used to leverage multiple LLM providers within a single application, allowing for creative content generation and model comparison.
Dependencies
The project requires the Spring AI MCP Server WebMVC Boot Starter:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
</dependency>
This starter provides:
- HTTP-based transport using Spring MVC (
WebMvcSseServerTransport) - Auto-configured SSE endpoints
- Optional STDIO transport
- Included
spring-boot-starter-webandmcp-spring-webmvcdependencies
Building the Project
Build the project using Maven:
./mvnw clean install -DskipTests
Running the Server
The server supports two transport modes:
WebMVC SSE Mode (Default)
java -jar target/mcp-sampling-weather-server-0.0.1-SNAPSHOT.jar
STDIO Mode
To enable STDIO transport, set the appropriate properties:
java -Dspring.ai.mcp.server.stdio=true -Dspring.main.web-application-type=none -jar target/mcp-sampling-weather-server-0.0.1-SNAPSHOT.jar
Configuration
Configure the server through application.properties:
# Server identification
spring.ai.mcp.server.name=my-weather-server
spring.ai.mcp.server.version=0.0.1
# Server type (SYNC/ASYNC)
spring.ai.mcp.server.type=SYNC
# Transport configuration
spring.ai.mcp.server.stdio=false
spring.ai.mcp.server.sse-message-endpoint=/mcp/message
# Change notifications
spring.ai.mcp.server.resource-change-notification=true
spring.ai.mcp.server.tool-change-notification=true
spring.ai.mcp.server.prompt-change-notification=true
# Logging (required for STDIO transport)
spring.main.banner-mode=off
logging.file.name=./target/starter-webmvc-server.log
Available Tools
Weather Temperature Tool
- Name:
getTemperature - Description: Get the temperature (in celsius) for a specific location
- Parameters:
latitude: double - The location latitudelongitude: double - The location longitudetoolContext: ToolContext - Automatically provided by Spring AI
This tool not only retrieves the current temperature from the Open-Meteo API but also uses MCP Sampling to generate creative poems about the weather from both OpenAI and Anthropic models.
Server Implementation
The server uses Spring Boot and Spring AI's tool annotations for automatic tool registration:
@SpringBootApplication
public class McpServerApplication {
public static void main(String[] args) {
SpringApplication.run(McpServerApplication.class, args);
}
@Bean
public ToolCallbackProvider weatherTools(WeatherService weatherService){
return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
}
}
The WeatherService implements the weather tool using the @Tool annotation and includes MCP Sampling functionality:
@Service
public class WeatherService {
@Tool(description = "Get the temperature (in celsius) for a specific location")
public String getTemperature(double latitude, double longitude, ToolContext toolContext) {
// Retrieve weather data from Open-Meteo API
WeatherResponse weatherResponse = restClient
.get()
.uri("https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}¤t=temperature_2m",
latitude, longitude)
.retrieve()
.body(WeatherResponse.class);
// Use MCP Sampling to generate creative responses
String responseWithPoems = callMcpSampling(toolContext, weatherResponse);
return responseWithPoems;
}
public String callMcpSampling(ToolContext toolContext, WeatherResponse weatherResponse) {
// Implementation that calls both OpenAI and Anthropic models
// to generate poems about the weather
}
}
MCP Clients
You can connect to the weather server using either STDIO or SSE transport:
Manual Clients
WebMVC SSE Client
For servers using SSE transport:
var transport = new HttpClientSseClientTransport("http://localhost:8080");
var client = McpClient.sync(transport).build();
STDIO Client
For servers using STDIO transport:
var stdioParams = ServerParameters.builder("java")
.args("-Dspring.ai.mcp.server.stdio=true",
"-Dspring.main.web-application-type=none",
"-Dspring.main.banner-mode=off",
"-Dlogging.pattern.console=",
"-jar",
"target/mcp-sampling-weather-server-0.0.1-SNAPSHOT.jar")
.build();
var transport = new StdioClientTransport(stdioParams);
var client = McpClient.sync(transport).build();
The sample project includes example client implementations:
- SampleClient.java: Manual MCP client implementation
- ClientStdio.java: STDIO transport connection
Sampling Client
The companion project mcp-sampling-client demonstrates how to implement a client that handles MCP 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();
});
};
}
To run the sampling client:
- Start the MCP server
- Set the required environment variables:
export OPENAI_API_KEY=your-openai-key export ANTHROPIC_API_KEY=your-anthropic-key - Run the client:
java -jar target/mcp-sampling-client-0.0.1-SNAPSHOT.jar