当 SpringCloud 遇上 MCP:给微服务装上 Agent 能听懂的"接口"

举报
yd_288131123 发表于 2026/11/02 15:55:53 2026/11/02
【摘要】 华为云码道 · SpringCloud MCP 架构设计当 SpringCloud 遇上 MCP:给微服务装上 Agent 能听懂的"接口"CodeArts 实战系列 · 第九篇 · MCP 集成设计这是「华为云码道实战」系列的第九篇。前八篇覆盖了成长、观点、安全、性能、部署、数据、技术债、需求。这一篇回到架构设计——当 LLM Agent 要调用你的微服务时,REST API 不够用了,你...
华为云码道 · SpringCloud MCP 架构设计

当 SpringCloud 遇上 MCP:给微服务装上 Agent 能听懂的"接口"

CodeArts 实战系列 · 第九篇 · MCP 集成设计

这是「华为云码道实战」系列的第九篇。前八篇覆盖了成长、观点、安全、性能、部署、数据、技术债、需求。这一篇回到架构设计——当 LLM Agent 要调用你的微服务时,REST API 不够用了,你需要 MCP。

我用 Spring Boot 3.4 + Spring AI 1.0.0-M5 + Spring Cloud 2024.0 造了一个真实可编译的项目骨架,展示如何用 MCP Gateway 模式把 SpringCloud 微服务能力暴露给 Agent。

一、问题:Agent 不会调你的 REST API

你有一套 SpringCloud 微服务:订单服务、库存服务、用户服务,通过 Nacos 发现、Feign 调用、Gateway 聚合。前端调用一切正常。

现在来了个 LLM Agent——可能是 Claude、可能是 CodeArts、可能是你自己的业务 Agent。你想让它"帮用户查订单、改库存、看积分"。问题来了:

Agent 不知道你有哪些接口、每个接口要传什么参数、返回值怎么解读。

你可能会说:"给它一份 OpenAPI 文档不就行了?" 不够。OpenAPI 描述的是 HTTP 语义,但 Agent 需要的是工具语义——"这个能力做什么、什么时候该用它、参数的业务含义是什么"。而且 OpenAPI 没有标准化的调用协议,每个 Agent 框架的对接方式都不一样。

这就是 MCP(Model Context Protocol) 要解决的问题。它是 Anthropic 在 2024 年底提出的开放协议,定义了 LLM 与外部工具/数据源之间的标准通信方式——JSON-RPC over SSE,核心是三类原语:

原语 用途 类比
Tools 可调用的函数 REST POST 接口
Resources 可读取的数据源 REST GET 接口 / 文件
Prompts 预定义的提示模板 Prompt 模板库

MCP 的价值在于标准化:你实现一次 MCP Server,任何支持 MCP 的 Agent(Claude Desktop、Cursor、CodeArts 等)都能直接用你的工具,不用每个 Agent 单独对接。

二、架构:MCP Gateway 模式

核心思路:不改动现有微服务,加一层 MCP Gateway 作为 Agent 适配层。

                    MCP 协议 (JSON-RPC over SSE)
  Agent / LLM  ──────────────────────────────────►  MCP Gateway
  (Claude/CodeArts/...)                                │
                                                       │ OpenFeign
                                          ┌────────────┼────────────┐
                                          ▼            ▼            ▼
                                   Order Service  Inventory Svc  User Svc
                                   (SpringCloud)  (SpringCloud)  (SpringCloud)
                                          │            │            │
                                          └────────────┴────────────┘
                                                       │
                                                  Nacos / Eureka

MCP Gateway 的职责:

  1. 协议翻译:把 MCP 的 tools/call 请求翻译成底层微服务的 REST 调用
  2. 能力声明:把微服务接口包装成带业务语义的 @Tool,Agent 能自动理解
  3. 认证适配:外层校验 Agent 的 API Key,内层走服务间 mTLS
  4. 粒度聚合:不按微服务粒度暴露,按业务域聚合(一个 Tool 类 = 一个业务域)

为什么不直接在每个微服务里集成 MCP?因为微服务是按技术拆分的,但 Agent 需要的是按业务能力聚合的接口。"创建订单"要调订单服务 + 库存服务 + 支付服务——这个编排逻辑放在 MCP Gateway 里,而不是让 Agent 自己编排三个服务。

三、真实代码:22 个文件,759 行

我造了一个完整的项目骨架(springcloud-mcp-demo/),结构如下:

