☰
MCP协议实战|Spring AI + 高德地图工具集成教程:TaoToken统一Key接入与本地联调
2026/10/1 7:10:08 网站建设 项目流程

1. 为什么要在 Spring AI 里接高德地图 MCP

先说清楚这篇要解决的事:你有一个基于 Spring AI 的对话应用,想让模型能查地理编码、算驾车路线、搜周边 POI,但不想为每个地图能力手写一套 Function Calling 的胶水代码。MCP(Model Context Protocol)就是干这个的——它把外部工具用统一协议暴露出来,Spring AI 作为 MCP 客户端去发现并调用这些工具,模型侧只看到一份工具清单。

MCP 是 Anthropic 在 2024 年 11 月推出的开放标准,常被叫做“AI 领域的 USB-C 接口”。它用 JSON-RPC 2.0 通信,核心是客户端-服务器架构:一个 MCP 客户端主机可以连多个 MCP 服务器。SDK 分三层——客户端/服务器层(McpClient、McpServer)、会话层(McpSession 管通信模式和状态)、传输层(McpTransport 负责 JSON-RPC 序列化,支持 Stdio 和 HTTP SSE)。六大概念里 Resources、Prompts、Tools、Sampling、Roots、Transports,实际开发中 Tools 是重中之重,其余了解即可。

高德地图官方提供了@amap/amap-maps-mcp-server这个 Node 包,通过 Stdio 方式启动,内置地理编码、逆地理编码、路径规划、周边搜索等十来个工具。Spring AI 这边用spring-ai-mcp-client-spring-boot-starter做客户端,启动时自动向 MCP Server 拉取工具列表,注入成ToolCallbackProvider,再交给ChatClient。

那 TaoToken 在这里扮演什么角色?它是统一 Key 网关。你本地跑 MCP 服务、调模型、做端到端验证,模型侧的鉴权走 TaoToken 一个 Key 就行,Base URL 指向https://taotoken.net/api,不用在多个厂商控制台之间来回切。这篇就按“本地联调”的路径走一遍:配 MCP 服务、配 Spring AI 客户端、用 TaoToken 统一 Key 完成鉴权、对高德地理编码和路径规划做一次真实请求验证。

适合谁看:已经在写 Spring Boot + Spring AI 项目、想接地图工具链但被工具注册和参数映射卡住的同学。下面所有配置都可以直接复制,路径和字段名保持和项目一致。

2. TaoToken 前置准备与 MCP 服务声明

动手之前先把两件事办了:拿到 TaoToken 的 Key,以及确认本地 Node 环境能跑 npx。

TaoToken 的定位是统一模型接入网关。你注册后在控制台创建一个 API Key,模型调用时 Base URL 填https://taotoken.net/api,Key 填进去即可。它不改变你调用模型的方式,只是把鉴权入口收敛到一个地方。控制台地址是https://taotoken.net/console,API Key 管理在https://taotoken.net/api-keys。如果你后面要长期跑编码类 Agent,可以看下 Coding Plan(https://taotoken.net/coding-plan);单纯验证模型连通性用模型对话页(https://taotoken.net)就够。

高德这边需要去高德开放平台申请一个 Web 服务类型的 Key。流程不复杂:注册登录进控制台,创建应用,在应用下添加 Key,服务平台选“Web服务”,勾选协议确认,复制生成的 Key。这个 Key 后面会写进 MCP 服务的环境变量里。

Node 环境确认一下:

node -v npx -v

Windows 上如果npx报找不到命令,用npx.cmd替代,这个坑后面排障章节会细说。

接下来在 Spring Boot 项目的src/main/resources目录下新建mcp-server-config-dev.json,声明高德 MCP 服务:

{ "mcpServers": { "amap-maps": { "command": "npx", "args": [ "-y", "@amap/amap-maps-mcp-server" ], "env": { "AMAP_MAPS_API_KEY": "替换成你的高德Web服务Key" } } } }

这里command是启动命令,args里-y表示自动确认安装,@amap/amap-maps-mcp-server是高德官方 MCP 包。env里塞高德 Key,MCP Server 启动时读取。注意这个文件是 Stdio 模式的服务声明,不是 HTTP SSE,所以 Spring AI 侧要配 stdio。

Maven 依赖加上 MCP 客户端 starter:

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId> <version>1.0.0-M6</version> </dependency>

版本号按你项目里 Spring AI 的 BOM 对齐,M6 是当时能跑通的一版。Spring AI 官方文档更新快,包路径可能变,建议对照 Spring AI Alibaba 的文档确认坐标。

application.yml里配 MCP 客户端,指定 stdio 模式和配置文件位置:

