在 Spring AI 中使用 MCP Server
1.1 Spring AI MCP 的介绍
Spring AI MCP 为模型上下文协议提供 Java 和 Spring 框架集成。它使 Spring AI 应用程序能够通过标准化的接口与不同的数据源和工具进行交互,支持同步和异步通信模式。整体架构如下:
Spring AI MCP 采用模块化架构,包括以下组件:
Spring AI 应用程序:使用 Spring AI 框架构建想要通过 MCP 访问数据的生成式 AI 应用程序
Spring MCP 客户端:MCP 协议的 Spring AI 实现,与服务器保持 1:1 连接
通过 Spring AI MCP,可以快速搭建 MCP 客户端和服务端程序。
2.2 使用 Spring AI MCP 快速搭建 MCP Server
Spring AI 提供了两种机制快速搭建 MCP Server,通过这两种方式开发者可以快速向 AI 应用开放自身的能力,这两种机制如下:
基于 stdio 的进程间通信传输,以独立的进程运行在 AI 应用本地,适用于比较轻量级的工具。
基于 SSE(Server-Sent Events) 进行远程服务访问,需要将服务单独部署,客户端通过服务端的 URL 进行远程访问,适用于比较重量级的工具。
2.2.1 基于 stdio 的 MCP 服务端实现
基于 stdio 的 MCP 服务端通过标准输入输出流与客户端通信,适用于作为子进程被客户端启动和管理的场景。
添加依赖
首先,在项目中添加 Spring AI MCP Server Starter 依赖:
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
</dependency>
配置 MCP 服务端
在 application.yml 中配置 MCP 服务端,这次要实现的是一个天气服务:
spring:main:web-application-type: none # 必须禁用web应用类型banner-mode: off # 禁用bannerai:mcp:server:stdio: true # 启用stdio模式name: my-weather-server # 服务器名称version: 0.0.1 # 服务器版本
实现 MCP 工具
使用 @Tool 注解标记方法,使其可以被 MCP 客户端发现和调用,通过 @ToolParameter 注解工具的具体参数:
class OpenMeteoService {private final WebClient webClient;public OpenMeteoService(WebClient.Builder webClientBuilder) {this.webClient = webClientBuilder.baseUrl("https://api.open-meteo.com/v1").build();}(description = "根据经纬度获取天气预报")public String getWeatherForecastByLocation((description = "纬度,例如:39.9042") String latitude,(description = "经度,例如:116.4074") String longitude) {try {String response = webClient.get().uri(uriBuilder -> uriBuilder.path("/forecast").queryParam("latitude", latitude).queryParam("longitude", longitude).queryParam("current", "temperature_2m,wind_speed_10m").queryParam("timezone", "auto").build()).retrieve().bodyToMono(String.class).block();// 解析响应并返回格式化的天气信息// 这里简化处理,实际应用中应该解析JSONreturn "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的天气信息:\n" + response;} catch (Exception e) {return "获取天气信息失败:" + e.getMessage();}}(description = "根据经纬度获取空气质量信息")public String getAirQuality((description = "纬度,例如:39.9042") String latitude,(description = "经度,例如:116.4074") String longitude) {// 模拟数据,实际应用中应调用真实APIreturn "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的空气质量:\n" +"- PM2.5: 15 μg/m³ (优)\n" +"- PM10: 28 μg/m³ (良)\n" +"- 空气质量指数(AQI): 42 (优)\n" +"- 主要污染物: 无";}
}
public
这里使用了 OpenMeteo, OpenMeteo 是一个开源的天气 API,为非商业用途提供免费访问,无需 API 密钥。
注册 MCP 工具
在应用程序入口类中注册工具:
class McpServerApplication {public static void main(String[] args) {SpringApplication.run(McpServerApplication.class, args);} public ToolCallbackProvider weatherTools(OpenMeteoService openMeteoService) {return MethodToolCallbackProvider.builder().toolObjects(openMeteoService).build();}
}
public
运行服务端
在控制台中执行如下命令,编译并打包应用:
Terminal window
mvn clean package -DskipTests
基于 SSE 的 MCP 服务端实现
基于 SSE 的 MCP 服务端通过 HTTP 协议与客户端通信,适用于作为独立服务部署的场景,可以被多个客户端远程调用,具体做法与 stdio 非常类似。
添加依赖
首先,在您的项目中添加依赖
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-mcp-server-webflux-spring-boot-starter</artifactId>
</dependency>
配置 MCP 服务端
在application.yml中配置 MCP 服务端:
server:port: 8080 # 服务器端口配置spring:ai:mcp:server:name: my-weather-server # MCP服务器名称version: 0.0.1 # 服务器版本号
实现 MCP 工具
与基于 stdio 的实现完全相同:
class OpenMeteoService {private final WebClient webClient;public OpenMeteoService(WebClient.Builder webClientBuilder) {this.webClient = webClientBuilder.baseUrl("https://api.open-meteo.com/v1").build();}(description = "根据经纬度获取天气预报")public String getWeatherForecastByLocation((description = "纬度,例如:39.9042") String latitude,(description = "经度,例如:116.4074") String longitude) {try {String response = webClient.get().uri(uriBuilder -> uriBuilder.path("/forecast").queryParam("latitude", latitude).queryParam("longitude", longitude).queryParam("current", "temperature_2m,wind_speed_10m").queryParam("timezone", "auto").build()).retrieve().bodyToMono(String.class).block();// 解析响应并返回格式化的天气信息return "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的天气信息:\n" + response;} catch (Exception e) {return "获取天气信息失败:" + e.getMessage();}}(description = "根据经纬度获取空气质量信息")public String getAirQuality((description = "纬度,例如:39.9042") String latitude,(description = "经度,例如:116.4074") String longitude) {// 模拟数据,实际应用中应调用真实APIreturn "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的空气质量:\n" +"- PM2.5: 15 μg/m³ (优)\n" +"- PM10: 28 μg/m³ (良)\n" +"- 空气质量指数(AQI): 42 (优)\n" +"- 主要污染物: 无";}
}
public
注册 MCP 工具
在应用程序入口类中注册工具:
class McpServerApplication {public static void main(String[] args) {SpringApplication.run(McpServerApplication.class, args);} public ToolCallbackProvider weatherTools(OpenMeteoService openMeteoService) {return MethodToolCallbackProvider.builder().toolObjects(openMeteoService).build();} public WebClient.Builder webClientBuilder() {return WebClient.builder();}
}
public
运行服务端
在控制台中输入命令,运行服务端:
Terminal window
mvn spring-boot:run
服务端将在 http://localhost:8080 启动。
2.3 在 Claude 中测试 mcp 服务
在上一小节中我们编写完了 MCP 服务,这些服务到底是否能正常运行呢?在 Claude Desktop 中可以测试一下。
修改配置文件,添加 weather 的配置,一定要注意 jar 包的路径必须是全路径:
{"mcpServers": {"github": {"command": "npx","args": ["-y","@modelcontextprotocol/server-github"],"env": {"GITHUB_PERSONAL_ACCESS_TOKEN": your token}},"weather": {"command": "java","args": ["-Dspring.ai.mcp.server.stdio=true","-Dspring.main.web-application-type=none","-Dlogging.pattern.console=","-jar","<修改为stdio编译之后的jar包全路径>"],"env": {}}}
}
重启 Claude 之后看到,我们编写的两个 Tool 已经被加载进来了:
输入提示词,查询今天北京的空气质量:
Claude 触发了我们自己编写的天气服务,展示了完整的数据:
上面使用了 stdio 的方式在 Claude Desktop 中使用我们自己编写的 MCP 服务,但是很可惜 Claude Desktop 不支持直接通过 SSE 模式访问,必须使用 mcp-proxy 作为中介,所以这里我们不再演示 Claude Desktop 接入 SSE 模式的 MCP 服务。
资料推荐
💡大模型中转API推荐
✨中转使用教程