第 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 旧传输,仍可用

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

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

9.3 Server:用注解暴露工具

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

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

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 异常、Error、McpError:继续上抛

  • 普通 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 → ToolCallbackProvider → ChatClient.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
连不上 url、endpoint(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 一起挂载。超时、鉴权、命名和目录裁剪处理好,比抠协议细节更影响能不能稳定跑。

相关推荐
指针向南5 小时前
canvas最大尺寸是多少:三个浏览器能画、能导出的上限
图像处理·人工智能·计算机视觉
零基础1235 小时前
LLM Agent 驱动的物模型构建:从设备手册到边缘接入的自动化实践
运维·人工智能·经验分享·python·自动化
mjhcsp5 小时前
DeepSeek V4.1 Flash 批量处理效能实测
java·前端·数据库
这张生成的图像能检测吗5 小时前
(论文速读)LINN:液体神经网络与脉冲神经元融合的可解释旋转机械故障诊断
人工智能·深度学习·神经网络·故障诊断
东方佑5 小时前
v24 (Hybrid2Fast) 架构与实验报告
人工智能·深度学习·语言模型·自然语言处理·架构
阿部多瑞 ABU5 小时前
重复的辩证法:从哲学僵尸到历史唯物主义——论意识、重复与人类解放
人工智能·ai写作
枫叶丹45 小时前
从一次推理请求出发:模型、显存、网络与服务系统如何共同决定性能
网络·人工智能·chatgpt·开源·agent·codex
YangYang9YangYan5 小时前
2027 秋招|应用统计学专业投递快消市场部,岗位 JD 拆解与统计能力落地
人工智能·数据分析
lie..5 小时前
30天从零开始学AI应用开发(Day 17):ChromaDB 上手:给本地文档建一个“外挂大脑”
数据库·人工智能·oracle
deepdata_cn5 小时前
Seedance 2.5如何敲开工厂车间的门
人工智能