旧 REST 接口封装成 MCP 服务:完整实战指南(TaoToken 统一 Key 接入版)
1. 旧 Spring MVC 接口接 AI Agent卡在哪一步你手上有一套跑了五六年的 Spring MVC 服务订单、用户、库存这些接口天天在扛线上流量业务逻辑稳得很。现在团队要接 AI Agent让大模型能直接调这些接口问题就来了MCP 协议是给 LLM 用的你的接口是给前端和 App 用的两边说的不是一种话。MCP 全称 Model Context Protocol它定义的是 LLM 和外部工具之间的标准通信方式。它不关心你后端是 Java、Python 还是别的只关心你能不能暴露一组符合规范的 Tool。所以真正要解决的问题不是重写旧系统而是在中间加一层适配把 REST 接口翻译成 MCP Tool。这篇面向的是已有 AI Agent 工具链、手里有存量 Spring MVC 项目的团队。我会给出可复制的 MCP 服务骨架、TaoToken 统一 Key 的配置片段以及一次端到端调用验证。旧系统零改动所有适配逻辑收敛在 MCP Server 层这是贯穿全文的原则。适合谁看Java 后端想快速把接口暴露给 Agent 的团队已经在用 Claude Code、Cursor 这类工具想接自研接口的以及被 JDK 版本卡住、旧系统不敢动的人。下面从架构到代码一步步来。2. 前置准备TaoToken 统一 Key 与 MCP 适配层定位在写代码之前先把两个东西理清楚一个是 MCP 适配层放在哪另一个是模型调用通道怎么统一。架构上分三段。左边是 LLM / AI Agent中间是 MCP Server 适配层右边是旧 Java REST 服务。Agent 通过 MCP 协议stdio 或 SSE/HTTP连到适配层适配层再用普通 HTTP 调旧接口。旧服务完全不知道 MCP 的存在它只看到熟悉的 REST 请求。┌─────────────┐ MCP Protocol ┌──────────────────┐ HTTP ┌─────────────────┐ │ LLM / │ ◄─────────────► │ MCP Server │ ◄───────► │ 旧 Java REST │ │ AI Agent │ (stdio/SSE/HTTP)│ (适配层) │ (REST) │ 服务 (不动) │ └─────────────┘ └──────────────────┘ └─────────────────┘模型调用通道这块我建议用 TaoToken 统一 Key 来管。原因是团队里往往不止一个模型、不止一个 Agent 工具每个工具各配一套 Key 和地址换模型时到处改配置很容易漏。TaoToken 提供统一的 API 通道模型对话、编码计划、控制台、API Keys 都在一个入口下配置一次就能被多个工具复用。你需要准备的东西一个 TaoToken 账号拿到统一 Key旧 REST 服务的地址和一个内部调用 Token建议走环境变量注入别硬编码JDK 17 和 Maven走 Spring AI 方案的话。注意旧接口的鉴权 Token 和 TaoToken 的 Key 是两回事。前者是适配层调旧服务用的后者是 Agent 调模型用的别混在一个配置里。3. 可复制配置MCP 服务骨架与 TaoToken 接入片段先给依赖。走 Spring AI MCP Server 方案的话pom 里加两块MCP Server starter 和用来调旧接口的 WebClient。dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-mcp-server-spring-boot-starter/artifactId version1.0.0/version /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-webflux/artifactId /dependency /dependenciesapplication.yml 里配 MCP Server 的基本信息和传输方式。本地 CLI 场景用 stdio远程给多个 Agent 调用用 sse。spring: ai: mcp: server: name: legacy-order-mcp version: 1.0.0 type: SYNC transport: sse sse-port: 8090接下来是 Tool 的核心代码。这里的关键是Tool 的 description 是写给 AI 看的不是写给开发者看的。它要回答“什么时候该调我、参数长什么样、返回什么”。Service public class LegacyOrderTools { private final WebClient webClient; public LegacyOrderTools(WebClient.Builder builder) { this.webClient builder .baseUrl(http://legacy-order-service:8080) .defaultHeader(Authorization, Bearer System.getenv(LEGACY_API_TOKEN)) .build(); } Tool(description 根据订单号查询订单详情。当用户询问我的订单到哪了、 订单什么时候发货时使用此工具。返回订单状态、总金额和商品列表。 订单号格式ORD-YYYY-NNNNNN) public String queryOrder( ToolParam(description 订单编号格式如 ORD-2024-001234) String orderId) { try { OrderDTO order webClient.get() .uri(/api/v1/orders/{id}, orderId) .retrieve() .bodyToMono(OrderDTO.class) .timeout(Duration.ofSeconds(10)) .block(); return formatOrderSummary(order); } catch (Exception e) { return 查询订单时系统繁忙请稍后重试。; } } private String formatOrderSummary(OrderDTO order) { return String.format(订单%s状态%s金额%.2f元, order.getId(), order.getStatusText(), order.getAmount()); } }注册 Tool Provider让 Spring 自动扫描到这些方法Configuration public class McpToolConfig { Bean public ToolCallbackProvider orderToolProvider(LegacyOrderTools tools) { return MethodToolCallbackProvider.builder() .toolObjects(tools) .build(); } }然后是 TaoToken 的配置片段。如果你用 Claude Code 这类工具settings.json 里这样写{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: 你的TaoToken统一Key } }如果用支持 config.toml 的客户端等价写法[provider] base_url https://taotoken.net/api api_key 你的TaoToken统一Key这样模型调用走统一通道MCP Server 只管把旧接口翻译成 Tool两件事解耦换模型不用动适配层代码。4. 验证请求一次端到端调用跑通配置写完先别急着接 Agent用 MCP Inspector 单独验证 Tool 能不能被正确发现和调用。npx modelcontextprotocol/inspector打开浏览器界面后你会看到注册的 Tool 列表点进 queryOrder手动输入ORD-2024-001234观察原始 JSON-RPC 请求和响应。这一步能确认三件事Tool 有没有注册成功、参数 Schema 对不对、旧接口返回有没有被正确裁剪。Inspector 通过后再接到真实 Agent 里测。以 Claude Desktop 为例编辑claude_desktop_config.json{ mcpServers: { legacy-order: { command: java, args: [-jar, legacy-order-mcp.jar], env: { LEGACY_API_TOKEN: your-internal-token } } } }重启后在对话里输入“帮我查一下订单 ORD-2024-001234 的物流状态”。如果 Agent 正确调用了 queryOrder 并返回了裁剪后的摘要说明整条链路通了。单元测试也别省重点验证响应裁剪有没有生效Test void testQueryOrderTool() { String result tools.queryOrder(ORD-2024-001234); assertThat(result).contains(已发货); assertThat(result).doesNotContain(cssClass); }doesNotContain(cssClass)这行很关键它保证旧接口里那些前端渲染用的冗余字段没被扔给 LLM。5. 本篇常见错排查Tool 不触发、超时、Token 浪费Tool 描述太笼统Agent 不调用。写成“调用订单查询接口”LLM 不知道什么时候该用。改成“当用户询问订单进度、物流状态时使用”并带上订单号格式示例命中率会明显提升。旧接口响应慢导致超时。旧系统可能扛着历史包袱响应不稳定。WebClient 一定要设 timeout并做降级.timeout(Duration.ofSeconds(10)) .onErrorResume(TimeoutException.class, e - Mono.just(查询超时旧系统响应较慢请稍后再试。))把整个 JSON 扔给 LLMToken 烧得飞快。旧接口可能返回两百个字段含大量前端用的样式类、埋点参数。必须在适配层裁剪只留 LLM 推理需要的字段。上面formatOrderSummary就是干这个的。错误信息抛 JSON 错误码。别返回{code:50023,msg:ORD_NOT_EXIST}LLM 看不懂。改成自然语言“订单号 ORD-2024-999999 不存在请检查是否有拼写错误。”写操作没防护。取消订单、删除账户这类 Tooldescription 里要明确标注危险并在业务层加二次确认。读操作先上线稳定后再开放写操作。TaoToken Key 和旧接口 Token 混用。两者作用域不同配置里分开写旧接口 Token 走环境变量别提交到仓库。6. 把旧接口稳定交给 Agent 调用走到这里你已经有了一个能跑的 MCP 适配层旧 Spring MVC 服务零改动Tool 描述面向 AI 写清楚响应做了裁剪错误用自然语言超时和降级都配上了。模型调用侧用 TaoToken 统一 Key 管起来换模型、加 Agent 工具都不用动适配层。后续要接更多旧接口就是复制 Tool 方法、写好 description、注册 Provider 这三步。生产上记得加限流防止 LLM 循环调用把旧系统打垮日志记录每次 Tool 调用的入参、耗时和响应摘要方便排查。如果你还没配好统一 Key可以从 API Keys 页面拿到 Key再对照接入文档把 settings.json 或 config.toml 补全。想先验证模型通道通不通去模型对话里发一条消息试试如果团队要长期跑编码和 Agent 任务Coding Plan 会更省心。旧系统不是包袱给它穿一件 AI 能看懂的外套就行。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →