Spring AI + MCP 实战:Java 应用调用外部工具的配置与验证

发布时间:2026/9/28 4:06:43
Spring AI + MCP 实战:Java 应用调用外部工具的配置与验证 1. 为什么 Java 后端要接 MCP从“写死工具”到“按需调用”如果你写过 Spring Boot 调大模型大概率经历过这个阶段想让模型查个天气、读个数据库、调个内部接口就得在代码里写一堆if-else或者Tool注解工具一多ChatClient的配置就变成一坨。更麻烦的是工具逻辑和业务代码耦合在一起换个模型、加个工具都要重新打包发版。MCPModel Context Protocol解决的正是这个问题。你可以把它理解成“AI 世界的 USB-C 接口”模型侧不需要知道工具具体怎么实现工具侧也不需要关心是哪个模型在调用双方只认一套标准协议。对 Java 开发者来说Spring AI 已经把 MCP 的客户端能力封装好了你只需要配置一个McpSyncClient就能让 Java 应用像调用本地方法一样调用外部工具。这篇面向的是需要打通 Java 侧工具调用的后端开发者尤其是已经在用 Spring Boot、想快速验证 MCP 链路的同学。我会给出可复制的 MCP 客户端配置骨架配合 TaoToken 统一 Key/API 通道接入示例最后跑一次真实的工具调用验证动作并告诉你预期结果长什么样。整个过程不需要你改模型代码也不需要自己实现协议解析。先说清楚适合谁如果你只是想让模型聊聊天那用不上 MCP但如果你需要让 Java 应用动态发现工具、按需调用、并且工具和模型解耦那这套组合值得花半小时跟一遍。2. 前置准备TaoToken 统一 Key 与依赖坐标在写配置之前先把“通道”和“依赖”两件事搞定。MCP 本身只管工具调用协议模型请求还是得走一个兼容 OpenAI 接口的通道。我这边用的是 TaoToken 的统一 Key好处是一个 Key 能覆盖模型对话和后续的 coding 场景不用在多个平台之间来回切。2.1 拿 Key 与确认 API 地址登录 TaoToken 控制台后在 API Keys 页面创建一个新 Key。建议按项目命名比如spring-ai-mcp-demo方便后面排查是哪个应用在调用。创建完复制出来只显示一次。API 地址用https://taotoken.net/api注意这个地址不带任何查询参数直接作为base-url使用。模型对话相关的入口在控制台里也能找到验证阶段可以直接用模型对话页面确认 Key 是否生效。注意Key 不要硬编码进application.yml提交到仓库本地用环境变量线上用配置中心。下面示例里我用${TAOTOKEN_API_KEY}占位。2.2 Maven 依赖Spring AI 的 MCP 客户端 starter 目前还在快速迭代建议锁定一个稳定版本。下面这套坐标我实测能跑通dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version1.0.0-M6/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-client/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId /dependency /dependenciesspring-ai-starter-mcp-client负责 MCP 协议通信spring-ai-openai-spring-boot-starter负责走 OpenAI 兼容接口。两个 starter 分工明确别只引一个。2.3 MCP Server 从哪来MCP 客户端要连一个 Server 才有工具可调。Server 可以是别人写好的比如文件系统、Git 操作类也可以是你自己用 Spring AI 的spring-ai-starter-mcp-server起的。本文重点在客户端配置所以假设你已经有一个可用的 MCP Server地址形如http://localhost:8081传输方式用 SSE。3. 可复制配置MCP 客户端骨架与 ChatClient 装配这一章是核心配置分两块application.yml里的连接参数和 Java 配置类里的 Bean 装配。两块都给你完整代码改改地址就能用。3.1 application.yml 连接参数spring: ai: openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: gpt-4o-mini temperature: 0.3 mcp: client: enabled: true name: java-mcp-client version: 1.0.0 type: SYNC request-timeout: 30s sse: connections: demo-server: url: http://localhost:8081 sse-endpoint: /sse几个参数说明一下。type: SYNC表示用同步客户端适合大多数后端场景如果你要并发调多个工具可以换成ASYNC。request-timeout别设太短工具执行慢的时候容易误判超时。sse-endpoint要和你的 MCP Server 实际暴露的路径一致常见的是/sse也有用/mcp/sse的连不上先查这里。3.2 Java 配置类装配 ToolCallbackProviderConfiguration public class McpClientConfig { Bean public ToolCallbackProvider toolCallbackProvider( ListMcpSyncClient mcpSyncClients) { return ToolCallbackProvider.from(mcpSyncClients); } Bean public ChatClient chatClient( ChatClient.Builder builder, ToolCallbackProvider toolCallbackProvider) { return builder .defaultSystem(你是一个 Java 后端助手需要外部信息时调用可用工具。) .defaultToolCallbacks(toolCallbackProvider) .build(); } }这里的关键是ToolCallbackProvider.from(mcpSyncClients)。Spring AI 会自动把 yml 里配置的 SSE 连接实例化成McpSyncClient你只要把它们收集起来交给ToolCallbackProvider再挂到ChatClient上。挂载之后模型在对话中就能“看到”这些工具的描述并决定是否调用。3.3 工具调用的触发方式不需要你手动写调用代码。当用户提问涉及工具能力时模型会返回一个 tool call 请求Spring AI 拦截后通过 MCP 客户端转发给 Server拿到结果再回填给模型最后输出自然语言回答。整个过程对业务代码透明你只管调chatClient.prompt()。如果你想让某个工具强制被调用可以在 prompt 里明确说“请使用工具查询”但正常场景下让模型自己判断更自然。4. 验证请求一次真实工具调用与预期结果配置写完跑一个最小验证。假设你的 MCP Server 上挂了一个“查询当前时间”的工具名字叫get_current_time。4.1 验证代码RestController public class McpDemoController { private final ChatClient chatClient; public McpDemoController(ChatClient chatClient) { this.chatClient chatClient; } GetMapping(/ask) public String ask(RequestParam String q) { return chatClient.prompt() .user(q) .call() .content(); } }启动应用后请求curl http://localhost:8080/ask?q现在几点了请用工具查一下4.2 预期结果与日志特征正常情况下你会看到返回类似“当前时间是 2025-01-15 14:32:10”。同时在应用日志里能看到两段关键信息一段是模型返回的 tool call 请求包含工具名和参数另一段是 MCP 客户端把工具执行结果回传后的二次模型请求。这两段日志出现说明 MCP 链路是通的。如果返回的是“我无法获取实时时间”那大概率是工具没被挂载上或者模型没识别到工具描述。先检查ToolCallbackProvider是否注入了非空的 client 列表。4.3 用模型对话页面交叉验证有时候你分不清是 MCP 的问题还是 Key 的问题。这时候可以打开 TaoToken 的模型对话入口用同一个 Key 直接问一句普通问题。如果那边正常、这边工具调用失败问题就锁定在 MCP 配置如果那边也报鉴权错误那就是 Key 或 base-url 的问题。这个交叉验证能省不少排查时间。5. 本篇常见错排查连不上、工具不触发、超时这一章按报错现象来都是我实际踩过的。5.1 SSE 连接 404 或 connection refused先确认 MCP Server 是否真的在跑端口对不对。然后检查sse-endpoint路径。有些 Server 的 SSE 路径是/sse有些是/mcp/sse还有的区分大小写。用浏览器或 curl 直接访问http://localhost:8081/sse能看到事件流输出就说明路径对了。如果 Server 在容器里注意localhost在容器网络里指向的是容器自己要换成宿主机 IP 或服务名。5.2 工具列表为空模型不触发调用日志里如果看到No tool callbacks registered说明ToolCallbackProvider没拿到 client。检查两点一是 yml 里spring.ai.mcp.client.enabled是否为 true二是McpSyncClient的 Bean 是否被 Spring 扫描到。有时候 starter 版本不匹配会导致 client 不自动装配这时候需要手动声明McpClientBean。另一个常见原因是工具描述太模糊模型判断不出该不该调。可以在 Server 侧把工具描述写清楚比如“查询当前系统时间无需参数返回 ISO 格式字符串”。5.3 请求超时但工具实际执行成功这种多半是request-timeout设太短或者工具执行本身慢。先把超时调到 60s 观察。如果还是超时看 MCP Server 侧日志确认工具是否真的执行完了。有些 Server 在工具执行完后没有正确发送响应事件客户端就会一直等。这种情况要检查 Server 的 MCP 实现是否符合协议版本。5.4 鉴权失败 401如果日志里出现 401先确认TAOTOKEN_API_KEY环境变量是否真的注入到运行进程里。用System.getenv(TAOTOKEN_API_KEY)打印一下长度别打印明文。另外确认base-url是https://taotoken.net/api末尾不要多加/v1Spring AI 的 OpenAI starter 会自己拼路径。6. 接入后的下一步把 Key 和通道固定下来链路跑通之后建议做两件事让后续开发更顺。第一件是把 Key 管理规范化。本地开发用环境变量CI 用 secret线上用配置中心。TaoToken 的 Key 可以在控制台按项目拆分不同环境用不同 Key出问题好定位。API Keys 页面还能看到调用记录排查 401 或额度问题很方便。第二件是确认你的接入方式。如果你只是偶尔验证模型和工具用模型对话入口就够了如果你要长期在 IDE 或 Agent 里跑编码任务建议看一下 Coding Plan它更适合高频、长会话的场景。接入文档里有完整的参数说明和示例遇到配置项不确定的时候直接查文档比翻源码快。我自己的习惯是新项目先把 MCP 客户端骨架和 TaoToken 通道配好跑通一次工具调用再往上叠业务逻辑。这样后面加工具、换模型都只是改配置不用动业务代码。