
🚀 欢迎来到我的CSDN博客:Optimistic _ chen
✨ 一名热爱技术与分享的全栈开发者,在这里记录成长,专注分享编程技术与实战经验,助力你的技术成长之路,与你共同进步!
🚀我的专栏推荐:
| 专栏 | 内容特色 | 适合人群 |
|---|---|---|
| 🔥C语言从入门到精通 | 系统讲解基础语法、指针、内存管理、项目实战 | 零基础新手、考研党、复习 |
| 🔥Java基础语法 | 系统解释了基础语法、类与对象、继承 | Java初学者 |
| 🔥Java核心技术 | 面向对象、集合框架、多线程、网络编程、新特性解析 | 有一定语法基础的开发者 |
| 🔥Java EE 进阶实战 | Servlet、JSP、SpringBoot、MyBatis、项目案例拆解 | 想快速入门Java Web开发的同学 |
| 🔥Java数据结构与算法 | 图解数据结构、LeetCode刷题解析、大厂面试算法题 | 面试备战、算法爱好者、计算机专业学生 |
| 🔥Redis系列 | 从数据类型到核心特性解析 | 项目必备 |
🚀我的承诺:
✅ 文章配套代码:每篇技术文章都提供完整的可运行代码示例
✅ 持续更新:专栏内容定期更新,紧跟技术趋势
✅ 答疑交流:欢迎在文章评论区留言讨论,我会及时回复(支持互粉)
🚀 关注我,解锁更多技术干货!
⏳ 每天进步一点点,未来惊艳所有人!✍️ 持续更新中,记得⭐收藏关注⭐不迷路 ✨
📌 标签:#技术博客 #编程学习 #Java #C语言 #算法 #程序员
文章目录
- 前言
- 什么是MCP
- [MCP Java SDK架构](#MCP Java SDK架构)
-
- Transport传输协议
- [MCP server](#MCP server)
- [MCP Client](#MCP Client)
- MCP使用
- [自定义MCP Server](#自定义MCP Server)
-
- [使用Stdio自定义MCP Server](#使用Stdio自定义MCP Server)
- [使用SSE自定义MCP Server](#使用SSE自定义MCP Server)
- 完结撒花!🎉
前言
当今快速发展的AI应用生态中,我们从优化提示词到使用Tool Calling突破大模型语言生成的界限,完成调用外部系统的实际任务。但是随着工具数量的增长和应用场景的复杂化,传统的Tool Calling实现方式暴露出一系列挑战:
- 工具接口格式不统一
- 模型需硬编码工具定义
- ...
为了解决这些问题,一个新的概念------MCP出现了。
什么是MCP
MCP(Model Context Protocol)模型上下文协议:事实上,MCP并不是代替Tool Calling的产物,而是为其提供一个统一、可扩展、跨平台的连接基础设施。
简单来说,MCP是Tool Calling的管理者。
- Tool Calling:模型决定要不要调用工具,调哪个工具,
- MCP:规定如何描述工具,如何发起调用,如何传递结果
有了MCP,AI只需要学习一种格式,MCP Server 负责翻译。
MCP Java SDK架构
MCP Java SDK提供MCP的Java实现,⽀持通过同步和异步通信模式与AI模型及⼯具进⾏标准化交互。

- Client/Server分别表示请求的发起者和请求的接收者(顾客和后厨)
- Session表示管理会话生命周期(订单管理系统)
- Transport表示消息传递的方式(手机订餐+骑手送餐)
Transport传输协议
MCP Java SDK提供了多种"通信⽅式",让AI应⽤(客⼾端)能灵活地与各种⼯具服务(服务器)进⾏对话
目前支持三种传输方式:
- 基于Stdio 的进程间通信传输协议
通过标准输⼊/输出(stdin和stdout)在两个程序之间传消息,⾼效直接 - 基于Java HttpClient的SSE客户端传输协议
基于JavaHttpClient发起HTTP请求,并接收服务端持续发送的事件流 - WebFlux SSE客户端传输协议
基于WebFlux的⾮阻塞、响应式编程模型,处理SSE流
MCP server
作为MCP协议的具体服务端实现,是对外提供特定功能的服务程序,我们可以直接去MCP Server社区去查找调用你想要的功能,社区中活跃着大量技术爱好者,致力于为MCP用户提供交流、资源共享等服务。
- GitHub MCP Registry:htttps://github.com/mcp/registry
- MCP Flow:https://mcpflow.io/home
- 火山引擎 MCP 广场:www.volcengine.com/mcp-marketplace
MCP Client
有了MCP 服务端后,如何在代码中调用这些服务,这就需要借助MCP 客户端。
作为MCP客户端是连接本地开发环境或应用与远程MCP服务器之间的桥梁,不同客户端对MCP协议的支持程度各不相同,⽤⼾可以根据⾃⼰的需求选择合适的客⼾端。
MCP使用
在使⽤MCPClient之前,通常需要先运⾏⼀个或多个MCPServer实例.⽽许多MCPServer是通过npx或uv命令启动的,在开始使⽤前,必须正确配置相应的运⾏环境。
准备一个MCP Server:可以到各大网站获取相应的配置
yaml
{
"mcpServers": {
"baidu-map": {
"command": "npx",
"args": [
"-y",
"@baidumap/mcp-server-baidu-map"
],
"env": {
"BAIDU_MAP_API_KEY": "xxx"
}
}
}
}
准备好MCP Server,这里通过Cursor来展示MCP的使用:
除了上述的客户端之外,我们也可以通过Spring AI代码来接入这些资源
首先,采用SpringAI-Alibaba来调用AI服务,引入依赖
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-ai-project</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mcp-client-demo</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<!-- mcp client-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-bom</artifactId>
<version>1.0.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
配置文件application
yaml
spring:
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY}
mcp:
client:
request-timeout: 60000
stdio:
servers-configuration: classpath:/mcp/mcp-servers-config.json
同时引入百度地图的配置:mcp/mcp-servers-config.json
yaml
{
"mcpServers": {
"baidu-map": {
"command": "npx.cmd",
"args": ["-y", "@baidumap/mcp-server-baidu-map"],
"env": {
"BAIDU_MAP_API_KEY": "nLpm876DutMXGl6gEwzJksuya0gbfk0B"
}
}
}
}
在controller添加该工具
java
@RestController
@RequestMapping("/chat")
public class ChatController {
private ChatClient chatClient;
public ChatController(DashScopeChatModel chatModel, ToolCallbackProvider toolCallbackProvider) {
this.chatClient = ChatClient.builder(chatModel)
.defaultToolCallbacks(toolCallbackProvider)
.build();
}
@RequestMapping("/generate")
public String generate(String message){
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
ToolCallbackProvider 是 Spring AI 中用于向 AI 模型注册和提供可用工具(MCP Server 的工具)的核心接口。所以,之后只要有MCP配置进来,ToolCallbackProvider 就可以调用,完美解决了Tool Calling中各个工具接口不同的情况,实现动态工具组合。
自定义MCP Server
我们知道MCP有两种通信方式:Stdio 和 Streamable HTTP

前面提到的两个协议是Stdio 和 SSE,但是在 2025年3月26日的协议更新后,官方已用更强大的 Streamable HTTP 取代 SSE(解决了SSE连接容易断开的痛点)
controller/ChatController
java
package com.zc.mcp.controller;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/chat")
public class ChatController {
private ChatClient chatClient;
public ChatController(DashScopeChatModel chatModel, ToolCallbackProvider toolCallbackProvider) {
this.chatClient = ChatClient.builder(chatModel)
.defaultToolCallbacks(toolCallbackProvider)
.build();
}
@RequestMapping("/generate")
public String generate(String message){
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
application.yml
yaml
spring:
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY}
mcp:
client:
request-timeout: 60000
stdio:
servers-configuration: classpath:/mcp/mcp-servers-config.json
/mcp/mcp-servers-config.json
json
{
"mcpServers": {
"stdio-server": {
"command": "java",
"args": [
"-Dfile.encoding=UTF-8",
"-Dspring.ai.mcp.server.stdio=true",
"-Dlogging.pattern.console=",
"-jar",
"E:\\springAI\\mcp\\mcp-stdio-server\\target\\mcp-stdio-server-1.0-SNAPSHOT.jar"
]
}
}
}
使用Stdio自定义MCP Server

Service/WeatherService
java
package com.zc.mcp.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Service
@Slf4j
public class WeatherService {
private final Map<String, WeatherInfo> weatherCache = new ConcurrentHashMap<>();
public WeatherService() {
// 初始化天气数据
weatherCache.put("北京", new WeatherInfo("晴转多云", "22~28", "南风2级", "78"));
weatherCache.put("上海", new WeatherInfo("小雨", "18~24", "东风3级", "52"));
weatherCache.put("广州", new WeatherInfo("晴朗", "25~33", "微风", "45"));
weatherCache.put("深圳", new WeatherInfo("多云", "24~30", "东北风2级", "60"));
}
@Tool(description = "查询指定城市的天气信息,返回天气状况、温度范围、风力、空气质量")
public String queryWeather(
@ToolParam(description = "城市名称,如:北京、上海、广州、深圳") String city) {
log.info("[HTTP MCP] queryWeather 调用,城市: {}", city);
if (!weatherCache.containsKey(city)) {
return String.format("未找到「%s」的天气信息,支持的城市:%s",
city, weatherCache.keySet());
}
WeatherInfo info = weatherCache.get(city);
return String.format("""
🌍 %s天气报告
─────────────────
☁️ 天气:%s
🌡️ 温度:%s°C
💨 风力:%s
🏭 AQI:%s
─────────────────
🕐 更新时间:%s
""",
city, info.weather, info.temp, info.wind, info.aqi,
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
);
}
record WeatherInfo(String weather, String temp, String wind, String aqi) {}
}
config/ToolConfig
java
package com.zc.mcp.config;
import com.zc.mcp.service.WeatherService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ToolConfig {
@Bean
public ToolCallbackProvider getWeather(WeatherService weatherService){
return MethodToolCallbackProvider.builder()
.toolObjects(weatherService)
.build();
}
}
application.yml
yaml
spring:
ai:
mcp:
server:
name: stdio-server
version: 0.0.1
main:
web-application-type: none
banner-mode: off
生成jar包


使用SSE自定义MCP Server
注意:使用SSE传输策略时,依赖的主要选择 是取决于你是作为客户端还是服务端,以及是使用传统的同步SSE 还是WebFlux响应式SSE。
| Starter | 角色 | 被谁调用 |
|---|---|---|
spring-ai-starter-mcp-server |
MCP Server | 本地MCP Client(通过Stdio) |
spring-ai-starter-mcp-server-webmvc |
MCP Server | 远程MCP Client(通过HTTP/SSE) |
spring-ai-starter-mcp-server-webflux |
MCP Server | 远程MCP Client(通过HTTP/SSE/WebFlux) |
spring-ai-starter-mcp-client |
MCP Client | Stdio/SSE客户端 |
spring-ai-starter-mcp-client-webflux |
MCP Client | WebFlux客户端 |
在Web项目中添加spring-ai-starter-mcp-server webflux依赖会导致MCP端点(/sse)失效,这是因为项目中同时存在org.springframework.web.servlet.DispatcherServlet和org.springframework.web.reactive.DispatcherHandler。根本原因是:当DispatcherServlet(Servlet)和DispatcherHandler(Reactive)共存时,Spring Boot会默认优先使用Servlet堆栈启动Web服务。这样应用将以传统的Tomcat(或Jetty/Undertow)服务器运行,而非WebFlux所需的Netty服务器,导致专属于WebFlux的/sse端点无法正常工作。
可以通过在配置文件中设置解决:
yaml
server:
port: 8081
spring:
ai:
mcp:
server:
name: sse-server
version: 0.0.1
main:
web-application-type: reactive
SSE的pom.xml文件
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mcp</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>mcp-sse</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<dependencies>
<!-- Web 容器支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
service实现工具的业务逻辑,config将工具暴露给MCP Server.(代码和Stdio类似)
config 中的 MethodToolCallbackProvider 就像一个"扫描器",把 @Tool 方法收集起来"交"给MCP Server.
SSE定义MCP Server后,启动项目,在Cursor中配置好服务后,就能直接使用了。
yaml
{
"mcpServers": {
"sse-server":{
"url":"http://127.0.0.1:8081/sse"
}
}
}

想要在SpringAI中作为MCP Client调用该工具,注意controller的细节
java
@RestController
@RequestMapping("/chat")
public class ChatController {
private final ChatClient chatClient;
@Autowired
public ChatController(DashScopeChatModel chatModel,
SyncMcpToolCallbackProvider mcpToolProvider) {
// DashScopeChatModel chatModel:阿里云通义千问的模型实例,负责实际调用大模型 API
// SyncMcpToolCallbackProvider mcpToolProvider:MCP 工具提供者,负责将远程 MCP Server 的工具转换成 Spring AI 可用的工具
this.chatClient = ChatClient.builder(chatModel)//告诉 ChatClient 使用哪个大模型
.defaultToolCallbacks(mcpToolProvider.getToolCallbacks()) // 把从 MCP 工具提供者中获取所有远程工具设置为 ChatClient 的默认工具
.build();
}
@RequestMapping("/generate")
public String generate(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}

完结撒花!🎉

如果这篇博客对你有帮助,不妨点个赞支持一下吧!👍
你的鼓励是我创作的最大动力~
✨ 想获取更多干货? 欢迎关注我的专栏 → optimistic_chen
📌 收藏本文,下次需要时不迷路!
我们下期再见!💫 持续更新中......
悄悄说:点击主页有更多精彩内容哦~ 😊
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7471a32ba1fc4954b6ae528ef5b66475.png