Spring AI 使用 MCP 客户端(调用高德 MCP)

0 阅读10分钟

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 注解、FunctionCallbackToolCallback 等实现,工具就是一段硬编码在应用里的 Java 代码

两者的本质区别

MCP 的本质,是 Tool Calling 的"标准化 + 动态化"。

  • 标准化:原生 Tool Calling 的工具定义格式、调用协议、错误处理,每个框架/每个应用各写各的;MCP 把"工具发现、工具调用、结果返回"统一成了标准协议。
  • 动态化:原生 Tool Calling 的工具数量、入参出参在编译期就固定死了,新增工具必须改代码、重新打包部署;MCP 下工具由外部 Server 在运行时动态下发,应用侧只要在配置文件里加一个服务地址,重启即获得新能力。

而且,MCP 调用本质上是"借助 Tool Calling 能力实现的工具调用"——并不是让 AI 服务器主动去调用 MCP 服务,而是通过 MCP 客户端把"Server 提供了哪些工具"告诉 AI,AI 想要使用这些工具时,就告诉后端程序去执行,后端执行完把结果返回给 AI,由 AI 最后总结回复。

核心区别与优缺点对比

维度原生 Tool CallingMCP
工具来源代码内硬编码外部 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 提供的 McpClientToolCallbackProvider
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 调用 ServerServer 调用真实业务接口(高德 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 服务: