Spring AI MCP 实战:打通 AI 与外部服务的边界
我们之前通过工具调用给 AI 应用加了不少能力,但每次加新功能都要写一堆代码。有没有更简单的方式?能不能像插 USB 一样,需要什么能力直接插上就能用?
MCP 就是来做这件事的。
本文先讲 MCP 的核心概念和原理,然后介绍三种使用方式,最后基于 Spring AI 框架实战开发 MCP 客户端和服务端,帮你掌握 MCP 的架构原理和最佳实践。
友情提示:由于 AI 技术更新速度很快,教程的部分细节可能会失效,请大家重点学习思路和方法,不要因为实操和教程不一致就过于担心,要学会自己阅读官方文档并查阅资料,多锻炼自己解决问题的能力。
一、需求分析
目前我们的咖啡店智能客服已经具备知识问答和工具调用能力。现在再加一个实用功能:当用户问“你们离我有多远”时,客服能根据用户的位置,计算出距离并推荐最近的门店。
怎么实现?
按照之前学习的知识,大概有三种思路:
- 依赖大模型自身能力:大模型可以理解“距离”这个概念,但它不知道用户在哪,也不知道门店的具体位置。
- 利用 RAG 知识库:把门店地址录入知识库,AI 可以查,但无法计算实时距离,也不知道用户当前位置。
- 利用工具调用:开发一个根据用户位置查询附近门店并计算距离的工具,调用高德地图 API 获取真实数据。准确度高,但每次都要写工具。
第三种方案效果最好。但既然要调用第三方 API,为什么不能直接接入现成的服务?
这就是 MCP 要解决的问题——让地图服务直接提供给 AI 调用,咖啡店客服只需要接入,不用自己开发位置查询工具。
二、MCP 必知必会
2.1 什么是 MCP?

MCP(Model Context Protocol,模型上下文协议)是由 Anthropic 在 2024 年 11 月提出的一种开放标准。它的核心目标是增强 AI 与外部系统的互操作能力,为 AI 模型连接外部数据源和工具提供标准化的方式。
你可以把 MCP 想象成 AI 应用的 USB 接口。就像 USB 为设备连接外设提供了统一的插拔标准,MCP 为 AI 模型连接不同的数据源和工具提供了标准化的方法。如今 MCP 的市场影响力还在持续扩大,到 2026 年 3 月,其 SDK 月下载量已突破 9700 万次,主流 AI 提供商几乎都给予了正式支持。
MCP 主要解决三个问题:
- 增强 AI 能力:AI 应用可以轻松接入别人提供的服务,实现网页搜索、数据库查询、第三方 API 调用等功能。
- 统一标准:MCP 本身不提供服务,只是定义了一套规范。服务提供者和使用者都去遵守同一套标准,大幅降低开发者的理解和接入成本。
- 打造服务生态:如果大家都把自己的能力做成标准化的 MCP 服务对外开放,就等于构建了一个服务市场,开发者可以按需选用,不用重复开发。目前已有超过 18000 个 MCP 服务可供使用。
标准可以造就生态。其实这并不新鲜了,前端同学可以想想NPN包,后端同学可以想想Maven仓库还有Docker镜像源,不懂编程的同学想想手机应用市场,应该就能理解了。
目前已经有不少 MCP 服务市场,开发者可以在这些平台上找到各种现成的 MCP 服务:
- MCP.so:较为主流,收录了超过 5000 个 MCP 服务
- GitHub Awesome MCP Servers: 开源 MCP服务集合
- 阿里云百炼MCP服务市场:阿里云提供的 MCP 服务平台,整合了大量企业级服务
- SpringAl Alibaba的MCP服务市场
- Glama.ai MCP服务
目前超过 18000 个 MCP 服务已经发布,覆盖了搜索、数据库、浏览器自动化、图片生成、地图等多个领域。其中绝大多数 MCP 服务市场主要提供本地下载 MCP 服务端代码并运行的方式,毕竟部署 MCP 服务也是需要成本的。
开源社区MCP市场:MCP.so

2.2 MCP 架构
MCP 采用经典的客户端-服务器架构,主要包含三个核心角色:

- Host(主机) :希望访问 MCP 服务的程序,比如 Claude Desktop、IDE、AI 工具,或者部署在服务器上的你自己的项目。MCP Client 内嵌在 Host 中,负责与 Server 建立通信。
- Client(客户端) :内嵌在主机中,负责和服务端建立连接并发送请求。它能自动匹配服务器的协议版本、确认可用功能、管理通信状态,还能发现和使用服务端提供的各种工具。
- Server(服务端) :负责提供具体的工具、资源和功能。它处理客户端的请求,解析协议,执行对应的业务逻辑,然后把结果返回。
这种设计的核心好处是客户端和服务端完全解耦——不管服务端是用什么语言开发的,客户端都能调用,不同开发语言的开发者可以协作构建统一的 AI 生态。
2.3 SDK 三层架构
如果要在程序中使用 MCP 或开发 MCP 服务,需要引入 MCP 官方的 SDK。MCP Java SDK 的架构主要分为三层:

