1. 为什么要在 Spring AI 里认真对待 MCP 的 JSON-RPC 层如果你正在用 Spring AI 1.x 做 Java 侧的 AI 应用大概率已经写过ChatClient调模型、用Tool注解暴露本地方法。但一旦工具不在本进程里——比如一个独立的检索服务、一个公司内部的订单查询服务、一个跑在另一台机器上的 Python 脚本——本地Tool就不够用了。这时候需要的是模型上下文协议MCP它把「AI 应用怎么调用外部工具」这件事标准化成了一套基于 JSON-RPC 2.0 的通信约定。MCP 能做什么简单说它让 AI 应用Host通过客户端Client连接到一个个独立的服务器Server服务器把资源、提示模板、工具以标准原语暴露出来。适合谁适合需要在 Java 项目里接入外部工具服务、又不想为每个工具写一套私有适配层的开发者。你可以把它理解成 AI 世界的 USB-C以前每个外部系统都要单独做一根线现在统一成一个接口。我试过在 Spring AI 1.x 里接一个自建的 MCP 服务最开始卡住的不是业务逻辑而是 JSON-RPC 的初始化握手和端点声明——文档里一笔带过实际配置时字段写错一个就静默失败。这篇就把这套配置骨架拆开从依赖到端点声明再到一次真实的工具调用链路验证全部落到可复制的代码。2. TaoToken 前置把模型侧和工具侧解耦在讲 MCP 配置之前先说清楚模型侧怎么接。MCP 解决的是「工具怎么暴露和调用」但工具调用最终还是要模型来决定「调哪个工具、传什么参数」。所以你需要一个能稳定响应工具调用tool calls的模型端点。我这边习惯用 TaoToken 作为模型接入层原因是它同时提供 OpenAI 兼容接口和 Anthropic 兼容接口Spring AI 1.x 里两种ChatModel实现都能直接对接不用为了换模型改 MCP 那层的代码。官网在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 注意这个地址后面不加任何查询参数。具体到配置你需要在 TaoToken 控制台创建一个 API Key然后把它写进 Spring 的配置文件。控制台入口在 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite API Key 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。创建好之后模型侧的配置大概是这样spring: ai: openai: api-key: ${TAOTOKEN_API_KEY} base-url: https://taotoken.net/api chat: options: model: claude-sonnet-4-5 temperature: 0.2这里base-url指向 TaoToken 的 API 根路径Spring AI 的 OpenAI starter 会自动拼接/v1/chat/completions之类的路径。如果你用的是 Anthropic 兼容模式换成对应的 starter 和base-url即可MCP 那层的代码完全不用动——这正是把模型侧和工具侧解耦的价值。注意API Key 不要硬编码在application.yml里提交到仓库用环境变量或者配置中心注入。MCP 服务器如果也要认证同样走环境变量。3. 可复制配置MCP 客户端与服务端的 JSON-RPC 骨架3.1 依赖引入Spring AI 1.x 对 MCP 的支持拆成了客户端和服务端两个 starter。假设你用的是 Maven先在pom.xml里加dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-client/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server/artifactId /dependency版本跟随你的 Spring AI BOM 走不要单独指定否则容易出现McpClient和McpServer的 API 不匹配。如果你只做客户端连接别人写好的 MCP 服务只引 client starter 就够了服务端 starter 是给「自己暴露工具给别人用」的场景。3.2 服务端声明 JSON-RPC 端点与工具服务端的核心是把一个 Spring Bean 里的方法注册成 MCP 工具。Spring AI 提供了Tool注解配合ToolCallbackProvider暴露出去。下面是一个最小可运行的服务端配置Configuration public class McpServerConfig { Bean public ToolCallbackProvider orderToolProvider(OrderService orderService) { return MethodToolCallbackProvider.builder() .toolObjects(orderService) .build(); } } Service public class OrderService { Tool(description 根据订单号查询订单状态返回状态码和更新时间) public OrderStatus queryOrder(ToolParam(description 订单号格式 ORD- 开头) String orderId) { // 真实场景这里查数据库或调内部 API return new OrderStatus(orderId, PAID, Instant.now()); } }然后在application.yml里声明 MCP 服务端的传输方式和端点spring: ai: mcp: server: name: order-mcp-server version: 1.0.0 protocol: STREAMABLE streamable-http: mcp-endpoint: /mcp port: 8081这里protocol: STREAMABLE对应新版推荐的 Streamable HTTP 传输mcp-endpoint就是 JSON-RPC 消息的入口路径。客户端会往http://localhost:8081/mcp发 POST 请求请求体是标准的 JSON-RPC 2.0 格式。3.3 客户端连接外部 MCP 服务客户端侧要声明「连哪个服务器、用什么传输」。Spring AI 1.x 支持在配置文件里直接声明多个 MCP 服务器连接spring: ai: mcp: client: enabled: true name: spring-ai-mcp-client version: 1.0.0 type: SYNC request-timeout: 30s streamable-http: connections: order-server: url: http://localhost:8081 endpoint: /mcptype: SYNC表示同步客户端适合请求-响应式的工具调用如果你要做流式或长任务可以换成ASYNC。connections下面可以挂多个服务器每个 key 是连接名url和endpoint拼起来就是完整的 JSON-RPC 端点。配置完之后Spring AI 会自动创建McpSyncClient并注册到ToolCallbackProvider里模型在对话时就能「看到」这些外部工具。你不需要手写 JSON-RPC 的initialize、tools/list、tools/call这些方法——框架帮你做了但理解它们有助于排障。3.4 JSON-RPC 消息长什么样为了后面排障方便这里贴一条真实的tools/call请求体你可以用 curl 直接打服务端验证{ jsonrpc: 2.0, id: 1, method: tools/call, params: { name: queryOrder, arguments: { orderId: ORD-20250101-001 } } }对应的成功响应{ jsonrpc: 2.0, id: 1, result: { content: [ { type: text, text: {\orderId\:\ORD-20250101-001\,\status\:\PAID\} } ] } }注意id在同一会话内不能重复也不能为null——这是 MCP 在 JSON-RPC 2.0 之上的硬性增强写自定义客户端时容易踩。4. 验证请求跑通一次工具调用链路配置写完怎么确认真的通了分两步先绕过模型直接验证 MCP 服务端再走完整链路让模型决定调用。4.1 直接打 JSON-RPC 端点服务端起在 8081 后先用 curl 发一个initialize请求curl -X POST http://localhost:8081/mcp \ -H Content-Type: application/json \ -d { jsonrpc: 2.0, id: 1, method: initialize, params: { protocolVersion: 2025-11-25, capabilities: {}, clientInfo: {name: curl-test, version: 1.0} } }如果返回里带result.capabilities.tools说明服务端能力协商成功。接着发tools/listcurl -X POST http://localhost:8081/mcp \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:2,method:tools/list,params:{}}你应该能看到queryOrder出现在工具列表里带inputSchema。这一步过了说明 JSON-RPC 层没问题问题只可能在客户端配置或模型侧。4.2 走完整链路写一个 Spring Boot 测试类注入ChatClient让它根据自然语言决定调用工具SpringBootTest class McpToolCallTest { Autowired private ChatClient chatClient; Test void shouldCallExternalOrderTool() { String reply chatClient.prompt() .user(帮我查一下订单 ORD-20250101-001 的状态) .call() .content(); System.out.println(reply); assertThat(reply).contains(PAID); } }跑起来后观察日志里有没有tools/call的 JSON-RPC 往返。成功的话模型会先返回一个 tool callSpring AI 把它转成 MCP 请求发给 8081拿到结果后再喂回模型生成最终回复。整个链路里模型侧走的是 TaoToken 的 API工具侧走的是本地 MCP 服务两边通过 Spring AI 的ToolCallbackProvider缝合。如果你只想先验证模型能不能正确识别工具可以打开模型对话页面手动试https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 把工具描述贴进去看它是否按预期生成调用参数。5. 本篇常见错排查5.1 客户端连不上日志只有一句 timeout先确认url和endpoint有没有拼错。url: http://localhost:8081加endpoint: /mcp拼出来是http://localhost:8081/mcp如果你在url里已经写了/mcp就会变成/mcp/mcp。另外 Streamable HTTP 的initialize是 POST但后续监听流是 GET如果服务端只放行了 POST握手会卡住。5.2 工具列表为空大概率是ToolCallbackProvider没被扫描到。检查Tool方法所在的类是不是 Spring BeanMethodToolCallbackProvider.builder().toolObjects(...)传进去的对象必须是被 Spring 管理的实例。另外Tool的方法参数要加ToolParam描述否则生成的inputSchema可能缺字段模型看不到参数说明就不会调。5.3 模型不调用工具先看模型侧返回里有没有tool_calls。如果模型压根没生成工具调用可能是工具描述太模糊或者模型本身对工具调用支持不好。换一个工具调用能力强的模型或者在 prompt 里明确「你必须使用 queryOrder 工具查询」。TaoToken 的模型列表里可以挑支持 function calling 的型号具体在文档页有说明https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。5.4 JSON-RPC id 重复导致会话中断如果你自己写了客户端重试逻辑注意每次请求的id要递增不能复用。MCP 规范明确要求同一会话内 id 不得重复复用了服务端可能直接断连。用 Spring AI 的McpSyncClient不用管这个框架内部维护了计数器。5.5 服务端返回 406 或 415Streamable HTTP 对Content-Type和Accept有要求。请求必须是application/json响应期望application/json或text/event-stream。如果你前面挂了网关检查网关有没有改写这两个头。6. 接下来怎么走MCP 的配置骨架搭起来之后真正花时间的是工具粒度的设计和权限边界。我的经验是一个 MCP 服务只暴露一组高内聚的工具别把订单、库存、用户全塞一个服务里否则模型在tools/list里看到几十个工具选择准确率会下降。另外服务端的Tool方法尽量幂等因为模型重试是常态。如果你要长期跑编码类 Agent把 MCP 客户端接进 IDE 或 CLI 工作流可以考虑用 Coding Plan 统一管理模型额度和调用https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。Claude Code 这类工具接 Anthropic 兼容端点的配置在 https://taotoken.net/claude-code?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite 有说明MCP 那层配置和本文一致换的只是模型接入地址。最后留一个实操建议先把本文的服务端 curl 验证跑通再动客户端配置。JSON-RPC 层通了后面都是 Spring 的装配问题排障范围会小很多。
企业数字化 ERP 产品动态
相关推荐
电机工程学报投稿格式全攻略:从被拒到一次过审的实操经验 1. 从投稿被拒到一次过审:电机工程学报论文格式的门道第一次往《中国电机工程学报》投稿的时候,我自认为内容做得扎实,仿真和实验数据都反复核对过,结果初审就被退回来了,理由只有一行字:“格式不符合本刊要… · 2026/9/26 11:23:24
开心超级签系统源码解析:Java签名与APK分发链路实战 简介:这是一套基于Java实现的超级签系统与APK分发平台源码,面向想深入理解Android签名机制、Java后端开发与应用分发流程的开发者,适合作为二次开发或定制扩展的实践参考。压缩包共434个文件,约48.82MB,以199个java源文… · 2026/9/26 11:23:18
基于自适应关键帧的微表情识别算法源码解析与实战 简介:本资源面向微表情识别方向的研究者与开发者,提供一套基于自适应关键帧的视频微表情识别算法完整实现,适合具备一定计算机视觉与深度学习基础、希望快速复现并二次开发的中高级学习者。资源包共14个文件,以6个Python源码文件为… · 2026/9/26 11:23:18
Bc_ChckenPrnce 配 TaoToken:settings.json 骨架与报错排查 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 12:01:35
Atlas 300V 24G部署YOLOv5全流程解析:从模型转换到NPU推理实践 最近在技术群里被问得最频繁的一个词,就是“atlas”。好多人在问“atlas部署yolo到底行不行”,还有人直接发来“atlas 300v 24g 是运算加速卡吗”这种问题。作为一个在边缘AI设备上折腾过不少推理框架的人,我可以明确说:Atlas 300… · 2026/9/26 12:01:35
SpringBoot健身轻食平台系统源码解析与部署实战指南 这套“基于SpringBoot的健身服务与轻食间平台系统”,名字一看就是典型的Java课程设计或者毕业设计项目。源码、lw(说明文档)、部署文档三件套都齐了,说明作者是真心想让你把它跑起来的。我拿到手之后,在本地和云服务器… · 2026/9/26 12:01:29
拼多多客服机器人接入实战:事件驱动架构与轻量级服务设计 简介:本资源是一款面向拼多多商家的智能客服机器人系统,专为解决电商高峰期人工客服响应滞后、重复咨询处理低效等痛点而设计,适用于具备基础Windows部署能力的中小商家及技术运维人员。压缩包共18个文件,含4个核心DLL插件&#x… · 2026/9/26 12:01:29
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46