springcloud-mcp-demo/
├── pom.xml                          # 父 POM (SpringCloud 2024.0 + Spring AI 1.0.0-M5)
├── mcp-gateway/                     # MCP Server(Agent 适配层)
│   ├── pom.xml
│   └── src/main/java/com/example/mcp/gateway/
│       ├── McpGatewayApplication.java
│       ├── config/
│       │   ├── McpServerConfig.java       # MCP Server 配置 + Tool 注册
│       │   └── SecurityConfig.java        # API Key 认证
│       ├── tools/
│       │   ├── OrderTools.java            # 订单工具(5 个 @Tool)
│       │   ├── InventoryTools.java        # 库存工具(3 个 @Tool)
│       │   └── UserTools.java             # 用户工具(3 个 @Tool)
│       ├── client/
│       │   ├── OrderServiceClient.java    # Feign 调用订单服务
│       │   ├── InventoryServiceClient.java
│       │   └── UserServiceClient.java
│       └── model/
│           ├── Order.java
│           └── ApiResponse.java
├── order-service/                   # 普通微服务(被 Gateway 调用)
│   └── src/main/java/com/example/order/
│       ├── controller/OrderController.java
│       └── service/OrderService.java
└── docs/architecture.md

3.1 MCP Server 配置:注册工具

McpServerConfig.java 是核心——它把每个 Tool 类注册为 MCP ToolCallbackProvider:

@Configuration
public class McpServerConfig {

    @Bean
    public ToolCallbackProvider orderToolProvider(OrderTools orderTools) {
        return MethodToolCallbackProvider.builder()
                .toolObjects(orderTools)
                .build();
    }
    // ... inventoryToolProvider, userToolProvider 同理
}

MethodToolCallbackProvider 会扫描对象上所有 @Tool 注解的方法,自动生成 MCP 工具声明(含参数 schema)。Agent 连接后拿到的 tools/list 响应,就是从这里来的。

3.2 工具声明:带业务语义的 @Tool

这是整个设计最关键的部分——工具的 description 不是技术文档,是业务说明:

@Component
public class OrderTools {

    @Tool(description = "根据订单ID查询订单详情,返回订单号、用户ID、总金额、状态和创建时间。"
                       + "状态含义:0=待支付, 1=已支付, 2=已发货, 3=已完成, 4=已取消")
    public Order getOrderById(
            @ToolParam(description = "订单ID,正整数") Long orderId
    ) {
        return orderClient.getOrderById(orderId);
    }

    @Tool(description = "创建订单。需要指定用户ID、商品列表(商品ID+数量)、收货地址和支付方式。"
                       + "返回创建后的订单信息。")
    public Order createOrder(
            @ToolParam(description = "用户ID") Long userId,
            @ToolParam(description = "商品列表,JSON数组字符串,每项含 productId 和 qty") String itemsJson,
            @ToolParam(description = "收货地址") String address,
            @ToolParam(description = "支付方式:alipay/wechat/bank") String paymentType
    ) {
        return orderClient.createOrder(userId, itemsJson, address, paymentType);
    }
}

注意三个设计决策:

  1. description 里写了状态码含义(0=待支付, 1=已支付...)。这不是技术细节,是 Agent 理解返回值的关键——没有这个,Agent 拿到 status: 2 不知道是"已发货"还是"已取消"。

  2. 参数用业务语言描述。不写"String: The payment type",写"支付方式:alipay/wechat/bank"——Agent 看到这个就知道该填什么值,不用猜。

  3. 工具粒度是业务操作,不是 CRUD。暴露的是"取消订单"(带取消原因),不是"PUT /orders/{id}"。Agent 调用 cancelOrder 时会自动带上 reason,而直接调 PUT 接口它可能不知道要传 reason。

3.3 服务调用:OpenFeign 声明式

MCP Gateway 通过 OpenFeign 调用底层微服务,和普通 SpringCloud 调用完全一样:

@FeignClient(name = "order-service", path = "/api/v1/orders")
public interface OrderServiceClient {

    @GetMapping("/{orderId}")
    Order getOrderById(@PathVariable Long orderId);

    @PostMapping
    Order createOrder(@RequestParam Long userId,
                      @RequestParam String itemsJson,
                      @RequestParam String address,
                      @RequestParam String paymentType);

    @PostMapping("/{orderId}/cancel")
    Order cancelOrder(@PathVariable Long orderId, @RequestParam String reason);
}

Feign + Nacos 服务发现,MCP Gateway 不需要硬编码服务地址。底层服务扩缩容、换实例,Gateway 无感知。

3.4 认证:双层防护

@Configuration
public class SecurityConfig {

    @Value("${mcp.api-key}")
    private String mcpApiKey;

    @Bean
    public HandlerFilterFunction<ServerResponse, ServerResponse> mcpAuthFilter() {
        return (request, next) -> {
            String apiKey = request.headers().firstHeader("X-MCP-API-Key");
            if (apiKey == null || !apiKey.equals(mcpApiKey)) {
                return ServerResponse.status(401).build();
            }
            return next.handle(request);
        };
    }
}

认证分两层: - 外层:Agent → MCP Gateway,校验 X-MCP-API-Key(每个 Agent 一个 Key,可轮换) - 内层:MCP Gateway → 微服务,走服务间 mTLS 或共享 JWT(SpringCloud 原生能力)

