Spring AI 使用 MCP 客户端(调用高德 MCP)
本文以 Spring AI 1.0.0-M6 为例,完整演示了如何通过 MCP(Model Context Protocol)客户端在 Spring AI 应用中接入高德地图 MCP 服务,并深入剖析 MCP 与原生 Tool Calling 的区别。
什么是 MCP?
MCP 是 Model Context Protocol(模型上下文协议)的缩写,由 Anthropic 于 2024 年 11 月提出并开源的一套开放标准协议。它统一了 AI 应用与外部"数据源 + 工具"的连接方式,让 AI 应用能够以标准化的手段获取上下文、调用工具、执行操作。
我们可以把 MCP 理解为 AI 世界的 "USB-C" 接口:
- USB-C 用统一的物理接口让不同设备互通互联;
- MCP 用统一的协议让不同的 AI 应用(Claude Desktop、各类 IDE、我们自己的 Spring AI 应用等)都能对接同一套工具与数据服务。
在 MCP 出现之前,每个 AI 应用想要接 N 个外部服务,就要针对每个服务写 N 套不同的集成代码,应用与工具之间是 N × M 的点对点网状耦合(N 个应用 × M 个工具)。有了 MCP 之后,工具提供方只需把能力以 MCP Server 的形式发布一次,任何支持 MCP 的客户端都能直接复用,集成关系从"网状"收敛为"星型":
┌────────────┐ ┌────────────┐
│ AI 应用 A │ │ AI 应用 B │
└─────┬──────┘ └─────┬──────┘
│ 统一协议 │
▼ ▼
┌──────────────────────────────┐
│ MCP 协议层 │
└──────┬──────────────┬────────┘
▼ ▼
┌──────────┐ ┌──────────┐
│ 高德 MCP │ │ GitHub │
│ Server │ │ MCP │
└──────────┘ └──────────┘
一句话总结:MCP 是"AI 应用的开放接口标准",它解决了 AI 应用如何统一、动态、可复用地接入外部工具与数据的问题。
有了 Tool Calling 为什么还要 MCP?两者的区别、优缺点对比
什么是 Tool Calling
Tool Calling(函数调用 / 工具调用) 是 LLM 本身的一项能力:模型在生成回复的过程中,可以"决定"调用开发者在代码里预先定义好的函数,由应用程序执行这些函数,再把执行结果回填给模型,最后由模型总结成自然语言回复。
在 Spring AI 中,原生 Tool Calling 通常通过 @Tool 注解、FunctionCallback、ToolCallback 等实现,工具就是一段硬编码在应用里的 Java 代码。
两者的本质区别
MCP 的本质,是 Tool Calling 的"标准化 + 动态化"。
- 标准化:原生 Tool Calling 的工具定义格式、调用协议、错误处理,每个框架/每个应用各写各的;MCP 把"工具发现、工具调用、结果返回"统一成了标准协议。
- 动态化:原生 Tool Calling 的工具数量、入参出参在编译期就固定死了,新增工具必须改代码、重新打包部署;MCP 下工具由外部 Server 在运行时动态下发,应用侧只要在配置文件里加一个服务地址,重启即获得新能力。
而且,MCP 调用本质上是"借助 Tool Calling 能力实现的工具调用"——并不是让 AI 服务器主动去调用 MCP 服务,而是通过 MCP 客户端把"Server 提供了哪些工具"告诉 AI,AI 想要使用这些工具时,就告诉后端程序去执行,后端执行完把结果返回给 AI,由 AI 最后总结回复。
核心区别与优缺点对比
| 维度 | 原生 Tool Calling | MCP |
|---|---|---|
| 工具来源 | 代码内硬编码 | 外部 MCP Server 动态提供 |
| 标准化程度 | 各框架/各家各自实现 | 统一开放协议 |
| 新增工具成本 | 改代码 + 重新打包发版 | 新增/修改一个 MCP Server 配置即可 |
| 跨应用复用 | 差,工具绑死在某个应用里 | 好,一次开发,处处复用 |
| 运行时扩展 | 不支持 | 支持工具动态发现(listTools) |
| 运行形态 | 与应用同进程 | 本地子进程(stdio)或远程服务(HTTP) |
| 接入/学习成本 | 低 | 有一定门槛(协议、进程、依赖) |
| 调试复杂度 | 低 | 相对高(多一层子进程/网络栈) |
| 生态丰富度 | 无生态,自己写 | 大量现成 Server(高德、GitHub、Slack…) |
| 安全边界 | 应用自身控制 | 需关注 Server 信任、权限与凭证管理 |
原生 Tool Calling 的优点: 实现简单、同进程调用性能好、调试容易;适合应用内部稳定、私有的小工具集。缺点: 工具与业务代码强耦合,每接一个新工具都要发版,无法跨应用共享,也无法利用社区生态。
MCP 的优点: 工具开发者可以独立维护 Server;应用侧通过配置即可动态接入海量第三方能力;工具可跨应用复用;便于统一治理与审计。缺点: 多一层子进程/网络开销,本地 stdio 模式依赖 Node.js 等运行时可用性,MCP 规范仍在快速演进、存在协议版本兼容问题,排障链路更长。
什么时候用哪个?
- 应用内部、固定不变、私有化的工具(如查询自家订单库):用原生 Tool Calling,简单高效。
- 需要接入大量第三方能力,或希望工具跨应用复用、独立演进:用 MCP,一次接入长期受益。
两者并不互斥,可以共存——一个应用里完全可以既有 @Tool 注解的原生工具,又有通过 ToolCallbackProvider 注入的 MCP 工具。
MCP 核心概念
架构组成
MCP 采用 Client / Server 架构,包含三个角色:
| 角色 | 说明 | 在 Spring AI 中的对应物 |
|---|---|---|
| Host(宿主应用) | 用户交互与 AI 推理发生的地方,如 Claude Desktop、IDE、我们的 Spring AI 应用 | ChatClient |
| Client(客户端) | 与某个 Server 保持 1:1 连接,负责能力协商、发起工具/资源/提示请求 | spring-ai-mcp-client-spring-boot-starter 提供的 McpClient、ToolCallbackProvider |
| Server(服务端) | 通过"原语"对外暴露能力,可以是本地子进程(如 npx 启动的高德 MCP),也可以是远程 HTTP 服务 | @amap/amap-maps-mcp-server 等 |
一个 Host 可以同时连接多个 Server,一个 Client 只对应一个 Server。
核心原语(Primitives)
MCP 定义了三大核心能力原语:
- Tools(工具):可被模型调用执行、并把结果返回给模型的函数,类比 Spring AI 的
@Tool。通过tools/list发现、tools/call调用。这是本文接入高德 MCP 用到的能力。 - Resources(资源):可被模型读取的外部数据,如文件内容、数据库记录、URL 内容等,类比 Spring AI 的
Resource。 - Prompts(提示词):可复用的提示模板,服务端定义好模板,客户端按需拉取。
传输方式(Transport)
| 传输方式 | 说明 | 适用场景 |
|---|---|---|
| stdio | 客户端启动一个子进程,通过标准输入/输出与该进程通信 | 本地运行 MCP 服务(本文场景) |
| Streamable HTTP | 通过 HTTP(含 SSE 流式响应)访问远程 MCP Server | 远程部署、跨机器调用 |
| SSE(早期) | 基于 Server-Sent Events 的单向推送 | 已被 Streamable HTTP 取代 |
一次完整的 MCP 调用流程
① 应用启动:读取 mcp-servers.json
│
② Client 拉起/连接各 Server(stdio 子进程 or HTTP)
│
③ 能力协商(capabilities negotiation)→ 拉取工具清单 tools/list
│
④ Spring AI 把工具列表转换为 ToolCallback,注入 ChatClient
│
⑤ 用户提问 → 模型判断需要调用工具 → 返回工具调用请求
│
⑥ Spring AI 客户端执行工具 → Client 调用 Server → Server 调用真实业务接口(高德 API)
│
⑦ 结果回传 → 回填给模型 → 模型总结并回复用户
利用 Spring AI 在程序中使用 MCP
环境准备
(1)依赖于 Node.js,去 官网 傻瓜式安装即可。由于本地 stdio 模式通过 npx 启动 MCP Server,Node.js 是必装项。
(2)使用地图 MCP 需要 API Key,我们可以到 地图开放平台 创建应用并添加 API Key。
引入依赖
在 pom.xml 中加入:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
版本提示(重要):示例基于
1.0.0-M6。Spring AI 1.0.0 正式版(GA)发布后,MCP 客户端的 starter 已统一更名为spring-ai-starter-mcp-client,并建议通过spring-ai-bom统一管理版本;配置项(spring.ai.mcp.client.stdio.*)与用法保持一致。1.0.0-M6对应 Spring Boot 3.4.x,使用时请留意 Spring Boot 版本兼容性。
配置 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"
}
}
}
}
特别注意:在 Windows 环境下,命令配置需要添加 .cmd 后缀(如 npx.cmd),否则会报找不到命令的错误。
建议:不要把 API Key 明文提交到 Git。可以将
env.AMAP_MAPS_API_KEY的值改为引用环境变量/配置占位符的方式注入,避免密钥泄露。
修改 Spring 配置文件
由于是本地运行 MCP 服务,所以使用 stdio 模式,并且要指定 MCP 服务配置文件的位置。在 application.yml 中加入:
spring:
ai:
mcp:
client:
stdio:
servers-configuration: classpath:mcp-servers.json
MCP 客户端程序启动时,会额外启动一个子进程来运行 MCP 服务,从而能够实现调用。
编写调用代码
通过自动注入的 ToolCallbackProvider 获取到配置中定义的 MCP 服务提供的 所有工具,并提供给 ChatClient:
@Resource
private ToolCallbackProvider toolCallbackProvider;
public String doChatWithMcp(String message, String chatId) {
ChatResponse response = chatClient
.prompt()
.user(message)
.advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
// 开启日志,便于观察效果
.advisors(new MyLoggerAdvisor())
.tools(toolCallbackProvider)
.call()
.chatResponse();
String content = response.getResult().getOutput().getText();
log.info("content: {}", content);
return content;
}
从这段代码我们能够看出,MCP 调用的本质就是类似工具调用,并不是让 AI 服务器主动去调用 MCP 服务,而是告诉 AI "MCP 服务提供了哪些工具",如果 AI 想要使用这些工具完成任务,就会告诉我们的后端程序,后端程序在执行工具后将结果返回给 AI,最后由 AI 总结并回复。
测试运行
运行效果:AI 会根据问题自动决策调用高德 MCP 的 search_poi 等工具(如周边搜索、POI 检索),拿到结果后再组织成"约会地点推荐"的回复。
可以在地图开放平台的控制台查看 API Key 的使用量,注意控制调用次数避免超出限额。
注意的坑
(1)安装好 Node.js 后,IDEA 可能识别不到 Node.js,最好重启 IDEA。
(2)Windows 下命令要加 .cmd 后缀:npx 写成 npx.cmd,否则报"找不到命令"。
(3)首次运行 npx 会联网下载依赖包(@amap/amap-maps-mcp-server),耗时较长;若网络受限(如国内访问 npm 源慢),可以配置 npm 镜像(如淘宝源)后再启动。
(4)工具是启动时动态发现的:如果 MCP 子进程启动失败(Node.js 未安装、包下载失败、命令写错),应用虽然能启动,但 ToolCallbackProvider 里可能是空的,模型自然就不会"使用工具"。遇到这种情况,先看启动日志里 MCP 客户端的连接与 tools/list 结果是否正常。
(5)版本兼容性:spring-ai-mcp-client-spring-boot-starter 是 Milestone 版本坐标;升级到 Spring AI 1.0.0 GA 时,starter 更名为 spring-ai-starter-mcp-client,注意同步调整依赖并核对 Spring Boot 版本。
(6)API Key 额度:每次工具调用都会真实消耗高德开放平台的调用次数,开发调试时注意控制频率,避免超限被限流或扣费。
(7)不要把 API Key 硬编码进 mcp-servers.json 提交到代码库,建议通过环境变量或配置中心注入。
(8)stdio 子进程生命周期:MCP 服务子进程随应用一起启动/销毁,本地多实例部署时要注意 Node 进程的占用与清理。
MCP 服务大全
目前已经有很多 MCP 服务市场,开发者可以在这些平台上找到各种现成的 MCP 服务:
- MCP.so:较为主流,提供丰富的 MCP 服务目录
- GitHub Awesome MCP Servers:开源 MCP 服务集合
- 阿里云百炼 MCP 服务市场
- Spring AI Alibaba 的 MCP 服务市场
- Glama.ai MCP 服务