1. 为什么要在 Spring AI 里接 MCP,以及这套组合到底解决什么问题
如果你正在用 Spring Boot 写 AI 应用,大概率遇到过这种尴尬:模型能聊天,但一让它查数据库、读文件、调内部接口,就得自己写一堆@Tool函数,每个项目重复一遍,工具定义和模型调用逻辑搅在一起。MCP(Model Context Protocol,模型上下文协议)就是来治这个病的——它把「工具/资源」从应用里抽出来,变成独立的 MCP Server,通过 JSON-RPC 2.0 标准协议暴露给任何支持 MCP 的客户端。Spring AI 从 1.0.0-M4 开始正式支持 MCP Client,意味着你可以在 Spring 生态里用注解和配置把远程工具挂到 ChatClient 上。
这套组合适合谁?三类人:一是做企业内部 AI 助手的后端同学,需要把已有微服务包装成模型可调用的工具;二是想快速验证 Agent 场景的独立开发者,不想为每个工具写胶水代码;三是已经在用 Spring AI 但被工具管理搞烦的团队。核心检索词就是「Spring AI MCP 集成」和「MCP Client 配置」,本文会围绕这两个点把最小闭环跑通。
我试过直接手写 JSON-RPC 调 MCP Server,能跑但太原始,后来换成 Spring AI 的spring-ai-mcp-client-spring-boot-starter,配置量直接砍掉八成。下面从依赖、配置、代码到验证,一步步来。
2. TaoToken 前置准备:统一 Key 与 API 通道怎么配
模型侧如果每个项目都去申请不同厂商的 Key,管理成本很高。TaoToken 提供统一 Key 和 API 通道,OpenAI 兼容格式,Spring AI 的spring-ai-openai-spring-boot-starter可以直接对接,不用改代码结构。你需要先拿到两样东西:API Key 和 Base URL。
访问 https://taotoken.net/api 可以查看接口说明,Key 在控制台生成:https://taotoken.net/console 。生成后建议单独建一个环境变量文件,别硬编码进application.yml,后面 Docker 部署也方便。
模型 ID 这块要注意,Spring AI 的 OpenAI starter 默认走gpt-4之类的名字,但实际请求时model字段要填 TaoToken 支持的模型 ID。你可以在模型对话页面先确认可用模型:https://taotoken.net/models ,选一个支持 function calling 的,因为 MCP 工具调用依赖模型的 tool use 能力。如果模型不支持 function calling,工具链路会在tools/call那一步静默失败,返回的choices里没有tool_calls字段,排查起来很费劲。
配置上,Spring AI 的 OpenAI 客户端读三个关键属性:spring.ai.openai.api-key、spring.ai.openai.base-url、spring.ai.openai.chat.options.model。Base URL 填https://taotoken.net/api,注意结尾不要带/v1,Spring AI 会自己拼/v1/chat/completions。如果你填成https://taotoken.net/api/v1,请求路径会变成/api/v1/v1/chat/completions,直接 404。
提示:Key 泄露风险高,建议用
${TAOTOKEN_API_KEY}占位,本地用 IDE 的 EnvFile 插件或export注入,生产用 K8s Secret 或 Docker env。
3. 可复制配置:application.yml 与 Maven 依赖完整片段
先看 Maven 依赖。Spring AI 的版本管理用 BOM,MCP Client starter 在 1.0.0-M4 里叫spring-ai-mcp-client-spring-boot-starter。注意仓库要加 Spring Milestones,因为 GA 版本还没发。
<properties> <java.version>17</java.version> <spring-ai.version>1.0.0-M4</spring-ai.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>${spring-ai.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots><enabled>false</enabled></snapshots> </repository> </repositories>然后是application.yml。MCP Client 支持 stdio 和 SSE 两种传输,本地开发用 stdio 起一个 Node 写的 MCP Server 最省事,远程用 SSE。这里给 SSE 配置,因为更贴近生产。
spring: application: name: spring-ai-mcp-demo ai: openai: api-key: ${TAOTOKEN_API_KEY} base-url: https://taotoken.net/api chat: options: model: gpt-4o-mini temperature: 0.3 mcp: client: enabled: true name: demo-mcp-client version: 1.0.0 type: SYNC request-timeout: 30s sse: connections: demo-server: url: http://localhost:8081 sse-endpoint: /sse server: port: 8080 logging: level: org.springframework.ai: DEBUG io.modelcontextprotocol: DEBUG关键点:spring.ai.mcp.client.sse.connections下面可以挂多个 Server,每个有个名字(这里是demo-server),后面代码里按名字取。sse-endpoint是 MCP Server 暴露 SSE 的路径,默认/sse,如果你的 Server 改了要同步。type: SYNC表示同步客户端,适合请求-响应模式;如果要流式,改成ASYNC。
注意:
request-timeout别设太短,MCP 工具调用可能涉及远程 IO,30 秒比较稳。设成 5 秒的话,稍微慢一点的数据库查询就超时了。
4. MCP Server 注册与端到端调用验证
配置写完后,Spring AI 会自动创建McpSyncClientBean。你需要做的是把它注册到ToolCallbackProvider,再挂到ChatClient上。下面是一个完整的配置类。
package com.example.mcpdemo.config; import org.springframework.ai.mcp.SyncMcpToolCallbackProvider; import org.springframework.ai.tool.ToolCallbackProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import io.modelcontextprotocol.client.McpSyncClient; import java.util.List; @Configuration public class McpToolConfig { @Bean public ToolCallbackProvider mcpToolCallbackProvider(List<McpSyncClient> mcpSyncClients) { return new SyncMcpToolCallbackProvider(mcpSyncClients); } }SyncMcpToolCallbackProvider会遍历所有McpSyncClient,调用tools/list拿到工具列表,包装成 Spring AI 的ToolCallback。这样 ChatClient 在发起请求时,会自动把这些工具塞进tools字段。
接着是 ChatClient 的配置和 Controller。
package com.example.mcpdemo.service; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.tool.ToolCallbackProvider; import org.springframework.stereotype.Service; @Service public class ChatService { private final ChatClient chatClient; public ChatService(ChatClient.Builder builder, ToolCallbackProvider toolCallbackProvider) { this.chatClient = builder .defaultToolCallbacks(toolCallbackProvider) .build(); } public String chat(String message) { return chatClient.prompt() .user(message) .call() .content(); } }Controller 就一行转发:
@RestController @RequestMapping("/api") public class ChatController { private final ChatService chatService; public ChatController(ChatService chatService) { this.chatService = chatService; } @PostMapping("/chat") public Map<String, String> chat(@RequestBody Map<String, String> body) { String reply = chatService.chat(body.get("message")); return Map.of("reply", reply); } }验证动作:先起一个 MCP Server。如果你没有现成的,可以用官方 filesystem server 测试,它提供read_file、list_directory等工具。启动后确认http://localhost:8081/sse能连上。然后启动 Spring Boot 应用,发一条请求:
curl -X POST http://localhost:8080/api/chat \ -H "Content-Type: application/json" \ -d '{"message":"帮我列出 /tmp 目录下的文件"}'如果链路通了,日志里会看到io.modelcontextprotocol打印的tools/list响应,包含工具名和 inputSchema;接着是tools/call,参数是模型生成的{"path":"/tmp"};最后模型把工具返回的 JSON 转成自然语言回复。返回体类似:
{"reply":"/tmp 目录下有 a.txt、b.log 两个文件。"}这一步成功,说明 Spring AI + MCP + TaoToken 的最小闭环打通了。模型侧走 TaoToken 的 OpenAI 兼容通道,工具侧走 MCP 标准协议,两边解耦。
5. 本篇常见错误排查:401、local proxy failed、reading choices、OAuth
401 Unauthorized:最常见。先看spring.ai.openai.api-key有没有读到环境变量。如果用了${TAOTOKEN_API_KEY}但启动时没注入,Spring 会报Could not resolve placeholder,不是 401。真正的 401 是 Key 无效或过期。去控制台重新生成一个,注意别把 Key 前后的空格复制进去。还有一种情况是 Base URL 写错,比如写成https://taotoken.net少了/api,请求打到首页返回 HTML,Spring AI 解析失败会报Unrecognized token。
local proxy failed / Connection refused:这个报错通常出现在 MCP Client 连 SSE 的时候。检查spring.ai.mcp.client.sse.connections.demo-server.url的端口和 MCP Server 实际监听端口是否一致。如果 MCP Server 还没启动,Spring Boot 启动时McpSyncClient初始化会失败,日志里是Failed to connect to SSE endpoint。解决办法是把 MCP Client 的初始化改成懒加载,或者确保 Server 先起。另外sse-endpoint路径别写错,有些 Server 用/mcp/sse。
reading choices 相关报错:典型的是Cannot deserialize value of type ... from Array value (token JsonToken.START_ARRAY)或者reading choices时 NPE。这多半是模型返回的choices为空数组,原因通常是模型不支持 function calling,或者请求里tools字段格式不对。先确认 TaoToken 控制台里选的模型支持 tool use,再把日志级别调到 DEBUG,看请求体里tools是不是合法 JSON Schema。如果tools为空数组,说明ToolCallbackProvider没注册成功,检查McpToolConfig有没有被扫描到。
OAuth 相关报错:如果你接的 MCP Server 需要 OAuth 鉴权,Spring AI 1.0.0-M4 的 MCP Client 对 OAuth 支持还不完整,会报401或invalid_token。临时方案是在 SSE 连接配置里加自定义 header,比如spring.ai.mcp.client.sse.connections.demo-server.headers.Authorization=Bearer xxx。长期方案是等 Spring AI 后续版本,或者自己在McpSyncClient初始化时注入HttpRequestCustomizer。
Codex auth.json / CC Switch / Cline MCP 三件套:如果你同时用 Codex 或 Cline 这类工具,它们的 MCP 配置和 Spring AI 不共享。Codex 的auth.json里存的是它自己的凭证,CC Switch 管的是 Claude Code 的配置切换,Cline 的 MCP 配置在 VS Code settings 里。这三者和 Spring AI 的application.yml是独立的,别混用。Spring AI 这边只要保证 Base URL、Key、Model ID 三件套正确即可:Base URL 是https://taotoken.net/api,Key 是控制台生成的,Model ID 是支持 function calling 的模型名。
6. 把闭环跑稳之后,下一步可以做什么
最小闭环跑通只是起点。实际项目里,MCP Server 往往不止一个,你可能同时挂文件系统、数据库、内部 API 三个 Server。Spring AI 的sse.connections支持配多个,每个名字不同,SyncMcpToolCallbackProvider会自动聚合所有工具。但要注意工具名冲突——两个 Server 都提供read_file的话,后注册的会覆盖前面的。解决办法是在 MCP Server 侧给工具加前缀,比如fs_read_file、db_query。
另一个坑是工具调用的上下文长度。MCP 的tools/list返回的 inputSchema 会全部塞进请求的tools字段,工具多了 token 消耗涨得很快。实测下来,10 个工具、每个 schema 200 token,一轮对话光工具定义就 2000 token。优化方向是按需加载,或者用 MCP 的resources机制把大块数据放资源里,工具只传 URI。
最后,TaoToken 的 Coding Plan 适合长期跑 Agent 场景,https://taotoken.net/coding-plan 有详细的额度说明。如果你只是验证模型对话,https://taotoken.net/chat 可以直接试。接入文档在 https://taotoken.net/doc ,API Keys 管理在 https://taotoken.net/api-keys 。Claude Code 相关的 Anthropic 兼容配置参考 https://taotoken.net/claude-code 。把这些地址存书签,下次配新项目直接翻。