1. 存量 Spring 系统为什么需要 MCP 工具化
很多团队手里都有一套跑了三五年的 Spring 系统,接口稳定、权限体系完整、业务逻辑沉淀得很厚。问题在于,当 AI 助手想调用这些能力时,往往只能靠人工写提示词、贴接口文档,模型既不知道有哪些接口,也不知道参数怎么填。MCP(Model Context Protocol)解决的正是这件事:它把「系统能做什么」变成模型可发现、可调用的工具清单,相当于给 AI 装了一个标准插座。
SpringAI-MCP 是 Spring 生态里落地 MCP 的官方路径,它允许你用注解把普通方法暴露成 MCP 工具。但存量系统有个现实约束:业务代码不能动。所以真正可行的做法不是去改 Controller,而是让 MCP 服务端以「旁路」方式把既有 REST API 包装成工具,再统一走 TaoToken 的 Key 和 API 通道,让模型侧只认一个入口。
这套方案适合谁?适合手里有大量 REST 接口、想快速接入 AI 工具链、又不想大改代码的后端团队。核心检索词就是「SpringAI-MCP 存量 API 零代码工具化」,下面从环境准备到端到端验证一步步拆开。
2. TaoToken 统一通道的前置准备
在写 MCP 服务端之前,先把模型侧的通道固定下来。TaoToken 在这里扮演的是统一网关角色:MCP 工具被调用后,最终还是要落到某个模型去理解意图、生成参数,这个模型请求统一走 TaoToken 的 API 地址,Key 也只维护一份。
你需要准备三样东西:Base URL、API Key、Model ID。Base URL 用https://taotoken.net/api,注意这个地址不带任何查询参数。API Key 在控制台的 API Keys 页面创建,建议按项目维度建独立 Key,方便后续按调用量排查问题。Model ID 根据你实际使用的模型填写,比如claude-sonnet-4-5这类标识。
创建 Key 的入口在这里:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
如果你还没决定用哪个模型,可以先在模型对话页面试一下意图理解效果:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite
这一步的关键是:MCP 服务端本身不直接持有模型凭证,它只负责把工具描述和调用结果整理好,模型请求由客户端侧统一走 TaoToken。这样存量系统的接口权限体系完全不受影响,MCP 层只做协议转换。
3. 可复制的 SpringAI-MCP 服务端配置
这一节给出能直接抄的配置。假设你有一个存量接口GET /api/order/status?orderId=xxx,我们要把它包装成 MCP 工具,且不改动原 Controller。
先看application.yml里的 MCP 服务端配置:
spring: ai: mcp: server: name: legacy-order-mcp version: 1.0.0 type: SYNC sse-endpoint: /mcp/sse sse-message-endpoint: /mcp/message capabilities: tool: true resource: false prompt: false taotoken: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} model-id: claude-sonnet-4-5注意api-key用环境变量注入,不要硬编码进仓库。接着是工具定义类,用@Tool注解把存量接口的调用逻辑包起来:
@Component public class LegacyOrderTools { private final RestClient restClient; public LegacyOrderTools(RestClient.Builder builder) { this.restClient = builder.baseUrl("http://legacy-order-svc:8080").build(); } @Tool(name = "get_order_status", description = "查询订单当前状态。输入订单号,返回状态码和状态描述。适用于用户询问订单进度、是否发货等场景。") public String getOrderStatus( @ToolParam(description = "订单号,纯数字,例如 20240115001") String orderId) { return restClient.get() .uri("/api/order/status?orderId={id}", orderId) .retrieve() .body(String.class); } }工具描述模板的写法很关键,它直接决定模型能不能稳定发现并正确调用。我总结的模板是:功能一句话 + 输入说明 + 返回说明 + 适用场景。缺了「适用场景」,模型在多个工具之间容易选错。
如果你用的是 Cline 或 Claude Code 这类客户端,需要在客户端侧配置 MCP 服务端地址,三件套写全:
{ "mcpServers": { "legacy-order": { "url": "http://localhost:8080/mcp/sse", "env": { "TAOTOKEN_BASE_URL": "https://taotoken.net/api", "TAOTOKEN_API_KEY": "sk-你的Key", "TAOTOKEN_MODEL_ID": "claude-sonnet-4-5" } } } }Base URL、Key、Model ID 三个字段一个都不能少,尤其是 Model ID,客户端要靠它决定把工具调用结果发给哪个模型。
4. 端到端调用验证与成功结果
配置写完后,启动 Spring Boot 应用,先确认 MCP 服务端起来了。访问http://localhost:8080/mcp/sse,如果返回 SSE 事件流而不是 404,说明端点正常。
接着在客户端里触发一次工具发现。以 Cline 为例,连接成功后它会列出可用工具,你应该能看到get_order_status。如果没出现,先检查@Tool注解的类是否被 Spring 扫描到,以及capabilities.tool是否为 true。
然后发一条自然语言请求:「帮我查一下订单 20240115001 现在什么状态」。正常流程是:客户端把工具清单和用户问题一起发给模型,模型判断需要调用get_order_status,客户端执行工具拿到结果,再把结果回传模型生成最终回复。
成功时你会看到类似这样的调用链:
{ "tool": "get_order_status", "arguments": { "orderId": "20240115001" }, "result": "{\"status\":\"SHIPPED\",\"desc\":\"已发货\"}" }模型最终回复:「订单 20240115001 当前状态是已发货。」到这里,存量接口在没有改动任何业务代码的前提下,已经能被 AI 稳定发现和调用了。
验证模型意图理解是否准确,可以在模型对话页面单独测一轮:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite
5. 常见报错排查对照
实际接入时最容易撞上几类错误,逐个对照。
401 Unauthorized:多半是 TaoToken 的 Key 没注入成功。检查环境变量TAOTOKEN_API_KEY是否在启动参数里,或者客户端 JSON 里的 Key 是否带了多余空格。Key 失效也会返回 401,去控制台确认一下状态。
local proxy failed / connection refused:客户端连不上 MCP 服务端的 SSE 端点。先确认 Spring Boot 端口和sse-endpoint路径一致,再确认客户端配置的 URL 没有多写斜杠。如果是容器环境,注意localhost在容器里指向的是容器自身。
reading choices 相关解析错误:这类通常出现在模型返回结构不符合预期时。检查 Model ID 是否填对,有些模型对工具调用的返回格式支持不同。换一个明确支持 function calling 的模型再试。
OAuth 相关报错:如果你给 MCP 端点加了鉴权,客户端没带 token 就会报这个。开发阶段可以先关掉 MCP 端点鉴权,生产环境再补上,但注意存量接口本身的权限体系不要绕过。
工具列表为空:@Tool注解的方法必须是 public,且所在类要被 Spring 管理。另外capabilities.tool设为 false 时工具不会注册,这个坑我踩过一次,排查了半天。
排障时建议先看 MCP 服务端日志,再看客户端日志,最后看模型返回。三层日志对照,基本能定位到是哪一环断了。接入文档在这里:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
6. 把通道固定下来,长期跑 Agent 更省心
单次验证通过只是开始。当你要把几十个存量接口都工具化,并且让 AI 助手长期在线服务时,Key 管理和调用配额就成了运维问题。这时候建议把模型通道统一收敛到 TaoToken,MCP 服务端只关心工具逻辑,模型凭证和额度在控制台集中管理。
如果你的场景是长期编码辅助或 Agent 常驻,可以看一下 Coding Plan 的额度方案:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite
最后给一个实用技巧:工具描述里的「适用场景」写得越具体,模型选错工具的概率越低。比如不要写「查询订单」,而要写「当用户询问订单是否发货、物流进度、预计到达时间时使用」。这一句话的差别,在工具数量超过十个之后会非常明显。