
摘要
Aliware
发布 stdio 模式的 MCP Server 发布 SSE 模式的 MCP Server 开发另一个 Spring 应用作为 MCP Client 调用 MCP Server 服务 使用 Claude 桌面应用接入我们的 Java MCP Server
配置并调用 stdio 模式的 MCP Server 配置并调用 SSE 模式的 MCP Server
模型上下文协议
(Model Context Protocol)入门
Aliware
2024 年 11 月,Anthropic 公司搞了个挺有意思的新玩意 - Model Context Protocol(模型上下文协议)简称为 MCP 协议。简单来说,它就是给 AI 和各类工具数据之间搭了个标准化的”桥梁”,让开发者不用再为对接问题头疼了。
awesome-mcp-servers mcp.so
使用百度/高德地图分析旅线计算时间 接 Puppeteer 自动操作网页 使用 Github/Gitlab 让大模型接管代码仓库 使用数据库组件完成对 Mysql、ES、Redis 等数据库的操作 使用搜索组件扩展大模型的数据搜索能力
~/Library/Application Support/Claude/claude_desktop_config.json
复制
%APPDATA%\Claude\claude_desktop_config.json
复制
{ "mcpServers": { "github": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-github" ], "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "`" } } }
复制




客户端:一般指的是大模型应用,比如 Claude、通过 Spring AI Alibaba、Langchain 等框架开发的 AI 应用 服务端:连接各种数据源的服务和工具

在 Spring AI 中
使用 MCP Server
Aliware

Spring AI 应用程序:使用 Spring AI 框架构建想要通过 MCP 访问数据的生成式 AI 应用程序 Spring MCP 客户端:MCP 协议的 Spring AI 实现,与服务器保持 1:1 连接
基于 stdio 的进程间通信传输,以独立的进程运行在 AI 应用本地,适用于比较轻量级的工具。 基于 SSE(Server-Sent Events) 进行远程服务访问,需要将服务单独部署,客户端通过服务端的 URL 进行远程访问,适用于比较重量级的工具。
添加依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
</dependency>
复制
配置 MCP 服务端
spring:
main:
web-application-type: none # 必须禁用web应用类型
banner-mode: off # 禁用banner
ai:
mcp:
server:
stdio: true # 启用stdio模式
name: my-weather-server # 服务器名称
version: 0.0.1 # 服务器版本
复制
实现 MCP 工具
@Service
public class OpenMeteoService {
private final WebClient webClient;
public OpenMeteoService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder
.baseUrl("https://api.open-meteo.com/v1")
.build();
}
@Tool(description = "根据经纬度获取天气预报")
public String getWeatherForecastByLocation(
@ToolParameter(description = "纬度,例如:39.9042") String latitude,
@ToolParameter(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();
// 解析响应并返回格式化的天气信息
// 这里简化处理,实际应用中应该解析JSON
return "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的天气信息:\n" + response;
} catch (Exception e) {
return "获取天气信息失败:" + e.getMessage();
}
}
@Tool(description = "根据经纬度获取空气质量信息")
public String getAirQuality(
@ToolParameter(description = "纬度,例如:39.9042") String latitude,
@ToolParameter(description = "经度,例如:116.4074") String longitude) {
// 模拟数据,实际应用中应调用真实API
return "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的空气质量:\n" +
"- PM2.5: 15 μg/m³ (优)\n" +
"- PM10: 28 μg/m³ (良)\n" +
"- 空气质量指数(AQI): 42 (优)\n" +
"- 主要污染物: 无";
}
}
复制
注册 MCP 工具
@SpringBootApplication
public class McpServerApplication {
public static void main(String[] args) {
SpringApplication.run(McpServerApplication.class, args);
}
@Bean
public ToolCallbackProvider weatherTools(OpenMeteoService openMeteoService) {
return MethodToolCallbackProvider.builder()
.toolObjects(openMeteoService)
.build();
}
}
复制
运行服务端
mvn clean package -DskipTests
复制
添加依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-webflux-spring-boot-starter</artifactId>
</dependency>
复制
配置 MCP 服务端
server:
port: 8080 # 服务器端口配置
spring:
ai:
mcp:
server:
name: my-weather-server # MCP服务器名称
version: 0.0.1 # 服务器版本号
复制
实现 MCP 工具
@Service
public class OpenMeteoService {
private final WebClient webClient;
public OpenMeteoService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder
.baseUrl("https://api.open-meteo.com/v1")
.build();
}
@Tool(description = "根据经纬度获取天气预报")
public String getWeatherForecastByLocation(
@ToolParameter(description = "纬度,例如:39.9042") String latitude,
@ToolParameter(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();
}
}
@Tool(description = "根据经纬度获取空气质量信息")
public String getAirQuality(
@ToolParameter(description = "纬度,例如:39.9042") String latitude,
@ToolParameter(description = "经度,例如:116.4074") String longitude) {
// 模拟数据,实际应用中应调用真实API
return "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的空气质量:\n" +
"- PM2.5: 15 μg/m³ (优)\n" +
"- PM10: 28 μg/m³ (良)\n" +
"- 空气质量指数(AQI): 42 (优)\n" +
"- 主要污染物: 无";
}
}
复制
注册 MCP 工具
@SpringBootApplication
public class McpServerApplication {
public static void main(String[] args) {
SpringApplication.run(McpServerApplication.class, args);
}
@Bean
public ToolCallbackProvider weatherTools(OpenMeteoService openMeteoService) {
return MethodToolCallbackProvider.builder()
.toolObjects(openMeteoService)
.build();
}
@Bean
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
复制
运行服务端
mvn spring-boot:run
复制
{
"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": {}
}
}
}
复制



