Java Spring AI MCP:在 Spring 里把 AI 接上你的业务系统

Java Spring AI MCP:在 Spring 里把 AI 接上你的业务系统

🔥 写在前面:MCP 教程十篇有九篇是 Node/TypeScript。但国内大量系统是 Java 栈,强行用 Node 写 Server 再和 Spring 对接,运维和协作成本都不低。好消息:Spring AI 已经原生支持 MCP。这篇文章带你用 Java 写一个生产级 MCP Server,把已有的业务 Service 直接暴露给 AI。
💡 我是做一线 Java + AI 工程落地的,MCP 和信创都是真刀真枪踩过坑的。本专栏会持续更新 MCP / Spring AI / 信创实战,关注我,新篇第一时间看,少走弯路。


一、先说结论

  • Spring AI 的 spring-ai-mcp 模块 已经把传输层、协议层、原语层都包好了,你只需要写 @Tool 标注的方法。
  • 对 Java 团队的最大价值:不用离开 Spring 生态 ,直接把现有 @Service 变成 AI 可调用的 Tool,复用事务、鉴权、连接池。
  • 两种玩法:SDK Server 模式 (内嵌 MCP Server,stdio/SSE)和Spring Boot Starter 模式(注解驱动,最省事)。
  • 别指望零成本:MCP 的「工具描述」「参数 Schema」仍要你认真写,否则 AI 不会调(见第七坑)。

二、为什么 Java 团队该直接用 Spring AI MCP

传统做法是「Node 写 MCP Server → 调 Java 后端 HTTP 接口」。问题:

  • 两套技术栈、两套部署、两套监控;
  • Node Server 成了「翻译层」,既脆弱又多余;
  • 鉴权 / 事务 / 日志要和 Java 侧对齐,重复劳动。

Spring AI MCP 直接把这层翻译去掉:

text 复制代码
AI Client  →  MCP(stdio/SSE)  →  Spring Boot 应用
                                 ├─ @Tool 方法(原 @Service 方法)
                                 ├─ Spring 事务 / 鉴权 / 连接池(复用)
                                 └─ 你的业务 DAO

一句话:你的 Spring Bean 就是 MCP Server,不用另起炉灶。

实际落地时有两种 Server 模式可选:内嵌式 (MCP Server 跑在你的 Spring Boot 进程里,通过 stdio 或 SSE 对外)和独立式 (打成单独 jar 由客户端拉起)。内嵌式最省事、和主应用共享事务/连接池;独立式隔离性更好,适合把 MCP 能力单独部署、横向扩容。我的默认选择是内嵌 SSE 模式------既能让远程客户端连,又不引入额外进程,运维面最小。要注意:SSE 模式走 HTTP,必须叠一层 Spring Security(见第七坑 6),否则公网直接被白嫖。


三、最快上手:Starter + 注解

核心依赖(Maven):

xml 复制代码
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>

写一个 Tool 只需一个注解:

java 复制代码
@Service
public class OrderService {

    @Tool(name = "query_order",
          description = "当用户想按订单号查询订单状态时调用,参数 orderId 为字符串")
    public String queryOrder(@ToolParam("订单号") String orderId) {
        return orderRepository.findStatus(orderId); // 复用已有 DAO + 事务
    }
}

关键点:@Tooldescription@ToolParam 的描述会原样发给 AI。写得含糊,AI 就不调(第七坑 2 同款问题)。

对应的 application.yml 声明 Server 模式与传输:

yaml 复制代码
# application.yml:声明 Server 模式与暴露的传输
spring:
  ai:
    mcp:
      server:
        enabled: true
        name: order-mcp
        version: 1.0.0
        type: SYNC                # SYNC(WebMVC)或 ASYNC(WebFlux)
        sse-endpoint: /mcp/sse    # SSE 模式对外暴露的路径

带 DTO 参数的写操作(参数 Schema 由 DTO 字段描述自动生成):

java 复制代码
// 复杂参数用 record + @ToolParam,Schema 由字段描述生成,AI 不会传错类型
public record OrderCmd(@ToolParam("订单号") String orderId,
                       @ToolParam("新状态") String status) {}

@Service
public class OrderService {
    @Tool(name = "update_order",
          description = "当用户要修改订单状态时调用,参数 orderId 为订单号,status 为目标状态")
    public String updateOrder(OrderCmd cmd) {
        return orderRepository.updateStatus(cmd.orderId(), cmd.status());
    }
}