- 客户端/服务器层(Client/Server Layer) :提供
McpClient和McpServer两个核心接口。McpClient负责处理客户端操作,而McpServer管理服务端的协议操作。两者均通过McpSession进行通信管理。 - 会话层(Session Layer) :通过
DefaultMcpSession的实现,管理通信模式与状态,保证消息的可靠传输。 - 传输层(Transport Layer) :负责 JSON-RPC 消息的序列化与反序列化,支持多种传输协议实现,如 Stdio、HTTP over SSE 等。这一层决定了数据如何通过网络或本地系统传输。
2.4 传输机制
MCP 的传输机制非常灵活,从网络协议栈的角度看,MCP 是应用层协议。从设计上主要分为数据层和传输层两个维度:数据层基于 JSON-RPC 2.0 标准,定义了工具调用、资源访问等操作的请求与响应消息结构;传输层则负责实际的数据传输工作。
MCP 支持两种传输机制:
- Stdio(标准输入输出):通过进程间的标准输入输出流进行通信。适用于本地进程间通信,比如同一台机器上的客户端与服务器通信。不依赖网络协议,是操作系统直接提供的进程间通信机制。适合本地开发调试、轻量级工具和 IDE 插件的场景。
- SSE(Server-Sent Events):客户端使用 HTTP POST 发送请求,服务器通过 SSE 流式返回响应。适用于远程网络通信,客户端与服务端分布在不同的主机上。基于 TCP 协议,适合部署在云端的远程服务和分布式系统。
客户端和服务端需要经过标准的连接建立流程之后,才能正常交换信息。如果选择 Stdio 传输,客户端通过命令行启动服务端子进程;如果选择 SSE 传输,客户端通过 HTTP 与远程服务端建立连接。无论哪种方式,双方都需要先完成协议版本协商和能力交换,然后才能开始正常的请求-响应通信。
客户端可以通过不同传输方式调用不同的 MCP 服务,可以是本地的,也可以是远程的,这种灵活性让 MCP 既能支持本地开发调试,也能支持云端生产环境的高并发部署。
2.5 核心概念
很多人以为 MCP 协议就只能提供工具给别人调用,但实际上 MCP 的能力远不止这些。按照官方定义,MCP 总共有 6 个核心概念。日常开发中最实用的是前三个:
- Resources(资源) :服务端可以向客户端提供各种数据,比如文本、文件、数据库记录、API 响应。资源是只读的,AI 可以基于这些资源来获得更丰富的上下文,但不能修改资源内容。
- Prompts(提示词) :服务端可以定义可复用的提示词模板和工作流,供客户端直接使用。它的作用是标准化常见的 AI 交互模式。
- Tools(工具) :这是 MCP 中最实用的特性。服务端把可调用的函数暴露给客户端,AI 模型可以执行计算、查询信息,或者和外部系统交互。
- Sampling(采样) :允许服务端通过客户端向 AI 模型发起生成请求(反向请求),实现复杂智能代理行为。
- Roots(根目录) :定义了服务器可以访问的文件系统位置,是 MCP 协议的安全机制,用于限制访问范围。
- Transports(传输) :也就是上面提到的 Stdio 和 SSE,负责实际的数据传输。
在 Spring AI 的 MCP 开发中,我们主要关注 Tools,其他概念了解即可。如果要进一步学习,可以去查阅官方文档。
三、Spring AI MCP 客户端开发
客户端的演示我们使用MCP.so平台的高德地图 MCP 工具为例:

