第 9 章 · Model Context Protocol(MCP)

版本:Spring AI 2.0.1 (MCP Java SDK 2.0.0

目标:分清 Host / Server,选对 starter 与传输,用注解暴露工具,并把 MCP Tool 桥进 ChatClient

本地 @Tool 写在本进程里。工具若在别的服务、别的语言、别的团队,各自再包一层私有 HTTP,目录和鉴权很快就会散。

MCP 约定的是一套标准协议:Host(通常是你的 AI 应用)去连接一个或多个 MCP Server,发现并调用其上的 Tools、Resources、Prompts。Spring AI 在两边都能站:当 Client 连别人,或当 Server 对外暴露能力。对 ChatClient 而言,远端 Tool 最终会桥成 ToolCallback,挂载方式与第 8 章相同。

bash 复制代码
本地 @Tool     → 同进程 Bean
MCP Tool       → 跨进程 / 跨语言,桥成 ToolCallback 后再挂

MCP 管「工具从哪来」,不管「怎么编排」;也管不了权限------鉴权仍在你的 Java 代码里。


9.1 角色与能力

上图里:

  • Host :Spring AI 应用,里面有 ChatClient

  • 传输:STDIO / SSE / HTTP 等

  • Server:提供 Tools、Resources、Prompts

  • ToolCallback:把远端工具结果接回 Host

情况 做法
工具就是本服务 Bean 本地 @Tool
工具在别的进程 / 语言 / 团队 对端做 MCP Server,本应用做 Client
两边都要 .tools(本地 POJO, mcpProvider) 一起挂

三类常见能力:

能力 做什么
Tools 可执行操作,如查单、建工单
Resources 按 URI 读内容,如政策原文
Prompts 可复用的提示模板

日常先把 Tools 桥进 ChatClient;Resources / Prompts 按产品需要再接。


9.2 Starter 与传输

角色 Starter
本应用连别人(Client) spring-ai-starter-mcp-client;响应式栈可用 ...-client-webflux
本服务对外暴露(Server,MVC) spring-ai-starter-mcp-server-webmvc
本服务对外暴露(Server,WebFlux) spring-ai-starter-mcp-server-webflux

已有 Spring MVC 业务选 webmvc;整站 WebFlux 选 webflux。Client 同步 / 异步要和 Web 栈一致:

bash 复制代码
spring.ai.mcp.client.type=SYNC

依赖示例:

xml 复制代码
<!-- Host:连远端 MCP Server -->
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
​
<!-- Server:MVC 对外暴露 -->
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>

Client 用 Streamable-HTTP 连接远端(2.0.1 推荐;键名以当前 starter 文档为准):

xml 复制代码
spring:
  ai:
    mcp:
      client:
        enabled: true
        type: SYNC
        streamable-http:
          connections:
            order-server:
              url: http://localhost:8091
              endpoint: /mcp

Server 侧对应:

xml 复制代码
spring:
  ai:
    mcp:
      server:
        type: SYNC
        protocol: STREAMABLE
        mcp-endpoint: /mcp

本机子进程也可用 STDIO;旧的 SSE 传输仍可用,但新项目优先 STREAMABLE。

传输 常见用途
STDIO 本机子进程 / sidecar
Streamable-HTTP 服务之间(2.0.1 推荐)
SSE 旧传输,仍可用

连不上时先查:urlendpoint、端口和防火墙。 若已连上 Server,但暂时不想把工具交给 ChatClient:

bash 复制代码
spring.ai.mcp.client.toolcallback.enabled=false

9.3 Server:用注解暴露工具

注解 作用
@McpTool / @McpToolParam 声明工具与参数(自动生成 JSON Schema)
@McpResource 声明可读资源
@McpPrompt / @McpComplete 声明提示模板与补全

annotations = @McpTool.McpAnnotations(...) 里的 readOnlyHintdestructiveHintidempotentHint 只是给调用方的提示,不是鉴权。租户、用户校验仍要写在方法体内。

java 复制代码
@Service
public class OrderMcpTools {
​
    private final OrderService orderService;
​
    public OrderMcpTools(OrderService orderService) {
        this.orderService = orderService;
    }
​
    @McpTool(
            name = "query_order",
            description = "按订单号查询订单摘要,返回简短 JSON",
            annotations = @McpTool.McpAnnotations(readOnlyHint = true))
    public String queryOrder(
            @McpToolParam(description = "订单号", required = true) String orderId) {
        // 在这里做调用方鉴权,不要依赖 hint
        return orderService.findBrief(orderId);
    }
​
    @McpTool(
            name = "create_ticket",
            description = "创建售后工单,成功返回工单号",
            annotations = @McpTool.McpAnnotations(destructiveHint = true))
    public String createTicket(
            @McpToolParam(description = "订单号", required = true) String orderId,
            @McpToolParam(description = "问题描述", required = true) String problem) {
        return orderService.createTicket(orderId, problem);
    }
}

异常处理与本地 @Tool 同一套约定(2.0.1):

  • checked 异常、ErrorMcpError:继续上抛

  • 普通 RuntimeException(且不是 McpError):转成工具错误结果给调用方

不要默认「所有异常都会变成一段错误字符串」。

资源示例:

java 复制代码
@McpResource(
        uri = "handbook://refund-policy",
        name = "refund-policy",
        description = "退款政策原文")
public String refundPolicy() {
    return handbookRepository.load("refund-policy");
}

Resource 常被读进 Prompt,脱敏和租户隔离要与 Tool 同等对待。


9.4 Client:挂到 ChatClient

链路是:MCP Server → 传输 → MCP Client → ToolCallbackProviderChatClient.tools(...) / defaultTools(...)

Boot 会提供 Provider(类名以自动配置为准,常见如 SyncMcpToolCallbackProvider)。它实现 ToolCallbackProvider,可直接传给第 8 章学过的挂载入口。

默认挂上(本 Client 的请求都能看见这些工具):

java 复制代码
@Configuration
class AiConfig {
​
    @Bean
    ChatClient chatClient(
            ChatClient.Builder builder,
            SyncMcpToolCallbackProvider mcpTools,
            OrderLocalTools localTools) {
        return builder
                .defaultTools(mcpTools, localTools)
                .build();
    }
}

只在某次请求挂载(目录按场景裁剪时更常用):

java 复制代码
String answer = chatClient.prompt()
        .user("查一下订单 10086 能不能退")
        .tools(mcpTools, localTools)
        .call()
        .content();

注意第 8 章的覆盖规则:请求级 tools(...) 会整组替换 defaultTools,不是合并。需要「默认 + 再加几个」时,把完整列表一次传入。

权限仍分两层:

  1. Server:接口鉴权、数据租户隔离

  2. Host :业务上谁能调哪个工具(例如只有客服角色能 create_ticket

模型只会按名称发起调用;是否真正执行,由你的代码决定。

工具很多时,可先按权限过滤可见集,再对可见集做目录检索(第 8 章 Tool Search),避免一次把远端全量 schema 塞进 Prompt。远端工具列表变更时,记得失效缓存或重建索引。


9.5 和本地 @Tool 怎么选

本地 @Tool MCP
部署 同进程 跨进程 / 跨语言
发布 随应用发版 Server 可单独升级
超时 本地方法调用 必须设超时,建议加熔断
失败 本地异常 网络故障 + 远端业务错误

命名建议带前缀(如 order_query_order),减少远程 search 与本地 search 撞名。若同一批工具既给 ChatClient 用,也给图编排用,放进同一注册表,避免两套名字。


9.6 常见坑

现象 先查什么
ChatClient 里没有 MCP 工具 是否连上 Server;toolcallback.enabled;Provider 是否注入;有没有 .tools / defaultTools
连不上 urlendpoint(STREAMABLE)或 sse-endpoint(SSE)、端口、防火墙;Client SYNC/ASYNC 是否匹配 Web 栈
一调远端就卡住 超时与熔断;错误是否回成短字符串给模型
鉴权失败 / 串租户 凭证如何进入 MCP Session;不要依赖线程 ThreadLocal 碰巧还能用
不该调的工具被调了 Host 侧白名单与业务鉴权;不要只靠 Server hint
异常表现和本地 @Tool 不一致 是否误吞了应上抛的异常;对照 2.0.1 异常约定
与本地工具同名 前缀;打印最终暴露给模型的 tool name 列表核对

9.7 小结

MCP 让工具可以放在别的进程里,但对 ChatClient 仍是 ToolCallback 供应线。先分清自己做 Client 还是 Server,选对 starter 和传输,用 @McpTool 暴露能力,再和本地 @Tool 一起挂载。超时、鉴权、命名和目录裁剪处理好,比抠协议细节更影响能不能稳定跑。

相关推荐
张小姐的猫1 小时前
【AI大模型接入SDK】 —— SQLite上手
linux·开发语言·c++·人工智能·python·log4j
雨辰AI1 小时前
信创多租户项目 9 大踩坑|数据隔离失效、权限越权终极解决(金仓 / 达梦 / 高斯全库适配)
java·大数据·数据库·后端
captain3761 小时前
网络原理(4)-TCP ▲▲▲
java·服务器·网络·网络协议·tcp/ip
陈嘿萌1 小时前
ECCV 2026|MAVFusion:运动感知稀疏交互驱动的高效红外-可见光视频融合
人工智能·计算机视觉·图像融合·佛山大学·学术研究与理论基础·eccv2026
俊哥V1 小时前
每日 AI 研究简报 · 2026-09-14
人工智能·ai
孙启超1 小时前
【AI开发之Rust】第 5 课:引用与生命周期 —— 借用能活多久?
人工智能·后端·rust·llm·ai应用开发
橙子圆1231 小时前
JUC之线程和进程
java
码流子1 小时前
2026 图像数据标注工具横评:LabelImg / CVAT / Label Studio / X-AnyLabeling / 国产Web平台,到底怎么选?
大数据·人工智能·算法
必须会一定会1 小时前
LiTwin 任务004:JSON Schema、OpenAPI、TypeScript、Java DTO 质量门禁实现
人工智能·程序人生·ai编程