经验:读操作(query)和写操作(update)建议拆成两个 Tool,方便后续做权限隔离(只读 Server / 读写 Server 分离,见第 4 篇)。


四、一次调用在 Spring 里怎么流转

AI 说「查一下订单 A123」,完整链路是:

  1. MCP 传输层收到 tools/call(参数 orderId=A123);
  2. Spring AI 的 Dispatcher 路由到 OrderService.queryOrder
  3. 方法内走正常的 Spring 事务 + 鉴权拦截器(和你的其他接口一致);
  4. 结果序列化回 MCP 协议帧,返回给 AI。

你写的业务代码完全不知道自己在被 AI 调用------这就是 Spring AI MCP 最优雅的地方。


五、手写 vs 框架:到底省了多少

我对比了「手写 Spring MVC 接口 + 自己封装 MCP 协议」和「直接用 Spring AI Starter」:

  • 手写:每个 Tool 约 40 行(协议解析 + 路由 + Schema 生成 + 错误处理),10 个 Tool = 400 行胶水代码;
  • Starter:每个 Tool 约 5 行(一个 @Tool 方法),10 个 Tool = 50 行;
  • 维护:协议升级时,手写版要改胶水代码,Starter 只升级依赖。

框架不仅是省代码,更关键是协议升级时不用重写,风险更低。


验收标准:你可以自己复现

按这 4 步,能确认你的 Spring MCP Server 真的跑通:

  1. 起项目mvn spring-boot:run,确认日志出现 MCP Server started 且监听配置的端口 / stdio。
  2. 连 Client:用支持 MCP 的客户端(如 Cline)配置该 Server 的启动命令,重启客户端。
  3. 看工具列表 :在客户端工具列表里能看到 query_order(你定义的 name),且描述正确。
  4. 真调一次 :让 AI「查订单 A123」,观察:① 客户端发出 tools/call;② 你的 Spring 应用日志打印了 queryOrder 被调用;③ AI 拿到结果并自然回复。四步全过 = 达标

六、实测:复用 Spring 生态的真实收益

  • 事务一致性:Tool 内抛异常,Spring 事务自动回滚,和 REST 接口行为一致------不用额外处理。
  • 鉴权复用 :已有的 @PreAuthorize / 拦截器对 Tool 调用同样生效,AI 越权调用被挡。
  • 监控复用:Tool 调用自动进 Micrometer / Actuator,和现有监控面板打通。

这三点用「Node 翻译层」方案基本都要重写一遍,Spring AI MCP 直接白嫖。


七、我踩过的 6 个坑

坑 1:Starter 选错,Server 起不来

现象:No qualifying bean 或端口被占。根因:WebMVC 和 WebFlux 的 Starter 混用。解决 :纯 Spring MVC 项目用 webmvc 版,Reactive 用 webflux 版,别混。预防:按项目响应式类型选 Starter。

坑 2:Tool 描述太短,AI 不调用

现象:方法注册了,AI 从不调。根因:description 只有「查询订单」四字。解决 :写成「用户按订单号查状态时调用,参数 orderId 为字符串」。预防:每个 Tool 描述包含触发场景 + 参数含义。

坑 3:参数类型没标注,Schema 生成错

现象:AI 传来的参数是字符串,方法要 Long,直接类型转换报错。根因:@ToolParam 没指明类型,Schema 推断错。解决 :明确类型,复杂对象用 DTO + 字段描述。预防:所有参数显式声明类型。

坑 4:长耗时 Tool 阻塞 MCP 线程

现象:查大报表的 Tool 一跑,其他 Tool 全卡。根因:MCP 处理在请求线程,同步阻塞。解决 :耗时操作丢到 @Async 或返回进度句柄。预防:超 2s 的 Tool 默认异步化。

坑 5:返回内容太大撑爆上下文

现象:AI 返回后「失忆」或超 token。根因:Tool 返回了整张 10 万行表。解决 :Server 端分页 / 截断,只回摘要 + 数量。预防:所有返回加 size 上限。

坑 6:SSE 模式忘了鉴权

现象:公网 Spring MCP 被白嫖。根因:SSE 走 HTTP 没加 Spring Security。解决 :加 Spring Security + Bearer Token,复用现有登录体系。预防:SSE 模式默认上 Security。


八、适合谁 / 不适合谁

✅ 适合

  • 已有 Spring Boot 业务系统,想让 AI 调用内部能力;
  • 团队是 Java 栈,不想引入 Node 运维;
  • 需要事务 / 鉴权 / 监控和现有系统一致。