spring: ai: mcp: client: stdio: servers-configuration: classpath:/mcp-server-config-dev.json

到这一步,前置就齐了:TaoToken Key 在手、高德 Key 写进 JSON、依赖和 yml 配好。下一节把 MCP 工具真正注册进 ChatClient。

3. 可复制配置:把 MCP 工具注册进 ChatClient

这一节是核心,配置片段都能直接抄。目标是把 MCP Server 暴露的工具通过ToolCallbackProvider注入到ChatClient,同时把模型鉴权指向 TaoToken。

先看模型侧的配置。在application.yml里加 TaoToken 的接入参数:

spring: ai: openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: gpt-4o-mini mcp: client: stdio: servers-configuration: classpath:/mcp-server-config-dev.json

base-url指向 TaoToken 的 API 地址,api-key从环境变量读,别硬编码进仓库。model填你要用的模型 ID,具体可用模型在 TaoToken 控制台或模型对话页能看到。这里三件套齐了:Base URL、Key、Model ID,缺一不可。

然后是 Java 侧的装配。改造你的TravelApp类,注入ToolCallbackProvider并绑定到ChatClient:

@Service public class TravelApp { private final ChatClient chatClient; public TravelApp(ChatClient.Builder builder, ToolCallbackProvider toolCallbackProvider) { this.chatClient = builder .defaultToolCallbacks(toolCallbackProvider) .build(); } public String chat(String chatId, String message) { return chatClient.prompt() .user(message) .advisors(a -> a.param("chatId", chatId)) .call() .content(); } }

ToolCallbackProvider由 Spring 自动注入。程序启动时,Spring 会创建McpClient,向 MCP Server 发请求拉取工具列表,把每个工具包装成ToolCallback。defaultToolCallbacks把这些回调注册到ChatClient,模型在对话中就能“看到”这些工具并按需调用。

如果你用的是ChatClient的流式接口,注册方式一样,只是最后调.stream()而不是.call()。

再确认一下 MCP 服务声明文件路径和 yml 里servers-configuration一致。常见错误是文件放在resources/mcp/下但 yml 写classpath:/mcp-server-config-dev.json,路径对不上就加载不到,启动时工具列表为空。

配置完成后,写个测试方法验证工具是否注册成功:

@Test void testMcp() { String chatId = UUID.randomUUID().toString(); String result = travelApp.chat(chatId, "帮我查一下郴州高椅岭附近5公里的酒店"); System.out.println(result); }

跑之前确保TAOTOKEN_API_KEY环境变量已设置。如果一切正常,模型会调用高德的周边搜索工具,返回 POI 列表。下一节看实际请求和返回结构。

4. 验证请求:地理编码与路径规划端到端跑通

配置就绪后,做一次真实的端到端验证。分两步:先单独验证地理编码,再验证路径规划,最后看模型编排多工具调用的返回结构。

地理编码是把地址转成经纬度。写个测试:

@Test void testGeocode() { String chatId = UUID.randomUUID().toString(); String result = travelApp.chat(chatId, "把'湖南省郴州市苏仙区高椅岭'转成经纬度坐标"); System.out.println(result); }

预期返回里包含经纬度数值,比如经度 113.0 左右、纬度 25.7 左右(具体值以高德返回为准)。如果返回的是模型自己编的坐标而不是工具调用结果,说明工具没被触发,回去检查ToolCallbackProvider是否注入成功。

路径规划验证:

@Test void testRoute() { String chatId = UUID.randomUUID().toString(); String result = travelApp.chat(chatId, "规划从郴州西站到高椅岭的驾车路线,告诉我距离和预计时间"); System.out.println(result); }

这一步模型会调用高德的驾车路径规划工具,返回距离(米)、预计耗时(秒)和路线步骤。返回结构里通常有route.paths[0].distance、route.paths[0].duration这类字段,模型会把它转成自然语言。

多工具编排验证——让模型先地理编码再算路线:

@Test void testMultiTool() { String chatId = UUID.randomUUID().toString(); String result = travelApp.chat(chatId, "先查高椅岭的坐标,再算从郴州西站开车过去要多久"); System.out.println(result); }

正常情况模型会连续调用两次工具:第一次地理编码拿坐标,第二次路径规划。你可以在日志里看到 MCP 的 JSON-RPC 请求和响应。如果只调了一次就编答案,说明工具描述不够清晰或模型能力不足,换个支持工具调用的模型再试。

验证成功的标志有三个:日志里出现 MCP 工具的tools/call请求;返回内容包含高德真实数据(距离、坐标等);多工具场景下模型按顺序调用了两次。三个都满足,说明 Spring AI + 高德 MCP + TaoToken 这条链路通了。