3.1 引入依赖
Spring AI 提供了两种客户端 Starter,分别支持普通同步调用和响应式编程,可以根据实际需要选择合适的依赖。
spring-ai-starter-mcp-client:核心启动器,提供基于标准输入输出(Stdio)和基于 HTTP 的 SSE 传输支持,适合大多数场景。spring-ai-starter-mcp-client-webflux:基于 WebFlux 的响应式 SSE 传输实现,适合需要异步流式处理或高并发的场景。
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
<version>1.0.0</version>
</dependency>
3.2 配置 MCP 服务
在项目 resources 目录下新建 mcp-servers.json 配置文件,定义需要使用的 MCP 服务:
{
"mcpServers": {
"amap-maps": {
"command": "npx",
"args": ["-y", "@amap/amap-maps-mcp-server"],
"env": {
"AMAP_MAPS_API_KEY": "你的高德地图API Key"
}
}
}
}
这个配置告诉 Spring AI:
- 我们要接入一个名为
amap-maps的 MCP 服务 - 通过
npx命令启动这个服务(需要本地有 Node.js 环境) -y参数表示自动确认,@amap/amap-maps-mcp-server是高德地图官方发布的 MCP 服务包名- 通过环境变量
AMAP_MAPS_API_KEY传入你在高德开放平台申请的 API Key
关于 API Key:去高德开放平台注册账号,申请一个 Web 服务类型的 API Key,替换上面的占位符即可。
然后在 application.yml 中添加配置:
spring:
ai:
mcp:
client:
enabled: true
stdio:
servers-configuration: classpath:mcp-servers.json
3.3 在代码中使用
在 Spring Boot 启动时,Spring AI 的** MCP 自动配置 **会做以下几件事:
- 读取
mcp-servers.json中的配置 - 通过
npx命令启动高德 MCP 服务的子进程(通过 Stdio 通信) - 建立客户端与这个子进程之间的连接
- 扫描服务端提供了哪些工具,把每个工具自动封装成
ToolCallback对象 - 把所有这些
ToolCallback收集起来,注入成一个ToolCallbackProviderBean
因此在业务代码中,只需要注入并使用它就行:
@Component
@Slf4j
public class CoffeeApp {
private final ChatClient chatclient;
@Autowired
private VectorStore coffeeVectorStore;
@Autowired
private ToolCallbackProvider toolCallbackProvider; //注入MCP工具
private static final String SYSTEM_PROMPT = """
你是“醒石咖啡”的智能客服助手。你的职责是友好、专业地回答顾客关于门店信息、饮品菜单、优惠活动、服务流程、投诉建议等常规问题。
回答原则:
1. 优先使用知识库中的标准答案,若无法确定则主动建议顾客联系门店或查看官方小程序 https://blog.xinxinnote.tech。
2. 对于员工内部制度(如奖惩、排班)、食品安全事故、法律纠纷等敏感问题,仅提供基础指引并转人工处理。
3. 不编造任何超出已知范围的优惠、价格或库存信息。
4. 保持礼貌、耐心,语气亲切但不过度热情。
禁止回答的内容:
- 顾客的个人隐私信息(如身份证号、银行卡号)
- 对竞争对手的负面评价
- 超出咖啡店业务范围的问题(如医疗建议、投资理财)
当不确定时,统一回复:“您好,这个问题我需要帮您转接人工客服或您可到店咨询,感谢理解!”
""";
public CoffeeApp(ChatModel dashscopeChatModel) {
//初始化具有记忆能力的ChatClient
MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(new InMemoryChatMemoryRepository())
.maxMessages(20)
.build();
this.chatclient = ChatClient.builder(dashscopeChatModel)
.defaultSystem(SYSTEM_PROMPT) //系统提示词
.defaultAdvisors(
MessageChatMemoryAdvisor.builder(chatMemory).build(),
new MyLoggerAdvisor()
)
.build();
}
/**
* 支持调用MCP能力
*
* @return
*/
public String chatWithMcp(String message, String chatId) {
ChatResponse chatResponse = chatclient.prompt()
.user(message)
.advisors(spec -> spec.param(ChatMemory.CONVERSATION_ID, chatId))
.advisors(new MyLoggerAdvisor()) //开启日志
.advisors(CustomRAGAdvisorFactory.createRagCustomAdvisor(coffeeVectorStore, null))
.toolCallbacks(toolCallbackProvider)
.call()
.chatResponse();
String content = chatResponse.getResult().getOutput().getText();
log.info("content: {}", content);
return content;
}
}
ToolCallbackProvider 已经被 Spring AI 自动扫描并注册好了。通过 .tools(toolCallbackProvider) 这一行,所有高德 MCP 服务提供的工具(比如附近搜索、地理编码、距离计算等)都被一次性注册给了 ChatClient。用户提问时,AI 模型会自主判断是否需要调用哪个工具来完成回答。
3.4 测试效果
写一个简单的测试来验证:
//测试代码
@SpringBootTest
class CoffeeAppTest {
@Autowired
private CoffeeApp coffeeApp;
@Test
void chatWithMcp() {
String chatId = UUID.randomUUID().toString();
String message = "你们店在上海哪个位置?离我这里有多远?我在虹桥火车站";
String answer = coffeeApp.chatWithMcp(message, chatId);
Assertions.assertNotNull(answer);
}
}
AI 会这样处理流程:
- 分析问题,判断需要用到地图搜索工具
- 调用高德 MCP 服务提供的"附近搜索"工具,传入"虹桥火车站"作为位置参数和"咖啡店"作为搜索关键词
- 高德 MCP 服务通过 API Key 调用高德地图接口,返回咖啡店列表
- AI 把返回的 JSON 数据整理成友好的推荐语,返回给用户

