首页 / 资讯中心 / 文章详情

Spring AI 实战 MCP 工具:客户端与服务端完整实现,TaoToken 统一 Key 接入示例

Spring AI 实战 MCP 工具:客户端与服务端完整实现,TaoToken 统一 Key 接入示例 ★ FEATURED ARTICLE
1. 为什么要在 Spring AI 里把 MCP 双端跑通MCPModel Context Protocol说白了就是给大模型配一套“工具插座标准”模型不直接碰你的数据库和内部接口而是通过一份声明好的工具清单去调用。Spring AI 从 1.0.0-M6 起把 MCP 的 Server 端和 Client 端都做进了 starterJava 团队不用再自己写一套 JSON-RPC 胶水层。这篇要解决的就是一个很具体的问题怎么在同一个 Spring 生态里一边把业务能力暴露成 MCP Server一边用 MCP Client 把模型和工具串起来并且模型调用统一走 TaoToken 的 Key避免每个项目各自维护一套模型凭证。适合谁看手上已经有 Spring Boot 3.x 项目、想给现有系统加“AI 能调工具”能力的后端同学或者正在做 AI Agent 原型、被 MCP 的 SSE/STDIO 两种传输方式绕晕的人。整条链路我按“服务端暴露工具 → 客户端连接 → 模型决策 → 工具执行 → 结果回填”的顺序写每一步都给可复制的配置和代码最后用 curl 验证端到端是否真的跑通。先说清楚两个角色。MCP Server 是工具提供方它不认识模型只负责把Tool标注的方法注册成可被发现的工具通过 SSE 或 STDIO 暴露出去。MCP Client 是调用方它持有模型客户端把用户的自然语言问题交给模型模型判断需要哪个工具Client 再去 Server 拉工具列表并执行。模型这一层我们统一指向 TaoToken 的 OpenAI 兼容接口Base URL 用https://taotoken.net/apiKey 在控制台生成这样 Server 和 Client 两个工程只需要一份模型凭证。一个容易踩的认知坑很多人以为 MCP Server 里也要配模型。不需要。Server 只做工具声明与执行模型推理全部发生在 Client 侧。你把模型配置塞进 Server只会多一份无用的连接。下面第 2 节先把 Key 和依赖版本定下来第 3 节开始写代码。2. TaoToken 前置准备与 Spring AI 版本对齐统一 Key 的意思是模型对话、工具调用决策都走同一个入口工程里只出现一处base-url和一处api-key。先去 TaoToken 控制台创建 API Key地址是https://taotoken.net/api-keys生成后复制成环境变量别硬编码进 yml。模型 ID 在模型对话页能看到当前可用的名称选一个支持 function calling 的对话模型即可工具调用依赖这个能力。依赖版本必须对齐这是 Spring AI MCP 最容易翻车的地方。BOM 版本、mcp-server starter、mcp-client starter、openai starter 四者版本要一致混用不同 milestone 会出现NoSuchMethodError或者工具列表为空。下面这份pom.xml片段是双端工程共用的版本管理部分properties java.version21/java.version spring-ai.version1.0.0-M6/spring-ai.version /properties dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version${spring-ai.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagementServer 端额外引入 WebFlux 版 MCP Server starter走 SSE 传输Client 端引入 MCP Client starter 加 OpenAI 模型 starter。注意 Client 端不要引 WebFlux 的 server starter否则端口会和你的业务服务打架。环境变量这样设Linux/macOS 用 exportWindows 用系统环境变量面板export TAOTOKEN_API_KEYsk-你的Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api模型名建议单独放一个变量TAOTOKEN_MODEL方便切换。这里有个细节OpenAI 兼容接口的 base-url 末尾不要带/v1Spring AI 的 OpenAI starter 会自己拼路径多写一段会变成/v1/v1/chat/completions直接 404。我试过在 yml 里写完整路径结果报404 Not Found去掉后缀就好了。版本对齐之后两个工程的目录结构建议分开mcp-server和mcp-client各自独立启动Server 默认 8081Client 默认 8080避免端口冲突。下面进入具体配置。3. 可复制配置application.yml 与工具声明先写 Server 端。application.yml里开启 MCP Server、指定名称版本和 SSE 端点同时把 WebFlux 端口改成 8081server: port: 8081 spring: application: name: weather-mcp-server ai: mcp: server: enabled: true name: weather-mcp-server version: 1.0.0 type: SYNC sse-endpoint: /mcp/stream工具类用Tool注解声明description 要写清楚“什么时候该调用”模型靠这句话做决策写得太含糊会导致工具不被选中。下面这个天气工具返回结构化 Map方便模型二次组织语言Component public class WeatherTool { Tool(description 查询指定城市的当前天气输入参数为城市中文名例如 深圳) public MapString, Object getCurrentWeather(String city) { System.out.printf(MCP Server 收到天气查询: %s%n, city); return Map.of( city, city, temperature, 26C, condition, 晴, humidity, 60% ); } }注册成ToolCallbackProvider这一步不做的话工具不会出现在 SSE 的工具清单里Configuration public class McpServerConfig { Bean public ToolCallbackProvider weatherTools(WeatherTool weatherTool) { return MethodToolCallbackProvider.builder() .toolObjects(weatherTool) .build(); } }Client 端的application.yml要同时配模型和 MCP 连接。模型走 TaoTokenMCP 用 SSE 连本地 Serverserver: port: 8080 spring: ai: openai: base-url: ${TAOTOKEN_BASE_URL} api-key: ${TAOTOKEN_API_KEY} chat: options: model: ${TAOTOKEN_MODEL} temperature: 0.3 mcp: client: enabled: true name: weather-mcp-client version: 1.0.0 type: SYNC sse: connections: weather-server: url: http://localhost:8081 sse-endpoint: /mcp/stream这段配置里三个关键件必须齐全Base URL 指向https://taotoken.net/apiKey 从环境变量注入Model ID 用你控制台里可用的对话模型。少任何一个Client 启动时不会报错但调用时会抛401或model not found。如果你用 Cline 或 CC Switch 这类工具做本地调试同样按这三件套填Base URL、API Key、Model ID不要只填 Key 就以为能通。工具声明和连接配置都齐了接下来写 Client 的调用代码把 ChatClient 和工具执行串起来。4. 验证请求从 curl 到端到端工具调用Client 侧的核心是把ChatClient和 MCP 工具绑定。Spring AI 的 MCP Client starter 会自动把连接到的工具注册进ToolCallbackProvider你在构建 ChatClient 时把 provider 传进去模型就能看到工具清单Service public class WeatherAgentService { private final ChatClient chatClient; public WeatherAgentService(ChatClient.Builder builder, ToolCallbackProvider toolCallbackProvider) { this.chatClient builder .defaultToolCallbacks(toolCallbackProvider) .build(); } public String ask(String question) { return chatClient.prompt() .user(question) .call() .content(); } }再暴露一个 HTTP 接口方便 curl 验证RestController public class AskController { private final WeatherAgentService agentService; public AskController(WeatherAgentService agentService) { this.agentService agentService; } PostMapping(/ask) public MapString, String ask(RequestBody MapString, String body) { String answer agentService.ask(body.get(question)); return Map.of(answer, answer); } }启动顺序很重要先起 Server8081确认 SSE 端点可访问再起 Client8080。验证 Server 是否暴露成功直接 curl SSE 端点看是否返回事件流curl -N http://localhost:8081/mcp/stream正常会看到event: endpoint之类的 SSE 帧说明工具清单通道已打开。然后调 Client 的接口curl -X POST http://localhost:8080/ask \ -H Content-Type: application/json \ -d {question:深圳今天天气怎么样}预期返回类似深圳今天晴气温 26C湿度 60%。同时 Server 控制台会打印MCP Server 收到天气查询: 深圳这条日志是端到端打通的最硬证据——它证明模型确实做出了工具调用决策Client 也确实把参数传到了 Server 并执行。如果只看到模型回复“我无法获取实时天气”说明工具没被注册进 ChatClient回去检查defaultToolCallbacks是否传了 provider。再补一个多轮验证连续问“北京呢”观察 Server 日志是否再次打印。两次都命中说明工具清单在会话间是复用的不是一次性绑定。到这一步模型调用走 TaoToken、工具注册走 MCP Server、调用决策走 MCP Client整条链路闭环。5. 本篇常见错排查401、local proxy failed 与工具为空排障按报错原文对照别凭感觉改配置。下面这几个是我在实际项目里反复遇到的。401 Unauthorized出现在 Client 调用模型时九成是 Key 没注入或 base-url 写错。检查环境变量是否在当前 shell 生效echo $TAOTOKEN_API_KEY看有没有值再确认 yml 里是${TAOTOKEN_BASE_URL}而不是写死的带/v1的地址。TaoToken 的 API 入口是https://taotoken.net/api路径拼接交给 starter。local proxy failed或连接被拒通常是 Client 连 Server 的地址不对。SSE 连接配置里url是主机加端口sse-endpoint是路径两者不要重复拼。比如写成url: http://localhost:8081/mcp/stream再加sse-endpoint: /mcp/stream实际请求会变成双路径。正确写法就是第 3 节那份url 只到端口。reading choices或反序列化异常多半是模型返回结构和你预期不符常见于模型 ID 填错、走到了非对话模型。回控制台确认 Model ID并确认该模型支持 function calling。还有一种情况是 temperature 设太高导致工具参数格式漂移调到 0.3 以下更稳。工具列表为空、模型始终不调用工具检查三处Server 端ToolCallbackProviderBean 是否被扫描到配置类别放在启动类扫描不到的包Client 端构建 ChatClient 时是否真的传了 providerTool的 description 是否写清了触发条件。另外 SYNC/ASYNC 类型两端要一致一端 SYNC 一端 ASYNC 会出现握手后工具清单拉取失败。OAuth 相关报错一般出现在你误配了需要鉴权的远程 MCP 服务本地自建 Server 不需要 OAuth把多余的鉴权配置删掉即可。如果确实要接第三方远程 MCP鉴权信息放在对应 connection 下别塞进全局模型配置里。最后提醒一个隐蔽问题Server 和 Client 都用spring.ai.mcp前缀但子键不同复制配置时容易把 server 段贴到 client 工程里启动不报错但行为诡异。建议两个工程的 yml 分开维护改完用curl各验一次再联调。6. 把 Key 与工具链固定下来的下一步链路跑通后建议把模型凭证和工具连接都收敛到环境变量加一份共享配置模板团队里谁拉代码都只改 Key 不改结构。模型侧继续用 TaoToken 的统一入口工具侧把新增业务能力按Tool方法增量注册Server 不用重启模型配置。需要长期跑编码类 Agent 的可以看 Coding Plan 的额度方式只是验证模型和工具是否通用模型对话页手动发一轮请求最快接入细节和参数说明在接入文档里查。把第 4 节的 curl 命令存成脚本每次改完配置跑一遍比肉眼检查 yml 靠谱得多。
阅读完成 · 觉得有帮助?
咨询建站