Spring AI / Model Context Protocol (MCP) / MCP Client Boot Starters

Spring AI 参考文档

模型上下文协议 (MCP)

MCP 客户端启动启动器

MCP 客户端启动启动器

Spring AI MCP(模型上下文协议)客户端启动启动器为 Spring Boot 应用程序中的 MCP 客户端功能提供了自动配置。它支持同步和异步客户端实现,并提供多种传输选项。

MCP 客户端启动启动器提供:

  • 管理多个客户端实例
  • 自动客户端初始化(如果启用)
  • 支持多种命名的传输方式(STDIO、Http/SSE 和 Streamable HTTP)
  • 与 Spring AI 的工具执行框架集成
  • 用于选择性包含/排除工具的工具过滤功能
  • 可自定义的工具名称前缀生成,以避免命名冲突
  • 适当的生命周期管理,在应用程序上下文关闭时自动清理资源
  • 通过定制器实现可自定义的客户端创建

启动器

标准 MCP 客户端

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

标准启动器通过 STDIO(进程内)、SSE、Streamable-HTTP 和 Stateless Streamable-HTTP 传输方式同时连接到一个或多个 MCP 服务器。SSE 和 Streamable-Http 传输使用基于 JDK HttpClient 的传输实现。每个到 MCP 服务器的连接都会创建一个新的 MCP 客户端实例。您可以选择 SYNC 或 ASYNC MCP 客户端(注意:您不能混合使用同步和异步客户端)。对于生产部署,我们建议使用基于 WebFlux 的 SSE 和 StreamableHttp 连接,配合 spring-ai-starter-mcp-client-webflux

WebFlux 客户端

WebFlux 启动器提供与标准启动器类似的功能,但使用基于 WebFlux 的 Streamable-Http、Stateless Streamable-Http 和 SSE 传输实现。

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

配置属性

通用属性

通用属性以 spring.ai.mcp.client 为前缀:

属性 描述 默认值
enabled 启用/禁用 MCP 客户端 true
name MCP 客户端实例的名称 spring-ai-mcp-client
version MCP 客户端实例的版本 1.0.0
initialized 是否在创建时初始化客户端 true
request-timeout MCP 客户端请求的超时时长 20s
type 客户端类型(SYNCASYNC)。所有客户端必须同为同步或异步;不支持混合使用 SYNC
root-change-notification 为所有客户端启用/禁用根变更通知 true
toolcallback.enabled 启用/禁用 MCP 工具回调与 Spring AI 工具执行框架的集成 true

MCP 注解属性

MCP 客户端注解提供了一种使用 Java 注解实现 MCP 客户端处理器的声明式方法。客户端 mcp-annotations 属性以 spring.ai.mcp.client.annotation-scanner 为前缀:

属性 描述 默认值
enabled 启用/禁用 MCP 客户端注解自动扫描 true

Stdio 传输属性

标准 I/O 传输的属性以 spring.ai.mcp.client.stdio 为前缀:

属性 描述 默认值
servers-configuration 包含 JSON 格式的 MCP 服务器配置的资源 -
connections 命名的 stdio 连接配置映射 -
connections.[name].command 要执行的 MCP 服务器命令 -
connections.[name].args 命令参数列表 -
connections.[name].env 服务器进程的环境变量映射 -

示例配置:

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        stdio:
          root-change-notification: true
          connections:
            server1:
              command: /path/to/server
              args:
                - --port=8080
                - --mode=production
              env:
                API_KEY: your-api-key
                DEBUG: "true"

或者,您可以使用外部 JSON 文件以 Claude Desktop 格式配置 stdio 连接:

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        stdio:
          servers-configuration: classpath:mcp-servers.json

Claude Desktop 格式如下所示:

json 复制代码
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/username/Desktop",
        "/Users/username/Downloads"
      ]
    }
  }
}

Windows STDIO 配置