5. 常见报错排查:401、npx 找不到、ToolContext 不支持

联调阶段最容易撞的几个坑,逐个说。

401 鉴权失败。报错通常是401 Unauthorized或invalid api key。先确认TAOTOKEN_API_KEY环境变量真的注入了,echo $TAOTOKEN_API_KEY(Windows 用echo %TAOTOKEN_API_KEY%)看有没有值。再确认base-url是https://taotoken.net/api,末尾不要多加/v1之类的路径,具体以接入文档为准(https://taotoken.net/doc)。Key 复制时别带空格。

local proxy failed / 连接超时。如果报local proxy failed或连接被拒,检查本机网络是否能访问taotoken.net。另外确认没有配多余的代理环境变量干扰请求。

Windows 下 npx 找不到。报错类似Cannot run program "npx": CreateProcess error=2。原因是 Windows 上 npx 的可执行文件是npx.cmd。把mcp-server-config-dev.json里的command从npx改成npx.cmd即可。Mac/Linux 保持npx。

ToolContext 不支持。报错ToolContext is not supported或call(String, ToolContext) throws exception。原因是 MCP 类型的ToolCallback默认不支持带ToolContext参数的call方法,而你的代码传了 toolContext。两个解法:一是临时把传 toolContext 的参数注释掉先跑通;二是用代理拦截。代理类思路是判断目标回调类名含mcp且方法名是call且第二个参数是ToolContext时,改调无 toolContext 的call方法:

public class McpToolCallbackProxy implements InvocationHandler { private final FunctionCallback target; public McpToolCallbackProxy(FunctionCallback target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (target.getClass().getSimpleName().toLowerCase().contains("mcp") && method.getName().equals("call") && args.length == 2 && args[1].getClass().equals(ToolContext.class)) { return target.call(args[0].toString()); } return method.invoke(target, args); } public static FunctionCallback[] proxyAll(FunctionCallback... callbacks) { FunctionCallback[] proxyArray = new FunctionCallback[callbacks.length]; for (int i = 0; i < callbacks.length; i++) { FunctionCallback callback = callbacks[i]; proxyArray[i] = (FunctionCallback) Proxy.newProxyInstance( callback.getClass().getClassLoader(), callback.getClass().getInterfaces(), new McpToolCallbackProxy(callback)); } return proxyArray; } }

注意原 excerpt 里method.invoke(proxy, method, args)那行是笔误,应该invoke(target, args),否则会无限递归。用代理时在装配处调McpToolCallbackProxy.proxyAll(...)包一层。

reading choices 报错。如果返回体解析报reading choices或choices is null,多半是模型返回格式和客户端预期不符。确认model填的是支持 chat completions 的模型 ID,别填成 embedding 或纯文本模型。DeepSeek 的纯文本模型不支持 MCP 工具调用,换支持 function calling 的模型。

工具列表为空。启动日志里没有工具注册信息,检查servers-configuration路径、JSON 格式、高德 Key 是否有效。JSON 里 Key 填错会导致 MCP Server 启动失败,工具自然拉不到。

6. 继续往下走:把链路固化进项目

链路跑通后,建议做三件事把它固化下来。

第一,把 MCP 服务声明按环境拆分。mcp-server-config-dev.json用于本地,生产环境另建一份,Key 走配置中心或环境变量注入,别把高德 Key 提交进 Git。

第二,给工具调用加日志。在ChatClient的 advisor 里记录每次工具调用的入参和返回,方便排查模型为什么没调工具或调错工具。MCP 的 JSON-RPC 请求本身也可以开 debug 日志看。

第三,模型侧统一走 TaoToken。Base URL 固定https://taotoken.net/api,Key 从环境变量读,换模型只改model字段。这样本地联调和线上部署的鉴权逻辑一致,不用为每个模型厂商单独配 Key。需要长期跑编码类 Agent 的话,Coding Plan(https://taotoken.net/coding-plan)比按量调用更省心;只是验证模型连通性,模型对话页(https://taotoken.net)点开就能试。

最后提醒一个实操细节:MCP Server 是本地进程,Spring Boot 启动时会拉起它,应用关闭时要确保进程被回收,否则残留的 npx 进程会占端口或内存。可以在McpClient的销毁回调里做清理,或者用@PreDestroy手动关。

这套组合跑下来,Spring AI 负责编排,MCP 负责工具协议,高德负责地理能力,TaoToken 负责统一鉴权。四者各司其职,你只需要维护一份工具声明和一份模型配置。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询