在 Spring AI Alibaba 中
集成 Mcp Client
Aliware
添加依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
</dependency>
<!-- 添加Spring AI MCP starter依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
</dependency>
复制
配置 MCP 服务器
spring:
ai:
dashscope:
# 配置通义千问API密钥
api-key: ${DASH_SCOPE_API_KEY}
mcp:
client:
stdio:
# 指定MCP服务器配置文件路径(推荐)
servers-configuration: classpath:/mcp-servers-config.json
# 直接配置示例,和上边的配制二选一
# connections:
# server1:
# command: java
# args:
# - -jar
# - path/to/your/mcp-server.jar
复制
{
"mcpServers": {
// 定义名为"weather"的MCP服务器
"weather": {
// 指定启动命令为java
"command": "java",
// 定义启动参数
"args": [
"-Dspring.ai.mcp.server.stdio=true",
"-Dspring.main.web-application-type=none",
"-jar",
"<修改为stdio编译之后的jar包全路径>"
],
// 环境变量配置(可选)
"env": {}
}
}
}
复制
编写一个启动类进行测试:
```java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
// 启动Spring Boot应用
SpringApplication.run(Application.class, args);
}
@Bean
public CommandLineRunner predefinedQuestions(
ChatClient.Builder chatClientBuilder,
ToolCallbackProvider tools,
ConfigurableApplicationContext context) {
return args -> {
// 构建ChatClient并注入MCP工具
var chatClient = chatClientBuilder
.defaultTools(tools)
.build();
// 定义用户输入
String userInput = "北京的天气如何?";
// 打印问题
System.out.println("\n>>> QUESTION: " + userInput);
// 调用LLM并打印响应
System.out.println("\n>>> ASSISTANT: " +
chatClient.prompt(userInput).call().content());
// 关闭应用上下文
context.close();
};
}
}
```
复制
mvn spring-boot:run
复制
>>> QUESTION: 北京的天气如何?
2025-03-31T17:56:17.931+08:00 DEBUG 23455 --- [mcp] [pool-1-thread-1] io.modelcontextprotocol.spec.McpSchema : Received JSON message: {"jsonrpc":"2.0","id":"60209de5-3","result":{"content":[{"type":"text","text":"\"当前天气:\\n温度: 18.6°C (体感温度: 15.1°C)\\n天气: 多云\\n风向: 南风 (4.7 km/h)\\n湿度: 18%\\n降水量: 0.0 毫米\\n\\n未来天气预报:\\n2025-03-31 (周一):\\n温度: 2.4°C ~ 19.5°C\\n天气: 多云\\n风向: 南风 (8.4 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-01 (周二):\\n温度: 7.6°C ~ 20.6°C\\n天气: 多云\\n风向: 西北风 (19.1 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-02 (周三):\\n温度: 6.9°C ~ 18.4°C\\n天气: 晴朗\\n风向: 西北风 (12.8 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-03 (周四):\\n温度: 7.0°C ~ 19.8°C\\n天气: 多云\\n风向: 南风 (16.3 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-04 (周五):\\n温度: 7.5°C ~ 21.6°C\\n天气: 多云\\n风向: 西北风 (19.6 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-05 (周六):\\n温度: 5.6°C ~ 20.7°C\\n天气: 多云\\n风向: 西风 (16.5 km/h)\\n降水量: 0.0 毫米\\n\\n2025-04-06 (周日):\\n温度: 8.4°C ~ 22.3°C\\n天气: 晴朗\\n风向: 南风 (9.4 km/h)\\n降水量: 0.0 毫米\\n\\n\""}],"isError":false}}
2025-03-31T17:56:17.932+08:00 DEBUG 23455 --- [mcp] [pool-1-thread-1] i.m.spec.McpClientSession : Received Response: JSONRPCResponse[jsonrpc=2.0, id=60209de5-3, result={content=[{type=text, text="当前天气:\n温度: 18.6°C (体感温度: 15.1°C)\n天气: 多云\n风向: 南风 (4.7 km/h)\n湿度: 18%\n降水量: 0.0 毫米\n\n未来天气预报:\n2025-03-31 (周一):\n温度: 2.4°C ~ 19.5°C\n天气: 多云\n风向: 南风 (8.4 km/h)\n降水量: 0.0 毫米\n\n2025-04-01 (周二):\n温度: 7.6°C ~ 20.6°C\n天气: 多云\n风向: 西北风 (19.1 km/h)\n降水量: 0.0 毫米\n\n2025-04-02 (周三):\n温度: 6.9°C ~ 18.4°C\n天气: 晴朗\n风向: 西北风 (12.8 km/h)\n降水量: 0.0 毫米\n\n2025-04-03 (周四):\n温度: 7.0°C ~ 19.8°C\n天气: 多云\n风向: 南风 (16.3 km/h)\n降水量: 0.0 毫米\n\n2025-04-04 (周五):\n温度: 7.5°C ~ 21.6°C\n天气: 多云\n风向: 西北风 (19.6 km/h)\n降水量: 0.0 毫米\n\n2025-04-05 (周六):\n温度: 5.6°C ~ 20.7°C\n天气: 多云\n风向: 西风 (16.5 km/h)\n降水量: 0.0 毫米\n\n2025-04-06 (周日):\n温度: 8.4°C ~ 22.3°C\n天气: 晴朗\n风向: 南风 (9.4 km/h)\n降水量: 0.0 毫米\n\n"}], isError=false}, error=null]
复制
添加依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-webflux-spring-boot-starter</artifactId>
</dependency>
复制
配置 MCP 服务器
spring:
ai:
dashscope:
api-key: ${DASH_SCOPE_API_KEY}
mcp:
client:
sse:
connections:
server1:
url: http://localhost:8080 #服务地址
复制
使用 MCP 客户端
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder,
ToolCallbackProvider tools,
ConfigurableApplicationContext context) {
return args -> {
// 构建ChatClient并注入MCP工具
var chatClient = chatClientBuilder
.defaultTools(tools)
.build();
// 使用ChatClient与LLM交互
String userInput = "北京的天气如何?";
System.out.println("\n>>> QUESTION: " + userInput);
System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(userInput).call().content());
context.close();
};
}
}
复制
mvn spring-boot:run
复制
Caused by: java.lang.IllegalStateException: Multiple tools with the same name (spring-ai-mcp-client-getWeatherForecastByLocation, spring-ai-mcp-client-getAirQuality)
at org.springframework.ai.mcp.SyncMcpToolCallbackProvider.validateToolCallbacks(SyncMcpToolCallbackProvider.java:126) ~[spring-ai-mcp-1.0.0-20250325.064812-147.jar:1.0.0-SNAPSHOT]
at org.springframework.ai.mcp.SyncMcpToolCallbackProvider.getToolCallbacks(SyncMcpToolCallbackProvider.java:110) ~[spring-ai-mcp-1.0.0-20250325.064812-147.jar:1.0.0-SNAPSHOT]
at org.springframework.ai.autoconfigure.mcp.client.McpClientAutoConfiguration.toolCallbacksDeprecated(McpClientAutoConfiguration.java:196) ~[spring-ai-mcp-client-spring-boot-autoconfigure-1.0.0-M6.jar:1.0.0-M6]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.2.0.jar:6.2.0]
... 23 common frames omitted
复制
SseHttpClientTransportAutoConfiguration
和
SseWebFluxTransportAutoConfiguration
。这两个自动配置类提供了同步和异步两种方式,本身应该是互斥的,但是 Spring AI 对于互斥的处理上出了问题,导致两个自动配置类都会加载。


