MCP Server 封装存量 Java 微服务的工程模式一、为什么这件事值得单独做成一层企业里真正重要的能力,往往不在新写的 AI Demo 里,而在已经跑了很多年的 Java 微服务里:订单、库存、支付、会员、营销等核心域能力,通常已经沉淀在 Spring Boot、Dubbo、gRPC 或内部 REST 服务中这些系统经过多年演进,拥有完备的数据模型、业务规则、鉴权体系和审计链路问题不在于“能力不存在”,而在于这些能力并不是为 LLM 和 Agent 设计的于是团队常常会掉进两个误区:直接让 Agent 调已有 OpenAPI。重新写一套“AI 专用后端”。这两种方式都不理想。前者的问题是,传统 API 面向的是前端或系统集成,不是面向模型语义。接口名、参数名、枚举值、异常语义、前置条件,对 LLM 来说往往并不透明。后者的问题则是重复建设,把已经在线上被验证过的业务逻辑又复制一遍,最终形成两套规则、两套治理、两套数据口径。更合理的做法,是在存量微服务与 Agent 之间增加一层MCP Server 能力适配层:对上,暴露统一、可发现、可描述、可组合的 Tool/Resource/Prompt 能力对下,复用现有 Java 微服务的业务实现、权限模型和数据边界对中间,补齐 LLM 场景下必须有的语义描述、调用约束、并发治理和安全审计这才是 MCP 在企业架构中的真正价值:**不是替代微服务,而是把微服务升级为 Agent 可安全消费的标准能力面。**二、先把概念讲透:MCP 在微服务体系中的角色到底是什么2.1 MCP 不是网关,也不是 Agent 框架很多文章一上来就写“用 MCP 暴露工具”,但没有把它在整体架构中的职责讲清楚。MCP 更接近一种面向模型的能力协议层。它解决的是三类问题:能力发现:Agent 如何知道系统里有哪些可调用能力能力语义:模型如何理解工具的用途、参数含义、约束条件和返回结构能力调用:模型如何用统一协议触发后端动作它不直接解决的事情包括:复杂业务实现本身企业服务治理本身多智能体编排本身API 网关的统一南北向流量接入所以在企业架构里更准确的定位应该是:用户 / Agent / Host │ │ MCP Protocol ▼ MCP Server(语义暴露层 + 治理适配层) │ │ HTTP / Dubbo / gRPC / MQ / DB ▼ 存量 Java 微服务与企业基础设施一句话总结:微服务负责业务能力网关负责流量接入MCP Server负责让模型“理解并安全调用这些能力”2.2 Tool、Resource、Prompt 如何映射企业系统在企业系统里,MCP 三类原语可以这样理解:MCP 原语本质存量系统中的典型映射Tool有意图、可执行、可能有副作用的动作创建订单、发起退款、锁库存、发布配置Resource只读、可获取的上下文资源订单详情、商品资料、系统配置、知识文档Prompt预置交互模板或任务模板故障排查模板、报表分析模板、客服 SOP 模板实际项目里,最核心的是Tool。因为企业希望 Agent 不只是“会回答”,而是“能做事”。但一旦进入“做事”这个维度,架构要求就完全变了。你需要的不再只是一个能返回 JSON 的接口,而是:明确的前置条件强约束参数定义幂等语义超时策略权限校验审计追踪失败补偿风险分级这也是为什么很多 MCP Demo 可以工作,但无法直接进生产。三、存量 Java 微服务接入 MCP 的四种主流工程模式先给出结论:**不存在唯一最佳模式,只有最适合当前系统约束的模式。**3.1 选型矩阵模式适用场景改造成本运行时性能治理灵活性推荐度同进程嵌入模式可改代码、Spring Boot 为主的新老系统低最高中很高独立网关代理模式遗留系统不可改、接口分散中中很高很高Sidecar 伴生模式K8s 环境、服务粒度清晰中高高高事件驱动异步模式长耗时任务、强解耦、最终一致性高高很高高下面分别展开。四、模式 A:同进程嵌入模式4.1 适用场景如果你的存量服务本身就是 Spring Boot 应用,而且可以正常发版,那么最推荐从这一种开始。它的核心思想是:在现有服务内部直接嵌入 MCP Server,把服务中的领域能力以薄适配层方式暴露为 Tool。优势很明显:不需要再多维护一套代理服务没有额外网络转发损耗能最自然地复用现有 Spring Bean、事务、权限、日志和监控体系适合先在单个核心域快速打样,再逐步规模化4.2 推荐分层即使是同进程模式,也不建议直接把@Service方法原封不动暴露成 Tool,而应该分四层:MCP Transport 层 ↓ Tool Facade 层 ↓ Application Service 层 ↓ Domain / Repository / External Client其中真正需要暴露给 LLM 的,只应该是Tool Facade。原因很简单:领域服务的接口通常对人类程序员友好,不一定对模型友好领域服务中的参数对象往往缺少面向模型的描述信息Tool 层更适合承接参数规整、风险检查、权限校验和结果裁剪4.3 生产级代码示例下面给一份更接近真实项目的实现,而不是只停留在注解 Demo。1. 领域服务package com.example.order.application; import com.example.order.domain.Order; import com.example.order.domain.OrderRepository; import com.example.order.domain.command.CreateOrderCommand; import com.example.order.domain.command.RefundOrderCommand; import com.example.order.domain.exception.OrderNotFoundException; import com.example.order.domain.exception.RefundNotAllowedException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class OrderApplicationService { private final OrderRepository orderRepository; private final InventoryGateway inventoryGateway; private final PaymentGateway paymentGateway; public OrderApplicationService(OrderRepository orderRepository, InventoryGateway inventoryGateway, PaymentGateway paymentGateway) { this.orderRepository = orderRepository; this.inventoryGateway = inventoryGateway; this.paymentGateway = paymentGateway; } @Transactional(readOnly = true) public OrderDetailDTO getOrder(String orderId) { Order order = orderRepository.findById(orderId) .orElseThrow(() - new OrderNotFoundException(orderId)); return OrderDetailDTO.from(order); } @Transactional public CreateOrderResult createOrder(CreateOrderCommand command) { inventoryGateway.reserve(command.items()); Order order = Order.create(command.userId(), command.items(), command.requestId()); orderRepository.save(order); return new CreateOrderResult(order.getOrderId(), order.getStatus().name()); } @Transactional public RefundResult refundOrder(RefundOrderCommand command) { Order order = orderRepository.findById(command.orderId()) .orElseThrow(() - new OrderNotFoundException(command.orderId())); if (!order.canRefund(command.amount())) { throw new RefundNotAllowedException(command.orderId(), command.amount()); } paymentGateway.refund(order.ge
MCP Server 封装存量 Java 微服务的工程模式
发布时间:2026/5/31 5:18:18
MCP Server 封装存量 Java 微服务的工程模式一、为什么这件事值得单独做成一层企业里真正重要的能力,往往不在新写的 AI Demo 里,而在已经跑了很多年的 Java 微服务里:订单、库存、支付、会员、营销等核心域能力,通常已经沉淀在 Spring Boot、Dubbo、gRPC 或内部 REST 服务中这些系统经过多年演进,拥有完备的数据模型、业务规则、鉴权体系和审计链路问题不在于“能力不存在”,而在于这些能力并不是为 LLM 和 Agent 设计的于是团队常常会掉进两个误区:直接让 Agent 调已有 OpenAPI。重新写一套“AI 专用后端”。这两种方式都不理想。前者的问题是,传统 API 面向的是前端或系统集成,不是面向模型语义。接口名、参数名、枚举值、异常语义、前置条件,对 LLM 来说往往并不透明。后者的问题则是重复建设,把已经在线上被验证过的业务逻辑又复制一遍,最终形成两套规则、两套治理、两套数据口径。更合理的做法,是在存量微服务与 Agent 之间增加一层MCP Server 能力适配层:对上,暴露统一、可发现、可描述、可组合的 Tool/Resource/Prompt 能力对下,复用现有 Java 微服务的业务实现、权限模型和数据边界对中间,补齐 LLM 场景下必须有的语义描述、调用约束、并发治理和安全审计这才是 MCP 在企业架构中的真正价值:**不是替代微服务,而是把微服务升级为 Agent 可安全消费的标准能力面。**二、先把概念讲透:MCP 在微服务体系中的角色到底是什么2.1 MCP 不是网关,也不是 Agent 框架很多文章一上来就写“用 MCP 暴露工具”,但没有把它在整体架构中的职责讲清楚。MCP 更接近一种面向模型的能力协议层。它解决的是三类问题:能力发现:Agent 如何知道系统里有哪些可调用能力能力语义:模型如何理解工具的用途、参数含义、约束条件和返回结构能力调用:模型如何用统一协议触发后端动作它不直接解决的事情包括:复杂业务实现本身企业服务治理本身多智能体编排本身API 网关的统一南北向流量接入所以在企业架构里更准确的定位应该是:用户 / Agent / Host │ │ MCP Protocol ▼ MCP Server(语义暴露层 + 治理适配层) │ │ HTTP / Dubbo / gRPC / MQ / DB ▼ 存量 Java 微服务与企业基础设施一句话总结:微服务负责业务能力网关负责流量接入MCP Server负责让模型“理解并安全调用这些能力”2.2 Tool、Resource、Prompt 如何映射企业系统在企业系统里,MCP 三类原语可以这样理解:MCP 原语本质存量系统中的典型映射Tool有意图、可执行、可能有副作用的动作创建订单、发起退款、锁库存、发布配置Resource只读、可获取的上下文资源订单详情、商品资料、系统配置、知识文档Prompt预置交互模板或任务模板故障排查模板、报表分析模板、客服 SOP 模板实际项目里,最核心的是Tool。因为企业希望 Agent 不只是“会回答”,而是“能做事”。但一旦进入“做事”这个维度,架构要求就完全变了。你需要的不再只是一个能返回 JSON 的接口,而是:明确的前置条件强约束参数定义幂等语义超时策略权限校验审计追踪失败补偿风险分级这也是为什么很多 MCP Demo 可以工作,但无法直接进生产。三、存量 Java 微服务接入 MCP 的四种主流工程模式先给出结论:**不存在唯一最佳模式,只有最适合当前系统约束的模式。**3.1 选型矩阵模式适用场景改造成本运行时性能治理灵活性推荐度同进程嵌入模式可改代码、Spring Boot 为主的新老系统低最高中很高独立网关代理模式遗留系统不可改、接口分散中中很高很高Sidecar 伴生模式K8s 环境、服务粒度清晰中高高高事件驱动异步模式长耗时任务、强解耦、最终一致性高高很高高下面分别展开。四、模式 A:同进程嵌入模式4.1 适用场景如果你的存量服务本身就是 Spring Boot 应用,而且可以正常发版,那么最推荐从这一种开始。它的核心思想是:在现有服务内部直接嵌入 MCP Server,把服务中的领域能力以薄适配层方式暴露为 Tool。优势很明显:不需要再多维护一套代理服务没有额外网络转发损耗能最自然地复用现有 Spring Bean、事务、权限、日志和监控体系适合先在单个核心域快速打样,再逐步规模化4.2 推荐分层即使是同进程模式,也不建议直接把@Service方法原封不动暴露成 Tool,而应该分四层:MCP Transport 层 ↓ Tool Facade 层 ↓ Application Service 层 ↓ Domain / Repository / External Client其中真正需要暴露给 LLM 的,只应该是Tool Facade。原因很简单:领域服务的接口通常对人类程序员友好,不一定对模型友好领域服务中的参数对象往往缺少面向模型的描述信息Tool 层更适合承接参数规整、风险检查、权限校验和结果裁剪4.3 生产级代码示例下面给一份更接近真实项目的实现,而不是只停留在注解 Demo。1. 领域服务package com.example.order.application; import com.example.order.domain.Order; import com.example.order.domain.OrderRepository; import com.example.order.domain.command.CreateOrderCommand; import com.example.order.domain.command.RefundOrderCommand; import com.example.order.domain.exception.OrderNotFoundException; import com.example.order.domain.exception.RefundNotAllowedException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class OrderApplicationService { private final OrderRepository orderRepository; private final InventoryGateway inventoryGateway; private final PaymentGateway paymentGateway; public OrderApplicationService(OrderRepository orderRepository, InventoryGateway inventoryGateway, PaymentGateway paymentGateway) { this.orderRepository = orderRepository; this.inventoryGateway = inventoryGateway; this.paymentGateway = paymentGateway; } @Transactional(readOnly = true) public OrderDetailDTO getOrder(String orderId) { Order order = orderRepository.findById(orderId) .orElseThrow(() - new OrderNotFoundException(orderId)); return OrderDetailDTO.from(order); } @Transactional public CreateOrderResult createOrder(CreateOrderCommand command) { inventoryGateway.reserve(command.items()); Order order = Order.create(command.userId(), command.items(), command.requestId()); orderRepository.save(order); return new CreateOrderResult(order.getOrderId(), order.getStatus().name()); } @Transactional public RefundResult refundOrder(RefundOrderCommand command) { Order order = orderRepository.findById(command.orderId()) .orElseThrow(() - new OrderNotFoundException(command.orderId())); if (!order.canRefund(command.amount())) { throw new RefundNotAllowedException(command.orderId(), command.amount()); } paymentGateway.refund(order.ge