ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

一文吃透 Spring AI Alibaba + MCP:服务端搭建 + 客户端调用全流程(TaoToken 统一 Key 接入版)

一文吃透 Spring AI Alibaba + MCP:服务端搭建 + 客户端调用全流程(TaoToken 统一 Key 接入版) 1. 为什么要在 Spring AI Alibaba 里折腾 MCP如果你正在用 Spring AI Alibaba 做智能体大概率会遇到一个尴尬模型本身很聪明但它够不到你的业务系统。想让它查一下订单、读一下本地文件、调一下内部接口就得在代码里硬编码一堆 if-else工具一多就变成意大利面。MCPModel Context Protocol就是来解决这个问题的。你可以把它理解成「AI 世界的 USB-C 接口」服务端把能力工具方法按统一协议暴露出来客户端按统一协议去发现和调用双方不用互相认识。Spring AI Alibaba 在 Spring AI 的基础上做了 Java 生态的适配让你用几个注解就能把普通 Service 变成 MCP 工具。这篇要交付的是一条能跑通的端到端链路用 Spring AI Alibaba 搭一个本地 MCP 服务端暴露天气查询工具再搭一个 MCP 客户端用 ReactAgent 调用服务端工具中间所有模型请求统一走 TaoToken 的 Key 和 API 通道。适合已经会写 Spring Boot、想快速把 MCP 落地的后端同学也适合正在选型智能体工具链的架构同学。下面每一步都给到可复制的配置和命令跟着敲就能出结果。2. TaoToken 前置一把 Key 打通模型通道在动手写 MCP 之前先把模型通道准备好。MCP 服务端本身不依赖大模型但客户端里的 ReactAgent 需要一个 ChatModel 来驱动「思考—调工具—再思考」的循环。传统做法是分别去各家平台申请 Key、记不同的 BaseURL切换模型时改一堆配置。TaoToken 的思路是统一入口一个 Key、一个 API 地址兼容 OpenAI 风格的调用方式模型切换只改模型名。你需要先拿到两样东西API Key在控制台的 API Keys 页面创建形如sk-xxxx只显示一次记得存好。API 地址https://taotoken.net/api所有请求都往这里发。创建 Key 的入口在这里https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai_alibaba拿到 Key 之后不要硬编码进代码。推荐用环境变量注入本地开发可以写进~/.zshrc或~/.bashrcexport TAOTOKEN_API_KEYsk-你的Key注意环境变量改完要source ~/.zshrc或重开终端才生效。后面客户端配置里用${TAOTOKEN_API_KEY}引用避免 Key 进 Git。如果你还想在写代码前先验证 Key 是否可用可以直接在模型对话页面发一条消息试试https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai_alibaba能正常返回就说明 Key 和通道没问题可以进入下一步。长期做编码类 Agent 的话也可以了解下 Coding Plan额度模型更适合高频调用https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai_alibaba3. 服务端搭建把普通 Service 变成 MCP 工具3.1 依赖选择与踩坑点服务端要暴露 MCP 能力核心依赖是spring-ai-starter-mcp-server-webflux。这里有个容易翻车的地方不要同时引入spring-boot-starter-web。因为 webflux 版本默认用 Netty 启动和 Tomcat 会冲突启动时报端口占用或者容器初始化失败。dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server-webflux/artifactId version1.1.2/version /dependency注意第一个依赖是spring-boot-starter而不是spring-boot-starter-web这是刻意为之。用 starter 会走 Netty正好适配 MCP 服务端的通信要求。3.2 application.yml 配置服务端配置很轻重点是端口、编码和 MCP 服务元信息server: port: 8088 servlet: encoding: enabled: true force: true charset: UTF-8 spring: application: name: local-mcp-server ai: mcp: server: type: async name: local-mcp-server version: 1.0.0type: async表示异步模式工具调用不会阻塞主线程并发场景下性能更好。name和version是 MCP 服务对外暴露的标识客户端连接时会看到。3.3 用 Tool 注解暴露工具方法这是整个服务端最舒服的部分。你不需要写任何协议相关的代码只要在普通 Service 方法上加ToolSpring AI Alibaba 会自动把它注册成 MCP 工具。description很重要模型靠它判断什么时候该调这个工具。Service public class WeatherService { Tool(description 根据城市名称获取天气信息) public String getWeatherByCity(String city) { return city 今天天气很好; } }实际项目里把return换成真实 API 调用即可比如接高德或和风天气。参数名city也会被协议带出去模型调用时会按这个名字传参。3.4 注册 ToolCallbackProvider光有Tool还不够需要用一个配置类把工具对象封装成ToolCallbackProviderSpring 容器启动时才会扫描并注册Configuration public class McpServerConfig { Bean public ToolCallbackProvider weatherTools(WeatherService weatherService) { return MethodToolCallbackProvider.builder() .toolObjects(weatherService) .build(); } }如果有多个工具类toolObjects()里逗号隔开继续加就行。启动应用控制台看到 Netty 在 8088 端口起来就说明服务端 OK 了Netty started on port 8088 (http) Started McpServerApplication in 1.198 seconds4. 客户端搭建ReactAgent 调用 MCP 工具4.1 客户端依赖客户端这边正常用spring-boot-starter-webTomcat 启动加上 Spring AI Alibaba 的 Agent 框架和 MCP 客户端 starterdependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-agent-framework/artifactId version1.1.2.0/version /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-client/artifactId version1.1.2/version /dependency4.2 客户端 application.yml 接入 TaoToken这里是把 TaoToken 接进来的关键位置。Spring AI Alibaba 默认用 DashScope 的 starter但我们可以通过自定义ChatModelBean 把请求指向 TaoToken 的 API 地址。配置里先声明 MCP 服务端连接信息spring: application: name: spring-ai-alibaba-agent ai: mcp: client: type: async request-timeout: 60s toolcallback: enabled: true sse: connections: local-mcp-server: url: http://localhost:8088connections下的local-mcp-server是自定义名称url指向刚才启动的服务端。toolcallback.enabled: true让客户端能接收服务端返回的工具响应。4.3 用 TaoToken 构建 ChatModel如果你用 OpenAI 兼容的模型可以自己 new 一个OpenAiChatModel把baseUrl指向 TaoTokenConfiguration public class ChatModelConfig { Bean public ChatModel chatModel() { OpenAiApi api OpenAiApi.builder() .baseUrl(https://taotoken.net/api) .apiKey(System.getenv(TAOTOKEN_API_KEY)) .build(); return OpenAiChatModel.builder() .openAiApi(api) .defaultOptions(OpenAiChatOptions.builder() .model(gpt-4o-mini) .build()) .build(); } }模型名按你实际要用的填TaoToken 支持多种模型切换只改这一行。这样客户端所有推理请求都走统一通道不用为每个模型单独配 Key。4.4 编写调用接口用一个 Controller 把 ReactAgent 跑起来核心是绑定ToolCallbackProvider让 Agent 知道有哪些工具可用RestController public class McpClientController { Resource private ToolCallbackProvider toolCallbackProvider; Resource private ChatModel chatModel; GetMapping(mcpTest) public String mcpTest() throws GraphRunnerException { ToolCallback[] toolCallbacks toolCallbackProvider.getToolCallbacks(); System.out.printf(Tools from MCP%n%s%n, JSON.toJSONString(toolCallbacks)); ReactAgent agent ReactAgent.builder() .name(weather_agent) .model(chatModel) .description(你是一个天气查询助手) .saver(new MemorySaver()) .toolCallbackProviders(toolCallbackProvider) .build(); RunnableConfig config RunnableConfig.builder() .threadId(session) .build(); StringBuffer answer new StringBuffer(); FluxNodeOutput stream agent.stream(上海天气怎么样, config); stream.doOnNext(output - { if (output.node().equals(_AGENT_MODEL_)) { answer.append(((StreamingOutput?) output).message().getText()); } else if (output.node().equals(_AGENT_TOOL_)) { answer.append(\nTool Call:) .append(((ToolResponseMessage) ((StreamingOutput?) output).message()) .getResponses().get(0)) .append(\n); } }).doOnComplete(() - System.out.println(answer)) .doOnError(e - System.err.println(Error: e.getMessage())) .blockLast(); return answer.toString(); } }threadId用于会话记忆同一个 id 的多轮对话能记住上下文。MemorySaver是内存版存储生产环境可以换成 Redis 或数据库实现。5. 验证请求与成功结果确保服务端 8088 已启动再启动客户端默认 8080浏览器或 curl 访问curl http://localhost:8080/mcpTest客户端控制台会先打印从 MCP 服务端发现的所有工具然后输出 Agent 的推理过程。看到类似下面的内容说明整条链路通了Tool Call:ToolResponse[idcall_b8f00f883a784fc1b35603, namegetWeatherByCity, responseData[{text:\上海 今天天气很好\}]]拆解一下这段输出namegetWeatherByCity说明模型正确选择了服务端暴露的工具responseData里是工具的真实返回。模型拿到这个结果后会再生成一句自然语言回复整个「模型决策 → 调 MCP 工具 → 模型总结」的循环就跑完了。如果你想确认工具发现环节可以单独看客户端启动日志里ToolCallbackProvider打印的 JSON里面会列出工具名、描述、参数 schema。这一步能对上后面调用基本不会出问题。6. 本篇常见错排查服务端起不来报端口冲突或容器异常。九成是同时引入了spring-boot-starter-web。检查 pom服务端只保留spring-boot-starter和spring-ai-starter-mcp-server-webflux把 web 依赖删掉。客户端连不上服务端报连接超时。先确认服务端 8088 端口在监听lsof -i:8088。再看客户端 yml 里sse.connections的 url 是不是写成了https本地是http。如果服务端和客户端不在同一台机器把localhost换成服务端实际 IP。模型不调工具直接瞎编答案。通常是Tool的description写得太模糊模型判断不出该不该用。把描述写具体比如「根据城市名称查询该城市当前天气参数为城市中文名」。另外确认toolcallback.enabled: true没漏。TaoToken 请求返回 401。检查环境变量TAOTOKEN_API_KEY是否在当前终端生效echo $TAOTOKEN_API_KEY看有没有值。如果是在 IDE 里跑注意 IDE 可能没继承 shell 的环境变量需要在 Run Configuration 里手动加。工具调用超时。默认request-timeout可能不够尤其是工具内部要调外部 API 时。在客户端 yml 里把request-timeout调到120s同时检查服务端工具方法本身有没有阻塞操作。中文返回乱码。服务端 yml 里server.servlet.encoding那几行要配上force: true和charset: UTF-8缺一不可。7. 下一步把链路接到真实业务跑通天气这个 demo 之后你可以把WeatherService换成任何真实能力查数据库、调内部微服务、读文件系统。MCP 的价值在于这些能力一旦按协议暴露任何支持 MCP 的客户端都能复用不用为每个 Agent 重写一遍工具代码。客户端这边把ChatModel的模型名换掉就能切换推理模型Key 和地址都不用动。需要管理多个 Key 或查看调用量去控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai_alibaba接入过程中如果遇到协议层面的细节问题比如工具 schema 定义、SSE 连接参数可以对照接入文档排查https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmcp_spring_ai_alibaba我实测下来最容易卡住的地方不是 MCP 协议本身而是依赖冲突和环境变量没生效这两件事。把这两点排掉剩下的就是按业务填工具方法了。
返回列表