@SpringBootApplication(exclude = {
org.springframework.ai.autoconfigure.mcp.client.SseHttpClientTransportAutoConfiguration.class
})
public class Application {
...
复制
mvn spring-boot:run
复制

在 Spring AI Alibaba 的
Open Manus 中体验 MCP
Aliware

添加依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
<version>${spring-ai.version}</version>
</dependency>
复制
配置 MCP 服务器

{
"mcpServers": {
"baidu-map": {
"command": "npx",
"args": [
"-y",
"@baidumap/mcp-server-baidu-map"
],
"env": {
"BAIDU_MAP_API_KEY": "your_baidu_AK"
}
}
}
}
复制
使用 MCP 工具
public LlmService(ChatModel chatModel, ToolCallbackProvider toolCallbackProvider) {
this.chatModel = chatModel;
this.planningChatClient = ChatClient.builder(chatModel)
.defaultSystem(PLANNING_SYSTEM_PROMPT)
.defaultAdvisors(new MessageChatMemoryAdvisor(planningMemory))
.defaultAdvisors(new SimpleLoggerAdvisor())
.defaultTools(ToolBuilder.getPlanningAgentToolCallbacks())
.defaultTools(toolCallbackProvider)
.build();
this.chatClient = ChatClient.builder(chatModel)
.defaultSystem(MANUS_SYSTEM_PROMPT)
.defaultAdvisors(new MessageChatMemoryAdvisor(memory))
.defaultAdvisors(new SimpleLoggerAdvisor())
.defaultTools(ToolBuilder.getManusAgentToolCalls())
.defaultTools(toolCallbackProvider)
.defaultOptions(OpenAiChatOptions.builder().internalToolExecutionEnabled(false).build())
.build();
this.finalizeChatClient = ChatClient.builder(chatModel)
.defaultSystem(FINALIZE_SYSTEM_PROMPT)
.defaultAdvisors(new MessageChatMemoryAdvisor(finalizeMemory))
.defaultAdvisors(new SimpleLoggerAdvisor())
.build();
}
复制
测试效果
Steps:
0. [ ] [MANUS] 使用百度地图的地理编码服务获取北京市和上海市的经纬度坐标
1. [ ] [MANUS] 使用百度地图的路线规划服务计算从北京市到上海市的驾车路线
2. [ ] [MANUS] 分析并提供最终的路线信息,包括距离、预计耗时等
复制
Here is a summary of what we accomplished in this step:
- For Beijing, we received the coordinates: Longitude (lng): 116.4133836971231, Latitude (lat): 39.910924547299565.
- For Shanghai, we received the coordinates: Longitude (lng): 121.48053886017651, Latitude (lat): 31.235929042252014.
复制
Distance: The total distance of the route is 1,223,200 meters (approximately 1,223 kilometers).
Duration: The estimated travel time is 50,592 seconds (approximately 14 hours and 3 minutes).
复制
总结
Aliware
文章转载自阿里巴巴中间件,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
Spring 实现数据库读写分离
听溪
42次阅读
2025-03-30 23:19:06
java项目选择云服务器怎么选?
云知识CLOUD
40次阅读
2025-04-09 20:02:37
Redis geo 实战:“附近的人”实现,打造社交的新维度
老王两点中
29次阅读
2025-04-11 09:02:30
Java数据库连接池学习
淡定
25次阅读
2025-04-14 22:46:26
瞧瞧别人家的判空,那叫一个优雅!
jinchanchanwaji
24次阅读
2025-04-03 14:56:21
从 Java 到 Go:面向对象的巨人与云原生的轻骑兵
京东云开发者
21次阅读
2025-04-25 11:41:37
【阿斯加德特快】WebFlux:Spring召唤雷霆战甲!每秒百万请求?索尔:我还没发力呢!
让天下没有难学的编程
19次阅读
2025-04-23 14:33:56
Java萌新修炼手册⑥:面向对象の修仙奥义——从"散修"到"宗门大佬"的基因飞升!
让天下没有难学的编程
18次阅读
2025-04-25 10:10:40
Java萌新修炼手册⑤:数组の千层套路——从"鸽子笼"到"摩天楼"的进阶之路!
让天下没有难学的编程
16次阅读
2025-04-25 10:10:41
Java萌新修炼手册④:流程控制の三十六计——让代码学会"见风使舵"!
让天下没有难学的编程
16次阅读
2025-04-23 14:33:55