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.jsonMCP 客户端程序启动时,会额外启动一个子进程来运行 MCP 服务,从而能够实现调用。
编写调用代码
通过自动注入的ToolCallbackProvider获取到配置中定义的 MCP 服务提供的所有工具,并提供给ChatClient:
@ResourceprivateToolCallbackProvidertoolCallbackProvider;publicStringdoChatWithMcp(Stringmessage,StringchatId){ChatResponseresponse=chatClient.prompt().user(message).advisors(spec->spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY,chatId).param(CHAT_MEMORY_RETRIEVE_SIZE_KEY,10))// 开启日志,便于观察效果.advisors(newMyLoggerAdvisor()).tools(toolCallbackProvider).call().chatResponse();Stringcontent=response.getResult().getOutput().getText();log.info("content: {}",content);returncontent;}从这段代码我们能够看出,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 服务