用 Spring AI 暴露 MCP 工具:Java 后端别把内部 API 直接丢给 Agent
很多团队接入 MCP 的第一反应是:把已有 REST API 包一层,让 Agent 调用。这个思路能跑通 Demo,但很容易把 AI 应用做成“会自动点接口的黑盒”。真正适合企业项目的 MCP Server,不应该只是 API 转发器,而应该是带权限、语义、审计和业务边界的工具层。
Spring AI 在 2026 年 5 月 23 日发布了 1.0.8、1.1.7 和 2.0.0-M7。其中 2.0.0-M7 提到两个和本文高度相关的变化:SSE transport 已被标记为 deprecated,Streamable HTTP 成为新的默认服务端协议;ToolCallAdvisor 成为 advisor 链中处理工具调用的标准方式。这说明 Spring AI 正在把“模型调用工具”从示例能力推向更工程化的运行链路。
MCP 的核心价值不是替代 REST API,而是让 AI Client 用统一协议发现和调用工具。按照 MCP 规范,工具有 name、description、inputSchema 等元数据,客户端可以通过 tools/list 发现工具,再通过 tools/call 调用工具。这里最关键的不是“能不能调用”,而是“模型看到的工具语义是否足够清晰,调用边界是否足够可控”。
一个常见的错误设计是这样:
createOrder(orderJson)
updateUser(userJson)
executeSql(sql)
callInternalApi(path, body)
这些工具对模型来说过于宽泛。尤其是 executeSql、callInternalApi 这类万能工具,相当于把系统边界交给提示词约束。更好的做法是把工具设计成业务动作,并让入参尽量结构化:
queryOrderStatus(orderNo, tenantId)
createRefundRequest(orderNo, reason, amount)
searchKnowledgeArticle(keyword, productCode)
在 Java 后端里,可以把 MCP Server 放在业务系统和 AI Agent 之间,作为一个“AI 可调用的应用服务层”。

用 Spring AI 2.0.0-M7 的 MCP Server Boot Starter,可以通过注解把 Spring Bean 方法注册成 MCP 工具。下面示例只展示关键思路,具体 API 可能会随版本变化,实际项目中应以官方文档为准。
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
spring:
ai:
mcp:
server:
protocol: STREAMABLE
type: SYNC
annotation-scanner:
enabled: true
@Component
public class OrderMcpTools {
private final OrderQueryService orderQueryService;
private final PermissionService permissionService;
private final AuditService auditService;
public OrderMcpTools(OrderQueryService orderQueryService,
PermissionService permissionService,
AuditService auditService) {
this.orderQueryService = orderQueryService;
this.permissionService = permissionService;
this.auditService = auditService;
}
@McpTool(
name = "query_order_status",
description = "查询指定租户下某个订单的当前状态,只返回状态、支付状态和物流摘要"
)
public OrderStatusView queryOrderStatus(
@McpToolParam(description = "订单号", required = true) String orderNo,
@McpToolParam(description = "租户 ID", required = true) String tenantId) {
permissionService.checkTenantReadable(tenantId);
auditService.record("query_order_status", tenantId, orderNo);
return orderQueryService.queryStatus(orderNo, tenantId);
}
}
这个例子里,工具不是直接暴露 OrderController,而是重新定义了 AI 可调用的业务能力。它有三个工程上的好处。
第一,返回值可控。模型不需要用户手机号、收货地址、内部备注,就不要返回。MCP 工具的输出应当是“模型完成任务所需的最小信息”,而不是数据库实体的完整 JSON。
第二,权限不依赖提示词。tenantId、用户身份、数据范围应在服务端校验。不要指望系统提示词里的“不要越权查询”能成为安全边界。对 Java 后端来说,MCP 工具仍然是线上接口,只是调用方从前端或第三方系统变成了 AI Client。
第三,审计天然可落地。每次工具调用都应该记录工具名、调用参数摘要、租户、用户、结果状态、耗时和 traceId。尤其是“写操作”工具,例如创建退款、修改工单、触发审批,必须能回放调用链路。
工具粒度也要克制。太粗,模型不知道该传什么;太细,Agent 需要多轮规划,稳定性会下降。一个实用判断是:如果这个动作在传统后台系统里本来就是一个明确按钮或服务方法,它通常适合做 MCP 工具;如果它只是某个 DAO 查询或内部工具类方法,通常不该直接暴露。
对于写操作,建议默认加二次确认。MCP 规范也强调,工具调用应当让用户清楚知道暴露了哪些工具,并且在敏感操作上保留人工确认能力。企业项目里可以把工具分成三类:
| 类型 | 示例 | 建议 |
|---|---|---|
| 只读查询 | 查询订单、搜索知识库 | 可直接调用,但要做权限和脱敏 |
| 低风险写入 | 创建草稿、生成待办 | 可自动执行,保留审计 |
| 高风险动作 | 退款、删除、发通知 | 必须人工确认或审批 |
另一个容易忽略的点是工具描述。description 不是给人看的注释,而是模型选择工具的重要依据。描述要写清楚“什么时候用、能做什么、不能做什么”。例如“查询订单状态”不如“查询指定租户下订单的当前履约状态;不能查询订单明细、用户隐私信息和支付流水”更稳。
如果系统里已经有 Spring Security、租户上下文、Micrometer、日志追踪,不需要为 MCP 另起一套。MCP Server 应该复用现有后端治理能力:认证鉴权走统一安全链路,业务校验走 Service,指标进入 Prometheus,日志带 traceId,异常映射成明确的工具调用失败结果。
MCP 给 Java 后端带来的不是“把所有接口交给模型”,而是一个重新整理系统能力的机会。把内部能力封装成小而清晰、可授权、可审计、可回滚的工具,Agent 才能真正进入业务系统;否则只是把原来由人手动触发的风险,换成了由模型自动触发。
更多推荐

所有评论(0)