资讯动态

【附源码】用Spring AI统一接入所有MCP客户端,TaoToken 通道配置全解析

发布时间:2026/10/9 2:23:31 来源:尧图企业网站定制
1. 为什么 Spring AI 做 MCP 客户端总在“连不上”上翻车如果你正在用 Java 写 AI 应用大概率已经碰到过这个场景项目里想同时接地图 MCP、搜索 MCP、数据库 MCP每个服务商给的接入方式还不一样有的走 SSE有的走 stdio有的干脆给你一个远程 HTTP 端点。你一边翻文档一边改配置最后发现真正卡住你的不是业务逻辑而是“客户端到底怎么统一管起来”。Spring AI 在这件事上的定位很明确——它把 MCP 客户端抽象成了一套可配置的连接层。你不需要为每个 MCP 服务写一套独立的调用代码而是通过spring.ai.mcp.client这组配置把不同传输方式的 MCP 服务统一注册进来。启动之后Spring AI 会自动完成握手、拉取工具列表、维护会话你拿到的就是一个可以直接注入使用的McpClient或工具回调。但问题也出在这里。MCP 协议本身还在快速演进不同服务端对 SSE 端点路径、鉴权参数、初始化超时的处理并不一致。再加上很多开发者是把 MCP 服务部署在远程本地网络环境、Base URL 拼接、Key 传递位置稍有偏差就会看到Connection refused、401 Unauthorized或者工具列表为空。更麻烦的是这些报错往往不会告诉你到底是哪一层出了问题。这篇内容面向的是需要同时对接多个 MCP 服务的 Java 开发者。我会用 Spring AI 作为统一接入层把 MCP 客户端的配置片段、TaoToken 通道的 Base URL 与鉴权参数填写位置、以及启动后验证工具列表拉取成功的具体命令全部给出来。源码结构可以直接对照改配置项我会标清楚每一项填在哪里、为什么这么填。核心检索词先摆出来Spring AI 统一接入 MCP 客户端指的是用一套 Spring AI 配置管理多个不同传输方式的 MCP 服务它能做的是自动发现工具、统一鉴权、集中管理连接适合谁——正在做 Java AI 应用、需要接多个 MCP 服务端、又不想每个服务写一套适配代码的开发者。我试过把五个 MCP 服务塞进同一个 Spring Boot 应用前三个小时全花在排查“为什么这个 SSE 连上了那个连不上”上。下面把踩过的坑和最终可复制的配置一次性讲清楚。2. TaoToken 通道前置准备Base URL、Key 与模型 ID 三件套在讲 Spring AI 的 MCP 客户端配置之前得先把通道层的事情说清楚。很多开发者卡住不是因为 Spring AI 配置写错了而是通道的 Base URL 和鉴权参数没填对位置。TaoToken 在这里扮演的是统一通道的角色。你可以把它理解成一个兼容 OpenAI 接口规范的入口Spring AI 的 OpenAI Starter 可以直接把 Base URL 指向它然后用同一个 Key 去调用不同的模型。对于 MCP 场景来说这意味着你的 Spring AI 应用在启动时既可以通过这个通道完成模型侧的对话请求也可以把 MCP 客户端的连接配置集中管理。先把三件套列出来配置项填写位置说明Base URLspring.ai.openai.base-url统一通道地址不带多余路径API Keyspring.ai.openai.api-key鉴权用放在请求头Model IDspring.ai.openai.chat.options.model具体调用的模型标识Base URL 填https://taotoken.net/api注意这里不要加 UTM 参数也不要自己拼/v1之类的后缀Spring AI 的 OpenAI Starter 会按规范拼接。API Key 在控制台创建创建入口在 API Keys 页面。模型 ID 根据你实际要用的模型填比如gpt-4o、claude-3-5-sonnet这类标识具体以通道文档里列出的为准。如果你还没创建 Key操作路径是先打开模型对话页面确认通道可用然后进控制台创建 API Key。控制台地址是https://taotoken.net/consoleAPI Keys 管理页是https://taotoken.net/api-keys。这两个页面建议先收藏后面排查 401 的时候会反复用到。对于长期做编码和 Agent 的场景可以考虑 Coding Plan它更适合高频调用。接入文档在https://taotoken.net/doc里面会持续更新各语言 SDK 的接入示例。Claude Code 相关的接入说明在https://taotoken.net/ClaudeCodeAnthropic如果你同时用 Claude Code 做本地开发可以参考那份配置。这里要强调一个容易忽略的点Spring AI 的 MCP 客户端配置和模型通道配置是两套东西。MCP 客户端负责连 MCP 服务端、拉工具列表模型通道负责实际对话时的推理请求。两者可以共用同一个 Key但 Base URL 的填写位置不同。MCP 服务端如果是远程 SSE它的 URL 是服务商给的不是 TaoToken 的地址TaoToken 的 Base URL 只填在spring.ai.openai.base-url这一项。把这三件套准备好之后再往下看 Spring AI 的 MCP 客户端配置就不会出现“Key 填了但不知道填哪”的情况。3. 可复制配置Spring AI MCP 客户端 SSE 与 stdio 双模式这一节直接给可复制的配置片段。Spring AI 的 MCP 客户端支持两种主流传输方式SSE 和 stdio。SSE 适合远程 MCP 服务stdio 适合本地进程启动的 MCP 服务。两种可以同时存在Spring AI 会分别管理。先看application.yml里的核心配置。路径是src/main/resources/application.ymlspring: ai: openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: gpt-4o mcp: client: enabled: true name: spring-ai-mcp-client version: 1.0.0 request-timeout: 30s type: SYNC sse: connections: map-server: url: https://mcp.map.qq.com sse-endpoint: /sse?key${MAP_MCP_KEY}format0 search-server: url: https://your-search-mcp-host sse-endpoint: /sse stdio: servers-configuration: classpath:mcp-servers.json这里有几个关键点。spring.ai.mcp.client.type填SYNC表示同步客户端如果你要用异步工具回调可以改成ASYNC。request-timeout建议设成 30 秒以上因为部分 MCP 服务端初始化较慢默认超时容易在启动阶段就断开。SSE 连接部分每个服务用connections下的一个子键区分。url是服务端根地址sse-endpoint是具体的 SSE 路径。注意有些服务商把 Key 放在 query 参数里比如上面地图服务的keyxxxformat0这种就按服务商文档原样拼在sse-endpoint后面。不要把 Key 放到url里否则 Spring AI 拼接路径时可能出错。stdio 模式通过一个 JSON 文件描述本地启动命令。文件路径是src/main/resources/mcp-servers.json{ mcpServers: { local-weather: { command: java, args: [ -Dspring.ai.mcp.server.stdiotrue, -Dspring.main.web-application-typenone, -Dlogging.pattern.console, -jar, ./mcp-server/target/mcp-server-1.0-SNAPSHOT.jar ] }, local-db: { command: npx, args: [ -y, modelcontextprotocol/server-sqlite, ./data/app.db ] } } }这个 JSON 的结构和 Claude Desktop 的配置文件格式一致所以如果你之前配过 Claude Desktop可以直接把那段mcpServers内容搬过来。Spring AI 会读取这个文件按command和args启动子进程然后通过标准输入输出完成 MCP 握手。如果你用的是application.properties而不是 YAML等价写法是spring.ai.openai.base-urlhttps://taotoken.net/api spring.ai.openai.api-key${TAOTOKEN_API_KEY} spring.ai.openai.chat.options.modelgpt-4o spring.ai.mcp.client.enabledtrue spring.ai.mcp.client.namespring-ai-mcp-client spring.ai.mcp.client.version1.0.0 spring.ai.mcp.client.request-timeout30s spring.ai.mcp.client.typeSYNC spring.ai.mcp.client.sse.connections.map-server.urlhttps://mcp.map.qq.com spring.ai.mcp.client.sse.connections.map-server.sse-endpoint/sse?key${MAP_MCP_KEY}format0 spring.ai.mcp.client.stdio.servers-configurationclasspath:mcp-servers.json依赖方面pom.xml里需要引入 Spring AI 的 OpenAI Starter 和 MCP Client Starterdependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-mcp-client-spring-boot-starter/artifactId /dependency版本号建议用 Spring AI 的 BOM 统一管理避免 starter 之间版本不一致导致自动配置失效。如果你在pom.xml里看到spring-ai-bom的dependencyManagement把版本对齐到同一个即可。配置写完之后启动类不需要额外加注解Spring AI 的自动配置会扫描spring.ai.mcp.client前缀并注册McpClientBean。你可以在任意Component里注入McpClient或ListMcpSyncClient来使用。4. 验证请求启动后拉取 MCP 工具列表的完整命令与预期返回配置写完只是第一步真正要确认的是 MCP 客户端有没有成功连上、工具列表有没有拉下来。这一节给两种验证方式一种是通过 Spring Boot 启动日志观察另一种是写一个简单的 CommandLineRunner 主动拉取工具列表。先看启动日志。正常启动后你会在控制台看到类似这样的输出INFO o.s.a.m.c.McpClientAutoConfiguration - Registered MCP client: spring-ai-mcp-client INFO o.s.a.m.c.sse.SseMcpClient - Connecting to SSE endpoint: https://mcp.map.qq.com/sse?key***format0 INFO o.s.a.m.c.sse.SseMcpClient - SSE connection established, session id: abc123 INFO o.s.a.m.c.McpClientImpl - Initializing MCP client, protocol version: 2024-11-05 INFO o.s.a.m.c.McpClientImpl - Discovered 6 tools from server: map-server INFO o.s.a.m.c.stdio.StdioMcpClient - Starting stdio server: local-weather INFO o.s.a.m.c.stdio.StdioMcpClient - Discovered 3 tools from server: local-weather关键行是Discovered N tools from server: xxx。如果每个服务都打印了工具数量说明握手和工具发现都成功了。如果某个服务只打印了连接建立但没有工具发现通常是初始化超时或者服务端返回了错误。更可靠的验证方式是主动拉取。写一个CommandLineRunnerimport org.springframework.ai.mcp.client.McpClient; import org.springframework.ai.mcp.spec.McpSchema; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; import java.util.List; Component public class McpToolListVerifier implements CommandLineRunner { private final ListMcpClient mcpClients; public McpToolListVerifier(ListMcpClient mcpClients) { this.mcpClients mcpClients; } Override public void run(String... args) { for (McpClient client : mcpClients) { System.out.println( MCP Client: client.getClientInfo().name() ); McpSchema.ListToolsResult result client.listTools(); result.tools().forEach(tool - { System.out.println(Tool: tool.name()); System.out.println( Description: tool.description()); System.out.println( Input Schema: tool.inputSchema()); }); } } }启动应用后预期返回类似 MCP Client: spring-ai-mcp-client Tool: get_current_weather Description: 获取指定城市的实时天气 Input Schema: {typeobject, properties{city{typestring}}, required[city]} Tool: search_news Description: 按关键词搜索新闻 Input Schema: {typeobject, properties{keyword{typestring}, limit{typeinteger}}, required[keyword]} Tool: query_database Description: 执行只读 SQL 查询 Input Schema: {typeobject, properties{sql{typestring}}, required[sql]}如果你看到工具名和描述都打印出来了说明 MCP 客户端已经完整可用。接下来就可以在业务代码里通过McpClient.callTool()调用具体工具。还有一个快速验证通道是否可用的方式用 curl 直接请求 TaoToken 的模型接口确认 Key 和 Base URL 没问题curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o, messages: [{role: user, content: ping}] }预期返回里会有choices数组和正常的content。如果这里返回 401说明 Key 有问题如果返回 404说明 Base URL 拼错了。这一步能快速把通道问题和 MCP 问题分开。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth这一节按真实报错来排查。下面这几个错误是我在实际接入过程中反复遇到的每个都给出定位方法和修复方式。401 Unauthorized这个最常见。先确认 Key 填在了正确的位置。如果你用的是 TaoToken 通道Key 应该填在spring.ai.openai.api-key而不是 MCP 的 SSE 配置里。MCP 服务端如果需要鉴权它的 Key 是服务商单独给的填在sse-endpoint的 query 参数里。排查命令echo $TAOTOKEN_API_KEY curl -H Authorization: Bearer $TAOTOKEN_API_KEY https://taotoken.net/api/v1/models如果 curl 也返回 401说明 Key 本身无效或已过期去 API Keys 页面重新创建一个。如果 curl 正常但 Spring AI 报 401检查application.yml里有没有把 Key 写成了${TAOTOKEN_API_KEY}但环境变量没注入。Spring Boot 读取环境变量时${TAOTOKEN_API_KEY}需要系统环境里真的有这个变量或者在application.yml同级目录放一个.env并引入。local proxy failed这个报错通常出现在 stdio 模式。Spring AI 启动子进程时如果command指向的可执行文件不在 PATH 里或者args里的 jar 路径不对就会报local proxy failed。排查步骤which java which npx ls -la ./mcp-server/target/mcp-server-1.0-SNAPSHOT.jar确认command用的可执行文件能被找到args里的路径是绝对路径或相对于工作目录的正确路径。如果你在 IDE 里启动工作目录可能是项目根目录但打包后运行 jar 时工作目录会变建议统一用绝对路径。reading choices 报错这个报错一般出现在模型通道侧说明 Spring AI 调用 OpenAI 兼容接口时返回体里没有choices字段。常见原因是 Base URL 填成了https://taotoken.net/api但实际请求路径被拼成了/api/chat/completions而正确路径应该是/api/v1/chat/completions。检查方式curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:gpt-4o,messages:[{role:user,content:hi}]}如果这个 curl 正常返回choices但 Spring AI 报错检查spring.ai.openai.base-url是不是多写了/v1。Spring AI 的 OpenAI Starter 会自动补/v1/chat/completions所以 Base URL 只需要填到https://taotoken.net/api。OAuth 相关报错部分 MCP 服务端要求 OAuth 鉴权返回OAuth token missing或invalid_token。这种服务端通常需要在 SSE 连接建立后通过一个额外的授权步骤获取 token。Spring AI 目前对 OAuth 的支持取决于版本如果你的版本不支持自动 OAuth 流程可以先用服务商提供的静态 token 填在sse-endpoint的 query 参数里或者改用 stdio 模式在本地启动。排查时先看服务商文档里有没有“获取 access token”的步骤如果有先用 curl 拿到 token再把它拼到 SSE URL 里测试。工具列表为空连接建立成功但listTools()返回空列表通常是 MCP 服务端初始化还没完成Spring AI 就去拉列表了。把request-timeout调大到 60s或者在CommandLineRunner里加一个短暂的Thread.sleep(2000)再拉取。另外确认服务端确实注册了工具有些 MCP 服务端需要额外参数才会暴露工具。6. 语义一致 CTA把 MCP 客户端接入落到可复用的工程结构走到这里Spring AI 作为 MCP 客户端统一接入层的核心配置已经全部给出来了。从application.yml里的 SSE 和 stdio 双模式配置到mcp-servers.json的本地进程描述再到启动后拉取工具列表的验证代码这一套结构可以直接复制到你的项目里。如果你在排查 401 或通道问题时需要确认 Key 和 Base URL先去 API Keys 页面检查 Key 状态再对照接入文档确认路径拼接方式。模型对话页面可以用来快速验证通道是否可用不用写代码就能确认请求能不能通。对于需要长期跑编码 Agent 的场景Coding Plan 在调用频率和稳定性上更适合持续使用。Claude Code 的接入配置在 ClaudeCodeAnthropic 页面有单独说明如果你同时用 Claude Code 做本地开发可以把 MCP 客户端配置和 Claude Code 的配置放在同一个工程里管理。最后给一个实用建议把 MCP 客户端的配置和模型通道的配置分成两个 profile。本地开发用application-local.yml把 stdio 模式的本地 MCP 服务打开线上部署用application-prod.yml只保留 SSE 模式的远程 MCP 服务。这样切换环境时不会因为本地路径问题导致启动失败。工具列表验证的CommandLineRunner建议只在本地 profile 里启用线上不需要每次启动都打印一遍工具列表。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