279 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Spring AI MCP WebFlux 服务器示例
## 项目简介
本项目是一个基于 Spring AI 框架的 Model Context Protocol (MCP) WebFlux 服务器示例。它展示了如何构建一个支持 WebFlux 和 STDIO 两种通信方式的 MCP 服务器,提供天气查询和空气质量信息等工具服务。
## 主要功能
- 支持 WebFlux 和 STDIO 两种通信方式
- 提供天气预报查询服务(基于 OpenMeteo API
- 提供空气质量信息查询服务(模拟数据)
- 支持响应式编程模型
- 支持工具函数的动态注册和调用
## 技术栈
- Java 17+
- Spring Boot 3.x
- Spring WebFlux
- Spring AI MCP Server
- OpenMeteo API
- Maven
## 项目结构
```
starter-webflux-server/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── org/springframework/ai/mcp/sample/server/
│ │ │ ├── McpServerApplication.java # 应用程序入口
│ │ │ └── OpenMeteoService.java # 天气服务实现
│ │ └── resources/
│ │ └── application.properties # 应用配置
│ └── test/
│ └── java/
│ └── org/springframework/ai/mcp/sample/client/
│ ├── ClientStdio.java # STDIO 客户端测试
│ ├── ClientSse.java # SSE 客户端测试
│ └── SampleClient.java # 通用客户端测试
└── pom.xml # Maven 配置
```
## 核心组件
### McpServerApplication
应用程序的主入口类,负责:
- 配置 Spring Boot 应用
- 注册天气工具服务
- 初始化 MCP 服务器
### OpenMeteoService
提供两个主要工具服务:
1. `getWeatherForecastByLocation`: 获取指定位置的天气预报
- 支持当前天气和未来 7 天预报
- 包含温度、湿度、风向、降水量等信息
- 使用 OpenMeteo 免费 API
2. `getAirQuality`: 获取指定位置的空气质量信息
- 提供欧洲 AQI 和美国 AQI 两种标准
- 包含 PM10、PM2.5、CO、NO2、SO2、O3 等污染物数据
- 目前使用模拟数据(可扩展为真实 API
## 配置说明
### 服务器配置
`application.properties` 中:
```properties
# 服务器配置
spring.ai.mcp.server.name=my-weather-server
spring.ai.mcp.server.version=0.0.1
# 使用 STDIO 传输时的配置
spring.main.banner-mode=off
# logging.pattern.console=
```
### WebFlux 客户端配置
在客户端的 `application.properties` 中:
```properties
# 基本配置
server.port=8888
spring.application.name=mcp
spring.main.web-application-type=none
# API 密钥配置
spring.ai.dashscope.api-key=${AI_DASHSCOPE_API_KEY}
# SSE 连接配置
spring.ai.mcp.client.sse.connections.server1.url=http://localhost:8080
# 调试日志
logging.level.io.modelcontextprotocol.client=DEBUG
logging.level.io.modelcontextprotocol.spec=DEBUG
# 编码配置
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
spring.mandatory-file-encoding=UTF-8
# 用户输入配置
ai.user.input=北京的天气如何?
```
## 使用方法
### 1. 编译项目
```bash
mvn clean package -DskipTests
```
### 2. 启动服务器
#### 作为 Web 服务器启动
```bash
mvn spring-boot:run
```
服务器将在 http://localhost:8080 启动。
#### 作为 STDIO 服务器启动
```bash
java -Dspring.ai.mcp.server.stdio=true \
-Dspring.main.web-application-type=none \
-Dlogging.pattern.console= \
-jar target/mcp-starter-webflux-server-0.0.1-SNAPSHOT.jar
```
### 3. 客户端示例
#### WebFlux 客户端
##### 代码示例
代码文件为 org.springframework.ai.mcp.sample.client.ClientSse可以直接运行测试。
```java
// 配置 WebFlux 客户端
var transport = new WebFluxSseClientTransport(
WebClient.builder().baseUrl("http://localhost:8080")
);
// 创建聊天客户端
var chatClient = chatClientBuilder
.defaultTools(tools)
.build();
// 发送问题并获取回答
System.out.println("\n>>> QUESTION: " + userInput);
System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(userInput).call().content());
```
##### mcp setting 配置示例
在 cursor、cline 等 MCP 客户端中,本示例可以使用如下配置:
```json
{
"mcpServers": {
"weather-local": {
"url": "http://localhost:8080/sse"
}
}
}
```
#### STDIO 客户端
##### 代码示例
代码文件为 org.springframework.ai.mcp.sample.client.ClientStdio可以直接运行测试。
```java
var stdioParams = ServerParameters.builder("java")
.args("-Dspring.ai.mcp.server.stdio=true",
"-Dspring.main.web-application-type=none",
"-Dlogging.pattern.console=",
"-jar",
"target/mcp-starter-webflux-server-0.0.1-SNAPSHOT.jar")
.build();
var transport = new StdioClientTransport(stdioParams);
new SampleClient(transport).run();
```
##### mcp setting 配置示例
在 cursor、cline 等 MCP 客户端中,本示例可以使用如下配置:
```json
{
"mcpServers": {
"weather-local": {
"command": "java",
"args": [
"-Dspring.ai.mcp.server.stdio=true",
"-Dspring.main.web-application-type=none",
"-Dlogging.pattern.console=",
"-jar",
"target/mcp-starter-webflux-server-0.0.1-SNAPSHOT.jar"
]
}
}
}
```
## 工具调用示例
### 获取天气预报
```java
CallToolResult weatherResult = client.callTool(
new CallToolRequest("getWeatherForecastByLocation",
Map.of("latitude", "39.9042", "longitude", "116.4074"))
);
```
### 获取空气质量信息
```java
CallToolResult airQualityResult = client.callTool(
new CallToolRequest("getAirQuality",
Map.of("latitude", "39.9042", "longitude", "116.4074"))
);
```
## 注意事项
1. OpenMeteo API 是免费的,无需 API 密钥
2. 空气质量数据目前使用模拟数据,实际应用中应替换为真实 API
3. 使用 STDIO 传输时,必须禁用控制台日志和 banner
4. 默认作为 WebFlux 服务器运行,支持 HTTP 通信
5. 客户端需要正确配置 SSE 连接 URL
6. 确保环境变量 `DASH_SCOPE_API_KEY` 已正确设置
## 扩展开发
如需添加新的工具服务:
1. 创建新的服务类
2. 使用 `@Tool` 注解标记方法
3.`McpServerApplication` 中注册服务
示例:
```java
@Service
public class MyNewService {
@Tool(description = "新工具描述")
public String myNewTool(String input) {
// 实现工具逻辑
return "处理结果: " + input;
}
}
// 在 McpServerApplication 中注册
@Bean
public ToolCallbackProvider myTools(MyNewService myNewService) {
return MethodToolCallbackProvider.builder()
.toolObjects(myNewService)
.build();
}
```
## 许可证
Apache License 2.0