整个过程不需要手动处理 HTTP 请求,不需要解析 JSON 响应,不需要写工具调用代码。MCP 服务把这一切都封装好了,Spring AI 负责对接,AI 负责决策。
四、Spring AI MCP 服务端开发
如果想把你自己写的工具暴露给其他人用,可以把工具封装成一个 MCP 服务,让别人也能通过标准协议接入。
4.1 引入依赖
Spring AI 提供了多种 MCP 服务端 Starter,根据应用场景选择:
spring-ai-starter-mcp-server:核心服务端启动器,提供 Stdio 传输支持,不需要额外的 Web 依赖。spring-ai-starter-mcp-server-webmvc:基于 Spring MVC 的 SSE 传输实现,兼容传统的 Servlet 环境。spring-ai-starter-mcp-server-webflux:基于 WebFlux 的响应式 SSE 传输实现,支持异步流式处理。
如果服务端需要接收客户端通过网络远程发起调用,建议使用 spring-ai-starter-mcp-server-webmvc;如果只需要在本机通过 Stdio 被调用,spring-ai-starter-mcp-server 就够用了。
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
4.2 配置服务
在 application.yml 中添加 MCP 服务端配置:
spring:
ai:
mcp:
server:
name: webmvc-mcp-server
version: 1.0.0
stdio: false
type: SYNC
sse-endpoint: /sse # SSE 端点路径
sse-message-endpoint: /mcp/message # SSE 消息端点路径
4.3 开发服务
开发 MCP 服务端的方式跟之前开发工具调用几乎一样——直接用 @Tool 注解标记服务类中的方法。
@Slf4j
@Component
public class TimeTool {
@Tool(description = "获取当前精确的日期和时间(包括年月日、时分秒)。当用户的问题涉及到现在、今天、当前时刻、倒计时、截止时间等需要基于当前时间进行计算的场景时,必须调用此工具进行计算")
public String getCurrentTimeByZoneId(
@ToolParam(description = "时区id,比如 Asia/Shanghai") String zoneId) {
log.info("TimeTool.getTimeByZoneId 调用入参:{}", zoneId);
ZoneId zid = ZoneId.of(zoneId);
ZonedDateTime now = ZonedDateTime.now(zid);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatTime = now.format(dtf);
log.info("TimeTool.getTimeByZoneId 调用返回值:{}", formatTime);
return formatTime;
}
}
4.4 注册工具
在 Spring Boot 项目启动时,通过配置类注册 ToolCallbackProvider Bean:
@Configuration
public class MCPConfig {
@Bean
public ToolCallbackProvider getTimeByZoneId(TimeTool timeTool) {
return MethodToolCallbackProvider.builder()
.toolObjects(timeTool) // 注册工具
.build();
}
}
这样,别人就可以通过 Stdio 或 SSE 的方式接入你的 MCP 服务,调用你提供的工具了。如果使用 Stdio 传输,客户端会在本地启动一个新的子进程来运行你的服务端程序;如果使用 SSE 传输,客户端会通过 HTTP 远程调用。
我们只需要把服务端打包成可执行的 JAR,并告知客户端启动命令。客户端只需要在配置 JSON 中填入启动命令,就能像使用任何第三方 MCP 服务一样使用你提供的工具。
总结
MCP 从本质上解决了 AI 应用接入外部能力时的重复开发问题。它的核心价值可以概括为"一次开发,到处调用",让工具开发者专注于把一件事做精,让 AI 应用开发者只关心怎么用好这些能力。
回顾整个过程,在 Spring AI框架中使用 MCP 和开发 MCP 是一件比较容易的事情,实际开发中 MCP 服务已经都封装好了,Spring AI 负责对接,AI 负责决策。如果你想了解更多 MCP 的玩法,可以去 MCP.so、阿里百炼等服务市场逛逛,看看别人都提供了哪些现成的服务。也可以试试把自己写的工具通过 @Tool 注解包一下,注册成 MCP 服务,分享给更多人使用。
如果你想获取本文的完整代码仓库,欢迎关注我的公众号 AutowiredAI,后台回复「MCP实战」即可。如果配置过程中遇到任何问题,欢迎留言交流,我会尽力解答。