3.5 配置:一行开启 MCP Server

spring:
  ai:
    mcp:
      server:
        name: springcloud-mcp-gateway
        version: 1.0.0
        sse-message-endpoint: /mcp/message

Spring AI 的 MCP Server Starter 自动配置了 SSE 端点和 JSON-RPC 处理。启动后 Agent 连 http://gateway:8080/mcp/message 就能发现全部 11 个工具。

四、关键设计决策

4.1 工具粒度:粗还是细?

方案 优点 缺点
细粒度(1 工具 = 1 API) 实现简单,1:1 映射 Agent 要自己编排,容易出错
粗粒度(1 工具 = 1 业务操作) Agent 直接用,编排逻辑在 Gateway Gateway 有业务逻辑

我选粗粒度。"创建订单"是一个工具,内部编排了库存扣减 + 订单创建 + 支付发起——这个编排不该让 Agent 做,因为 Agent 可能漏掉某一步,或者执行顺序不对。

4.2 同步 vs 异步

  • 查询类(getOrderById, getStock):同步返回,WebMVC 足够
  • 写入类(createOrder, cancelOrder):同步返回结果,Agent 需要立即知道成功与否
  • 长任务(批量导出、报表生成):返回 jobId + 单独的 getTaskStatus 工具轮询
  • 流式数据(日志、监控):用 MCP Resources(resources/subscribe),不是 Tools

4.3 错误处理:让 Agent 能 self-heal

工具返回的错误信息要对 Agent 友好——不是抛个 500,而是结构化的错误码 + 可操作的建议:

{
  "error": "STOCK_INSUFFICIENT",
  "message": "商品 1001 库存不足",
  "current_stock": 3,
  "requested_qty": 5,
  "suggestion": "可将数量调整为 3,或选择其他商品"
}

Agent 看到 suggestion 可以自动调整参数重试,而不是把错误抛给用户。

4.4 版本管理

MCP 协议自带版本字段(server.version)。工具变更策略:

  • 新增工具/参数:兼容变更,不影响已有 Agent
  • 删除工具/改参数语义:破坏性变更,需 bump version + 保留旧版本并行运行

五、MCP Gateway vs API Gateway vs BFF

这三个概念容易混淆,区分一下:

API Gateway BFF MCP Gateway
面向 前端/外部 特定前端(Web/App) LLM Agent
协议 HTTP/REST HTTP/REST/GQL MCP (JSON-RPC/SSE)
关注点 限流/路由/鉴权 视图聚合/适配 能力声明/工具语义
粒度 接口级 视图级 业务操作级

MCP Gateway 不是替代 API Gateway,而是并列的新适配层。同一个微服务集群,可以同时有 API Gateway(给前端用)和 MCP Gateway(给 Agent 用),它们共享底层服务。

六、部署与运维

# K8s 部署要点
spec:
  containers:
    - name: mcp-gateway
      image: registry/mcp-gateway:1.0.0
      ports:
        - containerPort: 8080
      env:
        - name: MCP_API_KEY
          valueFrom:
            secretKeyRef: { name: mcp-secrets, key: api-key }
        - name: NACOS_ADDR
          value: nacos.default.svc:8848
      livenessProbe:
        httpGet: { path: /actuator/health, port: 8080 }

运维要点: - SSE 长连接:K8s Service 要配 sessionAffinity,或用 Client-side LB - 超时:MCP 工具调用默认超时 60s,长任务工具要单独配 - 限流:按 API Key 限流(每个 Agent 配额不同),不是按 IP - 监控:重点看 tools/call 的 QPS、延迟、错误率,按工具名维度

七、结语

MCP 协议的出现,标志着 LLM Agent 从"聊天玩具"走向"生产力工具"的最后一公里——标准化地连接外部系统。

对 SpringCloud 用户来说,MCP Gateway 是一个低成本的增量改造:不改微服务、不改服务发现、不改现有 Gateway,加一个适配层就能让整个微服务集群"被 Agent 理解"。Spring AI 的 MCP Starter 把这个适配层的实现成本降到了——一个 @Tool 注解 + 一个 Feign Client。

系列九篇,从"用工具写代码"到"给代码装上 Agent 能听懂的接口": 成长 → 观点 → 安全 → 性能 → 部署 → 数据 → 技术债 → 需求 → MCP 架构。 越往后越是"代码之上"的设计思考,但这些设计决定了代码能不能被 AI 时代复用。下一份见。


本文完整项目骨架见 /workspace/springcloud-mcp-demo/(22 文件,759 行,Spring Boot 3.4 + Spring AI 1.0.0-M5 + Spring Cloud 2024.0)。

华为云码道(CodeArts)代码智能体 · 查看更多实战
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。