在 Windows 上,像 npxnpmnode 这样的命令是以批处理文件(.cmd)形式实现的,而不是本机可执行文件。Java 的 ProcessBuilder 不能直接执行批处理文件,需要 cmd.exe /c 包装器。

为什么 Windows 需要特殊处理

当 Java 的 ProcessBuilder(由 StdioClientTransport 内部使用)尝试在 Windows 上生成进程时,它只能执行:

  • 本机可执行文件(.exe 文件)
  • cmd.exe 可用的系统命令

Windows 批处理文件,如 npx.cmdnpm.cmd,甚至 python.cmd(来自 Microsoft Store),都需要 cmd.exe shell 来执行它们。

解决方案:cmd.exe 包装器

使用 cmd.exe /c 包装批处理文件命令:

Windows 配置:

json 复制代码
{
  "mcpServers": {
    "filesystem": {
      "command": "cmd.exe",
      "args": [
        "/c",
        "npx",
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "C:\\Users\\username\\Desktop"
      ]
    }
  }
}

Linux/macOS 配置:

json 复制代码
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/username/Desktop"
      ]
    }
  }
}
跨平台编程配置

对于需要跨平台工作且无需单独配置文件的应用程序,请在 Spring Boot 应用程序中使用操作系统检测:

java 复制代码
@Bean(destroyMethod = "close")
@ConditionalOnMissingBean(McpSyncClient.class)
public McpSyncClient mcpClient() {
    ServerParameters stdioParams;

    if (isWindows()) {
        // Windows: cmd.exe /c npx 方式
        var winArgs = new ArrayList<>(Arrays.asList(
            "/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "target"));
        stdioParams = ServerParameters.builder("cmd.exe")
                .args(winArgs)
                .build();
    } else {
        // Linux/Mac: 直接 npx 方式
        stdioParams = ServerParameters.builder("npx")
                .args("-y", "@modelcontextprotocol/server-filesystem", "target")
                .build();
    }

    return McpClient.sync(new StdioClientTransport(stdioParams, McpJsonDefaults.getMapper()))
            .requestTimeout(Duration.ofSeconds(10))
            .build()
            .initialize();
}

private static boolean isWindows() {
    return System.getProperty("os.name").toLowerCase().contains("win");
}

当使用带有 @Bean 的编程配置时,请添加 @ConditionalOnMissingBean(McpSyncClient.class) 以避免与来自 JSON 文件的自动配置冲突。

路径注意事项

相对路径(推荐以实现可移植性):

json 复制代码
{
  "command": "cmd.exe",
  "args": ["/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "target"]
}

MCP 服务器根据应用程序的工作目录解析相对路径。

绝对路径(Windows 需要反斜杠或转义的正斜杠):

json 复制代码
{
  "command": "cmd.exe",
  "args": ["/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "C:\\Users\\username\\project\\target"]
}
需要 cmd.exe 的常见 Windows 批处理文件
  • npx.cmd, npm.cmd - Node 包管理器
  • python.cmd - Python(Microsoft Store 安装)
  • pip.cmd - Python 包管理器
  • mvn.cmd - Maven 包装器
  • gradle.cmd - Gradle 包装器
  • 自定义 .cmd.bat 脚本

参考实现

请参阅 Spring AI 示例 - 文件系统,了解完整的跨平台 MCP 客户端实现,该实现会自动检测操作系统并相应地配置客户端。

Streamable-HTTP 传输属性

用于连接 Streamable-HTTP 和 Stateless Streamable-HTTP MCP 服务器。

Streamable-HTTP 传输的属性以 spring.ai.mcp.client.streamable-http 为前缀:

属性 描述 默认值
connections 命名的 Streamable-HTTP 连接配置映射 -
connections.[name].url 与 MCP 服务器进行 Streamable-Http 通信的基础 URL 端点 -
connections.[name].endpoint 用于连接的 streamable-http 端点(作为 URL 后缀) /mcp

示例配置:

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            server1:
              url: http://localhost:8080
            server2:
              url: http://otherserver:8081
              endpoint: /custom-sse

SSE 传输属性

服务器发送事件(SSE)传输的属性以 spring.ai.mcp.client.sse 为前缀:

属性 描述 默认值
connections 命名的 SSE 连接配置映射 -
connections.[name].url 与 MCP 服务器进行 SSE 通信的基础 URL 端点 -
connections.[name].sse-endpoint 用于连接的 sse 端点(作为 URL 后缀) /sse

示例配置:

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        sse:
          connections:
            # 使用默认 /sse 端点的简单配置
            server1:
              url: http://localhost:8080
            # 自定义 SSE 端点
            server2:
              url: http://otherserver:8081
              sse-endpoint: /custom-sse
            # 带有路径和令牌的复杂 URL(如 MCP Hub)
            mcp-hub:
              url: http://localhost:3000
              sse-endpoint: /mcp-hub/sse/cf9ec4527e3c4a2cbb149a85ea45ab01
            # 带有查询参数的 SSE 端点
            api-server:
              url: https://api.example.com
              sse-endpoint: /v1/mcp/events?token=abc123&format=json
URL 拆分指南

当您有完整的 SSE URL 时,将其拆分为基础 URL 和端点路径:

完整 URL 配置
http://localhost:3000/mcp-hub/sse/token123 url: localhost:3000 sse-endpoint: /mcp-hub/sse/token123
https://api.service.com/v2/events?key=secret url: api.service.com sse-endpoint: /v2/events?key=secret
http://localhost:8080/sse url: localhost:8080 sse-endpoint: /sse(或省略以使用默认值)
SSE 连接故障排除

404 Not Found 错误:

  • 验证 URL 拆分:确保基础 url 仅包含方案、主机和端口
  • 检查 sse-endpoint 是否以 / 开头,并包含完整路径和查询参数
  • 直接在浏览器或 curl 中测试完整 URL,以确认其可访问性

Streamable Http 传输属性

Streamable Http 传输的属性以 spring.ai.mcp.client.streamable-http 为前缀:

属性 描述 默认值
connections 命名的 Streamable Http 连接配置映射 -
connections.[name].url 与 MCP 服务器进行 Streamable-Http 通信的基础 URL 端点 -
connections.[name].endpoint 用于连接的 streamable-http 端点(作为 URL 后缀) /mcp

示例配置:

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            server1:
              url: http://localhost:8080
            server2:
              url: http://otherserver:8081
              endpoint: /custom-sse

功能特性

同步/异步客户端类型

启动器支持两种客户端类型:

  • 同步 - 默认客户端类型(spring.ai.mcp.client.type=SYNC),适用于传统的请求-响应模式和阻塞操作

注意:SYNC 客户端将仅注册同步的 MCP 注解方法。异步方法将被忽略。

  • 异步 - 适用于响应式应用程序的非阻塞操作,通过 spring.ai.mcp.client.type=ASYNC 配置

注意:ASYNC 客户端将仅注册异步的 MCP 注解方法。同步方法将被忽略。

客户端定制

自动配置通过回调接口提供了广泛的客户端规范定制功能。这些定制器允许您配置 MCP 客户端行为的各个方面,从请求超时到事件处理和消息处理。

定制类型

以下定制选项可用:

  • 请求配置 - 设置自定义请求超时
  • 自定义采样处理器 - 服务器通过客户端从 LLM 请求 LLM 采样(补全或生成)的标准化方式。此流程允许客户端保持对模型访问、选择和权限的控制,同时使服务器能够利用 AI 功能 --- 无需服务器 API 密钥。
  • 文件系统(根目录)访问 - 客户端向服务器公开文件系统根目录的标准化方式。根目录定义了服务器可以在文件系统中操作的边界,使它们能够了解可以访问哪些目录和文件。服务器可以从支持的客户端请求根目录列表,并在该列表更改时接收通知。
  • 引导处理器 - 服务器在交互期间通过客户端向用户请求额外信息的标准化方式。
  • 事件处理器 - 当发生特定服务器事件时通知客户端的处理器:
    • 工具变更通知 - 当可用服务器工具列表发生变化时
    • 资源变更通知 - 当可用服务器资源列表发生变化时
    • 提示变更通知 - 当可用服务器提示列表发生变化时
  • 日志处理器 - 服务器向客户端发送结构化日志消息的标准化方式。
  • 进度处理器 - 服务器向客户端发送结构化进度消息的标准化方式。

客户端可以通过设置最低日志级别来控制日志详细程度。

客户端定制示例

您可以为同步客户端实现 McpCustomizer<McpClient.SyncSpec>,或为异步客户端实现 McpCustomizer<McpClient.AsyncSpec>,具体取决于您的应用程序需求。

同步 (Sync)

java 复制代码
@Component
public class CustomMcpSyncClientCustomizer implements McpClientCustomizer<McpClient.SyncSpec> {
    @Override
    public void customize(String serverConfigurationName, McpClient.SyncSpec spec) {

        // 自定义请求超时配置
        spec.requestTimeout(Duration.ofSeconds(30));

        // 设置此客户端可以访问的根 URI
        spec.roots(roots);

        // 设置用于处理消息创建请求的自定义采样处理器
        spec.sampling((CreateMessageRequest messageRequest) -> {
            // 处理采样
            CreateMessageResult result = ...
            return result;
        });

        // 设置用于处理引导请求的自定义引导处理器
        spec.elicitation((ElicitRequest request) -> {
          // 处理引导
          return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));
        });

        // 添加一个消费者,在收到进度通知时收到通知
        spec.progressConsumer((ProgressNotification progress) -> {
         // 处理进度通知
        });

        // 添加一个消费者,在可用工具发生变化时收到通知,例如添加或删除工具
        spec.toolsChangeConsumer((List<McpSchema.Tool> tools) -> {
            // 处理工具变更
        });

        // 添加一个消费者,在可用资源发生变化时收到通知,例如添加或删除资源
        spec.resourcesChangeConsumer((List<McpSchema.Resource> resources) -> {
            // 处理资源变更
        });

        // 添加一个消费者,在可用提示发生变化时收到通知,例如添加或删除提示
        spec.promptsChangeConsumer((List<McpSchema.Prompt> prompts) -> {
            // 处理提示变更
        });

        // 添加一个消费者,在从服务器收到日志消息时收到通知
        spec.loggingConsumer((McpSchema.LoggingMessageNotification log) -> {
            // 处理日志消息
        });
    }
}

serverConfigurationName 参数是定制器所应用到的服务器配置的名称,也是为其创建 MCP 客户端的名称。

MCP 客户端自动配置会自动检测并应用在应用程序上下文中找到的任何定制器。

传输支持

自动配置支持多种传输类型:

  • 标准 I/O (Stdio)(由 spring-ai-starter-mcp-clientspring-ai-starter-mcp-client-webflux 激活)
  • (HttpClient) HTTP/SSE 和 Streamable-HTTP(由 spring-ai-starter-mcp-client 激活)
  • (WebFlux) HTTP/SSE 和 Streamable-HTTP(由 spring-ai-starter-mcp-client-webflux 激活)

工具过滤

MCP 客户端启动启动器通过 McpToolFilter 接口支持对已发现工具的过滤。这允许您根据自定义条件(如 MCP 连接信息或工具属性)选择性地包含或排除工具。

要实现工具过滤,请创建一个实现 McpToolFilter 接口的 bean:

java 复制代码
@Component
public class CustomMcpToolFilter implements McpToolFilter {

    @Override
    public boolean test(McpConnectionInfo connectionInfo, McpSchema.Tool tool) {
        // 基于连接信息和工具属性的过滤逻辑
        // 返回 true 以包含该工具,返回 false 以排除它

        // 示例:排除来自特定客户端的工具
        if (connectionInfo.clientInfo().name().equals("restricted-client")) {
            return false;
        }

        // 示例:仅包含具有特定名称的工具
        if (tool.name().startsWith("allowed_")) {
            return true;
        }

        // 示例:根据工具描述或其他属性进行过滤
        if (tool.description() != null &&
            tool.description().contains("experimental")) {
            return false;
        }

        return true; // 默认包含所有其他工具
    }
}

McpConnectionInfo 记录提供对以下内容的访问:

  • clientCapabilities - MCP 客户端的能力
  • clientInfo - 关于 MCP 客户端的信息(名称和版本)
  • initializeResult - 来自 MCP 服务器的初始化结果

该过滤器会自动检测并应用于同步和异步 MCP 工具回调提供者。如果未提供自定义过滤器,则默认包含所有已发现的工具。

注意:应用程序上下文中只能定义一个 McpToolFilter bean。如果需要多个过滤器,请将它们组合成一个单一的复合过滤器实现。

工具名称前缀生成

MCP 客户端启动启动器通过 McpToolNamePrefixGenerator 接口支持可自定义的工具名称前缀生成。此功能有助于通过为来自多个 MCP 服务器的工具添加唯一前缀来避免命名冲突。

默认情况下,如果未提供自定义的 McpToolNamePrefixGenerator bean,启动器将使用 DefaultMcpToolNamePrefixGenerator,它确保所有 MCP 客户端连接中的工具名称唯一。默认生成器:

  • 跟踪所有现有连接和工具名称以确保唯一性
  • 通过将非字母数字字符替换为下划线来格式化工具名称(例如,my-tool 变为 my_tool
  • 当在不同连接中检测到重复的工具名称时,添加计数器前缀(例如,alt_1_toolName, alt_2_toolName
  • 是线程安全的,并保持幂等性 - (客户端、服务器、工具)的相同组合总是获得相同的唯一名称
  • 确保最终名称不超过 64 个字符(必要时从开头截断)

例如:

  • 第一次出现工具 searchsearch
  • 来自不同连接的第二次出现工具 searchalt_1_search
  • 带有特殊字符的工具 my-special-toolmy_special_tool

您可以通过提供自己的实现来自定义此行为:

java 复制代码
@Component
public class CustomToolNamePrefixGenerator implements McpToolNamePrefixGenerator {

    @Override
    public String prefixedToolName(McpConnectionInfo connectionInfo, Tool tool) {
        // 生成带前缀工具名称的自定义逻辑

        // 示例:使用服务器名称和版本作为前缀
        String serverName = connectionInfo.initializeResult().serverInfo().name();
        String serverVersion = connectionInfo.initializeResult().serverInfo().version();
        return serverName + "_v" + serverVersion.replace(".", "_") + "_" + tool.name();
    }
}

McpConnectionInfo 记录提供关于 MCP 连接的全面信息:

  • clientCapabilities - MCP 客户端的能力
  • clientInfo - 关于 MCP 客户端的信息(名称、标题和版本)
  • initializeResult - 来自 MCP 服务器的初始化结果,包括服务器信息
内置前缀生成器

该框架提供了几个内置前缀生成器:

  • DefaultMcpToolNamePrefixGenerator - 通过跟踪重复项并在需要时添加计数器前缀来确保工具名称唯一(如果未提供自定义 bean,则默认使用)
  • McpToolNamePrefixGenerator.noPrefix() - 返回不带任何前缀的工具名称(如果多个服务器提供同名工具,可能会导致冲突)

要完全禁用前缀并使用原始工具名称(如果使用多个 MCP 服务器,则不推荐),请将无前缀生成器注册为 bean:

java 复制代码
@Configuration
public class McpConfiguration {

    @Bean
    public McpToolNamePrefixGenerator mcpToolNamePrefixGenerator() {
        return McpToolNamePrefixGenerator.noPrefix();
    }
}

前缀生成器会自动检测并通过 Spring 的 ObjectProvider 机制应用于同步和异步 MCP 工具回调提供者。如果未提供自定义生成器 bean,则自动使用 DefaultMcpToolNamePrefixGenerator

当使用 McpToolNamePrefixGenerator.noPrefix() 配合多个 MCP 服务器时,重复的工具名称将导致 IllegalStateException。默认的 DefaultMcpToolNamePrefixGenerator 通过自动为重复工具名称添加唯一前缀来防止此问题。

工具上下文到 MCP 元数据转换器

MCP 客户端启动启动器通过 ToolContextToMcpMetaConverter 接口支持将 Spring AI 的 ToolContext 自定义转换为 MCP 工具调用元数据。此功能允许您将额外的上下文信息(例如用户 ID、密钥令牌)作为元数据与 LLM 生成的调用参数一起传递。

例如,您可以在工具上下文中传递 MCP progressToken 到您的 MCP 进度流程,以跟踪长时间运行操作的进度:

java 复制代码
ChatModel chatModel = ...

String response = ChatClient.create(chatModel)
        .prompt("Tell me more about the customer with ID 42")
        .toolContext(Map.of("progressToken", "my-progress-token"))
        .call()
        .content();

默认情况下,如果未提供自定义转换器 bean,启动器使用 ToolContextToMcpMetaConverter.defaultConverter(),它:

  • 过滤掉 MCP 交换键(McpToolUtils.TOOL_CONTEXT_MCP_EXCHANGE_KEY
  • 过滤掉值为空的条目
  • 将所有其他上下文条目作为元数据传递

您可以通过提供自己的实现来自定义此行为:

java 复制代码
@Component
public class CustomToolContextToMcpMetaConverter implements ToolContextToMcpMetaConverter {

    @Override
    public Map<String, Object> convert(ToolContext toolContext) {
        if (toolContext == null || toolContext.getContext() == null) {
            return Map.of();
        }

        // 将工具上下文转换为 MCP 元数据的自定义逻辑
        Map<String, Object> metadata = new HashMap<>();

        // 示例:为所有键添加自定义前缀
        for (Map.Entry<String, Object> entry : toolContext.getContext().entrySet()) {
            if (entry.getValue() != null) {
                metadata.put("app_" + entry.getKey(), entry.getValue());
            }
        }

        // 示例:添加额外的元数据
        metadata.put("timestamp", System.currentTimeMillis());
        metadata.put("source", "spring-ai");

        return metadata;
    }
}
内置转换器

该框架提供了内置转换器:

  • ToolContextToMcpMetaConverter.defaultConverter() - 过滤掉 MCP 交换键和空值(如果未提供自定义 bean,则默认使用)
  • ToolContextToMcpMetaConverter.noOp() - 返回空映射,有效地禁用上下文到元数据的转换

要完全禁用上下文到元数据的转换:

java 复制代码
@Configuration
public class McpConfiguration {

    @Bean
    public ToolContextToMcpMetaConverter toolContextToMcpMetaConverter() {
        return ToolContextToMcpMetaConverter.noOp();
    }
}

该转换器会自动检测并通过 Spring 的 ObjectProvider 机制应用于同步和异步 MCP 工具回调。如果未提供自定义转换器 bean,则自动使用默认转换器。

禁用 MCP ToolCallback 自动配置

MCP ToolCallback 自动配置默认启用,但可以通过 spring.ai.mcp.client.toolcallback.enabled=false 属性禁用。

禁用后,不会从可用的 MCP 工具创建 ToolCallbackProvider bean。

MCP 客户端注解

MCP 客户端启动启动器自动检测并注册用于处理各种 MCP 客户端操作的注解方法:

  • @McpLogging - 处理来自 MCP 服务器的日志消息通知
  • @McpSampling - 处理来自 MCP 服务器的 LLM 补全采样请求
  • @McpElicitation - 处理从用户收集额外信息的引导请求
  • @McpProgress - 处理长时间运行操作的进度通知
  • @McpToolListChanged - 处理服务器工具列表变更时的通知
  • @McpResourceListChanged - 处理服务器资源列表变更时的通知
  • @McpPromptListChanged - 处理服务器提示列表变更时的通知

使用示例:

java 复制代码
@Component
public class McpClientHandlers {

    @McpLogging(clients = "server1")
    public void handleLoggingMessage(LoggingMessageNotification notification) {
        System.out.println("Received log: " + notification.level() +
                          " - " + notification.data());
    }

    @McpSampling(clients = "server1")
    public CreateMessageResult handleSamplingRequest(CreateMessageRequest request) {
        // 处理请求并生成响应
        String response = generateLLMResponse(request);

        return CreateMessageResult.builder(Role.ASSISTANT, response, "gpt-4")
            .build();
    }

    @McpProgress(clients = "server1")
    public void handleProgressNotification(ProgressNotification notification) {
        double percentage = notification.progress() * 100;
        System.out.println(String.format("Progress: %.2f%% - %s",
            percentage, notification.message()));
    }

    @McpToolListChanged(clients = "server1")
    public void handleToolListChanged(List<McpSchema.Tool> updatedTools) {
        System.out.println("Tool list updated: " + updatedTools.size() + " tools available");
        // 更新本地工具注册表
        toolRegistry.updateTools(updatedTools);
    }
}

注解支持同步和异步实现,并且可以使用 clients 参数为特定客户端进行配置:

java 复制代码
@McpLogging(clients = "server1")
public void handleServer1Logs(LoggingMessageNotification notification) {
    // 处理来自特定服务器的日志
    logToFile("server1.log", notification);
}

@McpSampling(clients = "server1")
public Mono<CreateMessageResult> handleAsyncSampling(CreateMessageRequest request) {
    return Mono.fromCallable(() -> {
        String response = generateLLMResponse(request);
        return CreateMessageResult.builder(Role.ASSISTANT, response, "gpt-4")
            .build();
    }).subscribeOn(Schedulers.boundedElastic());
}

有关所有可用注解及其使用模式的详细信息,请参阅 MCP 客户端注解文档。

使用示例

将适当的启动器依赖项添加到您的项目,并在 application.propertiesapplication.yml 中配置客户端:

yaml 复制代码
spring:
  ai:
    mcp:
      client:
        enabled: true
        name: my-mcp-client
        version: 1.0.0
        request-timeout: 30s
        type: SYNC  # 或 ASYNC 用于响应式应用程序
        sse:
          connections:
            server1:
              url: http://localhost:8080
            server2:
              url: http://otherserver:8081
        streamable-http:
          connections:
            server3:
              url: http://localhost:8083
              endpoint: /mcp
        stdio:
          root-change-notification: false
          connections:
            server1:
              command: /path/to/server
              args:
                - --port=8080
                - --mode=production
              env:
                API_KEY: your-api-key
                DEBUG: "true"

MCP 客户端 bean 将自动配置并可供注入:

java 复制代码
@Autowired
private List<McpSyncClient> mcpSyncClients;  // 用于同步客户端

// 或者

@Autowired
private List<McpAsyncClient> mcpAsyncClients;  // 用于异步客户端

当启用工具回调时(默认行为),所有 MCP 客户端注册的 MCP 工具将作为 ToolCallbackProvider 实例提供:

java 复制代码
@Autowired
private SyncMcpToolCallbackProvider toolCallbackProvider;
ToolCallback[] toolCallbacks = toolCallbackProvider.getToolCallbacks();

示例应用程序

  • Brave Web Search Chatbot - 一个使用模型上下文协议与网络搜索服务器交互的聊天机器人。
  • 默认 MCP 客户端启动器 - 一个使用默认 spring-ai-starter-mcp-client MCP 客户端启动启动器的简单示例。
  • WebFlux MCP 客户端启动器 - 一个使用 spring-ai-starter-mcp-client-webflux MCP 客户端启动启动器的简单示例。

其他资源

  • Spring AI 文档
  • 模型上下文协议规范
  • Spring Boot 自动配置