⚠️ 暂不适合

  • 超轻量工具、无 Spring 依赖:用 Node SDK 更轻;
  • 客户端要求极致低延迟的边缘场景。

九、总结

Spring AI MCP 让 Java 团队「零翻译层」地把业务系统暴露给 AI,最大红利是复用 Spring 的事务、鉴权、监控 。只要认真写好 @Tool 的描述和参数 Schema,剩下的交给框架。下一篇我们谈更实战的:多个 MCP Server 怎么编排


📢 下篇预告

第 4 篇《多个 MCP Server 怎么编排:数据库 / Redis / Git / 飞书一把梭》------一个客户端接 4 个 Server 时,能力冲突、命名空间、权限边界怎么管?实测给你一套编排规范。


💬 聊聊 + 关注

你的 Spring 项目里,最想先暴露给 AI 的是哪个 Service?订单、用户、还是报表?评论区聊聊,我可以挑一个在下篇做完整示例。

👉 如果这篇帮你用 Java 落地了 MCP Server,点个「关注」------专栏后续还有:多 Server 编排避坑、可交互应用生成、MCP 安全攻防实战、用 MCP 接私有大模型。关注后新篇直接推给你,不迷路。


附:依赖选型与速查表

Gradle 等价依赖(不用 Maven 的团队)

gradle 复制代码
// build.gradle:WebMVC 项目用 webmvc,Reactive 项目换成 webflux
dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-mcp-server-webmvc'
}

表 1:Starter 选型

项目类型 Starter 传输 适用
纯 Spring MVC spring-ai-starter-mcp-server-webmvc stdio / SSE 绝大多数后台
Reactive / WebFlux spring-ai-starter-mcp-server-webflux SSE 响应式栈
仅本地子进程 spring-ai-starter-mcp-server stdio 桌面客户端拉起

表 2:手写 vs Starter

维度 手写封装 Spring AI Starter
单 Tool 代码量 ~40 行 ~5 行
10 Tool 总量 ~400 行胶水 ~50 行
协议升级 改胶水代码 只升依赖
事务/鉴权 自己接 复用 Spring

表 3:复用 Spring 生态能力

能力 是否自动复用 说明
事务(@Transactional) Tool 内异常自动回滚
鉴权(@PreAuthorize) AI 越权调用被拦
监控(Micrometer) Tool 调用进 Actuator
日志(SLF4J) 和现有日志体系一致

表 4:常用注解对照

注解 作用 注意
@Tool 标记方法为 Tool description 必写触发场景
@ToolParam 标记参数 + 描述 复杂对象用 DTO
@ToolCallback 注册回调 动态注册用
record 作参数 自动生成 Schema 字段加 @ToolParam
@Async 异步 Tool 超 2s 操作用它

表 5:6 个坑 → 对策

根因 对策
Starter 选错 MVC/Flux 混用 按响应式类型选
描述太短 AI 不调 description 含糊 写触发场景+参数
参数类型错 未标类型 显式声明/DTO
长耗时阻塞 同步阻塞线程 @Async 或进度句柄
返回过大 全量返回 分页/截断
SSE 忘鉴权 无 Security 加 Bearer Token
相关推荐
小白说大模型1 小时前
去AI味提示词大全:25个实用Prompt帮你降低AI率
大数据·人工智能·pytorch·深度学习·机器学习·prompt
美狐美颜SDK开放平台1 小时前
从视频处理到实时渲染:直播APP中视频美颜SDK的关键技术解析
前端·人工智能·架构·实时互动·音视频·视频美颜sdk
重生之小比特1 小时前
【Java SE】数据类型与变量
java·开发语言·python
苏渡苇1 小时前
Spring Insight 里如何对 Span 进行清洗
java·spring boot·后端·spring·系统监控
Mr数据杨1 小时前
从下一商品推荐到实战建模 WB推荐系统竞赛案例拆解
人工智能·数据分析·kaggle竞赛
find1star1 小时前
LeetCode 54:螺旋矩阵——用四个边界模拟矩阵收缩
java·算法·leetcode·边缘计算·学习方法
Yeniden1 小时前
Java 后端从零到企业级:第1篇 Java 基础语法——变量、数据类型与运算符
java·开发语言·apache
邪修king1 小时前
Linux系统篇(二十三) 基础 IO:从“文件”到“文件描述符”,彻底理解重定向
android·java·linux
陈童学哦1 小时前
别再盲目换AI工具!先盘点你的开发工作流
人工智能