MCP第 5 篇:用 Spring AI 写 MCP:注解、自动配置、ChatClient 集成

第 5 篇:用 Spring AI 写 MCP------注解、自动配置、ChatClient 集成

📍 系列导航 :1. 认识 MCP | 2. 本地实战 | 3. 多能力工程 | 4. HTTP URL | 5. Spring AI | 6. 企业治理

5.1 Spring AI 和 MCP SDK 是什么关系

先澄清一个常见误解:

💡 Spring AI 不是 MCP 的替代品,它是 Spring 生态的 AI 应用框架,内部集成了 MCP。

text 复制代码
Spring AI(应用框架)
   └── 集成 MCP
        └── 底层:官方 MCP Java SDK
维度 官方 MCP Java SDK Spring AI
定位 协议实现库 Spring 生态 AI 应用框架
依赖 io.modelcontextprotocol.sdk:mcp org.springframework.ai:*
写 Server 手动 McpServer.sync(...)、手动定义 Tool 注解 + 自动配置 + starter
写 Client 手动 McpClient.sync(...) ChatClient 集成 MCP Client
适合 理解协议、轻量 Server、非 Spring 项目 Spring Boot 项目、Chat/RAG/Tool 一体化

⚠️ 版本说明:Spring AI 1.0 前后 artifact 名、注解包路径有调整。以下示例以 Spring AI 1.0.x 为参考,实际以官方文档为准。

5.2 Spring AI 作为 MCP Server:注解式 Tool

5.2.1 pom 依赖

xml 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

artifact 名可能随版本变化,以 Spring AI 官方文档的 MCP Server starter 为准。

5.2.2 application.yml

yaml 复制代码
server:
  port: 8080
  servlet:
    context-path: /sales

spring:
  ai:
    mcp:
      server:
        name: sales-server
        version: 1.0.0
        # 端点路径由 starter 默认或在此配置,具体键名以版本为准

5.2.3 用 @Tool 声明工具(基础版)

java 复制代码
package com.example.sales;

import com.example.sales.model.SalesRecord;
import com.example.sales.service.SalesService;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class SalesTools {

    private final SalesService service;

    public SalesTools(SalesService service) {
        this.service = service;
    }

    @Tool(name = "sales_query", description = "按地区和 ISO 周查询销售数据")
    public SalesRecord querySales(
            @ToolParam(description = "地区名称,例如 华东、华南、华北") String region,
            @ToolParam(description = "ISO 周,格式 YYYY-Www,例如 2026-W20") String week) {
        return service.query(region, week);
    }

    @Tool(name = "sales_top_regions", description = "返回指定周营收最高的地区")
    public List<SalesRecord> topRegions(
            @ToolParam(description = "ISO 周,格式 YYYY-Www") String week,
            @ToolParam(description = "返回数量,默认 3,范围 1-20", required = false) Integer limit) {
        return service.topRegions(week, limit == null ? 3 : limit);
    }
}

对比第 2 篇:

维度 官方 SDK(第 2 篇) Spring AI(本篇)
定义 Tool 手动 McpSchema.Tool + JSON Schema 字符串 @Tool + 方法签名
参数描述 手写 JSON Schema @ToolParam
异常处理 手动 try/catch 可交给全局异常处理
注册 手动 .tools(...) 自动扫描 @Tool
代码量 多 少

5.2.4 多模态返回:把图片 URL 映射为 ImageContent

Spring AI 相比官方 SDK 的一个优势:对多模态返回有更好的封装。

假设 Tool 需要返回一张图表:

java 复制代码
@Tool(name = "sales_chart", description = "生成指定周的销售趋势图,返回图表 URL")
public ChartResult generateChart(
        @ToolParam(description = "ISO 周,例如 2026-W20") String week) {
    String imageUrl = chartService.render(week);   // 生成 PNG,上传到对象存储
    return new ChartResult(imageUrl, "2026-W20 销售趋势");
}

public record ChartResult(String imageUrl, String caption) {}

Spring AI 在把 Tool 结果序列化回 MCP 时,会根据返回类型和内容自动映射为 MCP 的 ImageContent 或 TextContent。对于包含 imageUrl 的对象,通常有两种方式:

方式一:返回 URL 字符串,让模型通过文本引用

最简单,模型拿到 URL 后可以在回复里引用。适合"让模型描述图片"或"在前端展示"。

方式二:返回 ImageContent,让模型直接看到图片

如果你希望模型直接"看图"做分析,需要返回 MCP 的 ImageContent(Base64 或 URL)。Spring AI 的 MCP 扩展会识别 Media 类型或 org.springframework.ai.content.Media,自动转为 ImageContent:

java 复制代码
import org.springframework.ai.content.Media;
import org.springframework.core.io.ByteArrayResource;

@Tool(name = "sales_chart", description = "生成指定周的销售趋势图")
public Media generateChart(
        @ToolParam(description = "ISO 周,例如 2026-W20") String week) {
    byte[] png = chartService.renderBytes(week);
    return new Media(
        org.springframework.util.MimeTypeUtils.IMAGE_PNG,
        new ByteArrayResource(png)
    );
}

模型收到 ImageContent 后,可以直接对图表做视觉分析(如"哪个地区下降最快"),而不只是读数字。

💡 选型建议:

  • 只需要模型引用图表 → 返回 URL 字符串
  • 需要模型"看图"分析 → 返回 Media / ImageContent
  • Base64 会显著增大上下文,大图优先用 URL

这个能力是官方 SDK 手写 JSON Schema 时比较难优雅实现的,也是 Spring AI 在多模态场景的加分项。

5.2.5 注册 Tool 到 MCP Server

Spring AI 的 MCP Server starter 通常会自动发现 @Tool 方法,或通过 ToolCallbackProvider 显式注册:

java 复制代码
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class McpToolConfig {

    @Bean
    public ToolCallbackProvider salesToolCallbackProvider(SalesTools salesTools) {
        return MethodToolCallbackProvider.builder()
            .toolObjects(salesTools)
            .build();
    }
}

不同版本可能自动注册,也可能需要显式 ToolCallbackProvider。以官方示例为准。

5.2.6 启动与验证

bash 复制代码
mvn spring-boot:run

端点(以 starter 默认路径为准,常见为 /sse、/mcp/message 或可配置):

text 复制代码
http://localhost:8080/sales/sse

用 MCP Inspector 或 Claude Desktop 验证工具列表。

5.3 Spring AI 作为 MCP Client:ChatClient 集成

如果对方是 Spring AI 应用,可以用 ChatClient 直接消费 MCP Server。

5.3.1 pom 依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>

5.3.2 application.yml

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        enabled: true
        name: my-agent
        version: 1.0.0
        type: SYNC
        sse:
          connections:
            sales:
              url: https://mcp.example.com/sales/mcp

配置键名随版本变化,以 Spring AI 官方文档的 MCP Client 配置为准。

5.3.3 用 ChatClient 调用

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.web.bind.annotation.*;

@RestController
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient.Builder builder,
                          ToolCallbackProvider mcpTools) {
        this.chatClient = builder
            .defaultTools(mcpTools)   // 把 MCP Server 的工具注入 ChatClient
            .build();
    }

    @GetMapping("/chat")
    public String chat(@RequestParam String q) {
        return chatClient.prompt()
            .user(q)
            .call()
            .content();
    }
}

用户问"查一下 2026-W20 华东销售",Spring AI 会自动:

  1. 把 MCP Server 的工具描述注入模型上下文
  2. 模型决定调用 sales_query
  3. Spring AI 通过 MCP Client 转发给 Server
  4. 结果回填给模型
  5. 生成自然语言回复

5.4 什么时候用 Spring AI,什么时候用官方 SDK

你的情况 建议
已有 Spring Boot 项目,还要 Chat/RAG Spring AI
想快速写 Tool,少写胶水 Spring AI
需要多模态返回(图片、音频) Spring AI
想理解协议、完全控制 官方 SDK
非 Spring 项目、轻量 Server 官方 SDK
需要 MCP Server + MCP Client 一体化 Spring AI
需要精细控制 Transport / Schema 官方 SDK

两者底层协议一致,可以混用:Server 用官方 SDK,Client 用 Spring AI,或反过来。

5.5 Spring AI 写 MCP 的常见坑

坑 解决
starter 版本不匹配 用 spring-ai-bom 统一版本
@Tool 没被扫描 确认组件扫描路径,或显式 ToolCallbackProvider
参数描述缺失 @ToolParam 写清格式和示例
返回对象无法序列化 用 record / POJO,确保 Jackson 可序列化
异常直接抛出 配全局异常处理,转可读错误
MCP Server 端点路径不清楚 查 starter 文档,或显式配置
Client 配置键名不对 以当前版本文档为准,不要照抄旧博客
多模态返回 Base64 过大 大图优先返回 URL,不让模型直接读 Base64

5.6 本篇小结

  • Spring AI 是上层框架,底层仍是官方 MCP SDK。
  • Server 侧:@Tool + @ToolParam + starter 自动配置,代码量大幅减少。
  • Client 侧:ChatClient + ToolCallbackProvider,自动完成工具注入和调用。
  • 多模态返回:Media / ImageContent 让模型能"看图",但大图优先用 URL。
  • 选型看项目:Spring Boot 项目优先 Spring AI,轻量/非 Spring 用官方 SDK。

下一篇:Spring AI Alibaba 封装 MCP------Nacos 注册、Gateway、企业级治理。


相关推荐
康实训1 小时前
老年评估仿真实训平台架构设计与老年人能力评估实训室教学落地实践
大数据·人工智能·算法·实训室·实训室建设
misty youth1 小时前
Agent-智能体工程方法论
人工智能·ai·llm·agent·智能体
lisw051 小时前
制造业信息化:现代工业的发展趋势!
大数据·网络·人工智能
AllData公司负责人1 小时前
AllData搭建大模型资产中台集成开源项目BISHENG/Crater/Coze-Studio/Coze-Loop/DataFIow,建设AI大模型开发底座
大数据·人工智能·开源·bisheng·coze-studio·crater·datafiow
DongQiShanRen1 小时前
六根硬件映射(四):归属澄清、两处不一致与卷十一总表
开发语言·人工智能·算法·rust·哈希算法·集成学习
麦豆GEO1 小时前
官网GEO优化指南:从展示窗口到AI品牌认知中心
人工智能
阡陌数智1 小时前
Gemini 4 Argon 百万 Token 输出能力解析:原生长输出模型的工程落地与并发成本治理
人工智能·架构
丑梨数据2 小时前
信创环境里跑文档工具:格式兼容与本地合规的几个坑
数据结构·人工智能·算法·决策树·排序算法
麦豆GEO2 小时前
GEO与传统内容营销的核心差异:AI时代内容运营的全面升级
大数据·人工智能·内容运营