Skip to content
Spring AI 文档版本 2.1.0-SNAPSHOT 源快照 9d15870f 更新于 2026-10-16

MCP 客户端 Boot Starter

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

MCP 客户端 Boot Starter 提供:

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

Starters

标准 MCP 客户端

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

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

WebFlux 客户端

WebFlux starter 提供与标准 starter 类似的功能,但使用基于 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
nameMCP 客户端实例的名称spring-ai-mcp-client
versionMCP 客户端实例的版本1.0.0
initialized是否在创建时初始化客户端true
request-timeoutMCP 客户端请求的超时时长20s
type客户端类型(SYNC 或 ASYNC)。所有客户端必须全为同步或全为异步;不支持混用SYNC
root-change-notification为所有客户端启用/禁用 root 变更通知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"

或者,你可以使用Claude Desktop 格式通过一个外部 JSON 文件来配置 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 配置

WARNING

在 Windows 上,像 npx、npm 和 node 这样的命令是以批处理文件(.cmd)实现的,而非本地可执行文件。Java 的 ProcessBuilder 不能直接执行批处理文件,需要 cmd.exe /c 包装。

为何 Windows 需要特殊处理

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

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

像 npx.cmd、npm.cmd,乃至 python.cmd(来自 Microsoft Store)这样的 Windows 批处理文件,需要 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 approach
        var winArgs = new ArrayList<>(Arrays.asList(
            "/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "target"));
        stdioParams = ServerParameters.builder("cmd.exe")
                .args(winArgs)
                .build();
    } else {
        // Linux/Mac: direct npx approach
        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");
}

NOTE

使用带 @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 脚本

参考实现

关于一个完整的、会自动检测操作系统并恰当配置客户端的跨平台 MCP 客户端实现,参见 Spring AI Examples - Filesystem。

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:
            # Simple configuration using default /sse endpoint
            server1:
              url: http://localhost:8080
            # Custom SSE endpoint
            server2:
              url: http://otherserver:8081
              sse-endpoint: /custom-sse
            # Complex URL with path and token (like MCP Hub)
            mcp-hub:
              url: http://localhost:3000
              sse-endpoint: /mcp-hub/sse/cf9ec4527e3c4a2cbb149a85ea45ab01
            # SSE endpoint with query parameters
            api-server:
              url: https://api.example.com
              sse-endpoint: /v1/mcp/events?token=abc123&format=json

URL 拆分指南

当你有一个完整的 SSE URL 时,把它拆分为基础 URL 和端点路径:

Full URLConfiguration
\http://localhost:3000/mcp-hub/sse/token123url: http://localhost:3000 + sse-endpoint: /mcp-hub/sse/token123
\https://api.service.com/v2/events?key=secreturl: https://api.service.com + sse-endpoint: /v2/events?key=secret
\http://localhost:8080/sseurl: http://localhost:8080 + sse-endpoint: /sse (or omit for default)

排查 SSE 连接

404 Not Found 错误:

  • 校验 URL 拆分:确保基础 url 只含 scheme、host 和 port
  • 检查 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

特性

同步/异步客户端类型

该 starter 支持两种类型的客户端:

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

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

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

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

客户端作用域与会话边界

自动配置的 McpSyncClient 和 McpAsyncClient bean 是应用作用域的单例。 每个已配置的 MCP 服务端连接会创建一个客户端 bean,且该 bean 被应用所服务的每个请求共享。

每个客户端代表一个 MCP 协议会话。 该会话在其整个生命周期内附着于客户端 bean,仅当服务端终止它(HTTP 404)或客户端被关闭时才更换。

DANGER

MCP 会话不是按用户的边界。 通过 transportContextProvider(...)、McpSyncHttpClientRequestCustomizer 或 WebClient 的 ExchangeFilterFunction 传播的逐请求凭据,会逐请求应用并确实带着调用者的身份抵达服务端。 而其之下的 MCP 协议会话仍被该客户端 bean 的所有调用者共享。 多用户应用应当考虑以下几点:

  • initialize 与 tools/list 交换只发生一次,是在客户端连接时可用的任何身份之下进行,而非在后来调用工具的某个用户身份之下。
  • 任何仅以 MCP 会话为键的服务端状态,会被该客户端 bean 的所有用户共享。
  • 由服务端发起的交互(如 sampling 和 elicitation)到达一个共享流上,且不携带任何按用户的归属。 连接的任一侧都不要把 MCP 会话当作某个用户或租户的边界。

这是否要紧取决于你连接的 MCP 服务端。对无状态服务端,共享客户端没问题;对那种每次都依据所提供令牌授权、且不在会话上保留任何有用户意义状态、并且是有状态的服务端,也没问题。在以下情形请考虑为每个用户或每个租户使用独立会话:

  • 服务端会依据身份过滤 tools/list、资源或提示词——因为发现只运行一次,此后所有用户看到的都是首个调用者的视图。
  • 服务端在会话上保留有用户意义状态,例如工作目录、订阅、分页游标或缓存上下文。
  • 你使用 sampling 或 elicitation,并需要那些服务端发起的请求归属到特定用户。
  • 服务端按会话做审计或限速,或你的部署要求各租户不共享协议会话。
  • 你无法核实一个第三方服务端如何对待它的会话。

需要为每个用户或每个租户使用独立 MCP 协议会话的应用,必须自己管理该生命周期,为每个主体创建一个传输和客户端,并在该主体的工作完成时关闭它。 自动配置的 bean 不适合此,且 Spring AI 不提供按用户的客户端池化。 关于以编程方式构造客户端,参见 绕过 Spring AI 自动配置。

客户端定制

自动配置通过回调接口提供丰富的客户端规格定制能力。这些定制器让你能配置 MCP 客户端行为的方方面面,从请求超时到事件处理与消息处理。

定制类型

可用的定制选项如下:

  • 请求配置 - 设置自定义请求超时
  • 自定义 Sampling 处理器 - 一种标准化方式,让服务端通过客户端向 LLM 请求 LLM 采样(completions 或 generations)。这一流程让客户端在使服务端得以利用 AI 能力——无需服务端 API 密钥——的同时,保持对模型访问、选择与权限的控制。
  • 文件系统(Roots)访问 - 一种标准化方式,让客户端向服务端暴露文件系统 roots。 Roots 界定服务端能在文件系统内操作的范围,让它们了解自己有权限访问哪些目录和文件。 服务端可以从支持的客户端请求 roots 列表,并在该列表变化时收到通知。
  • Elicitation 处理器 - 一种标准化方式,让服务端在交互期间通过客户端向用户请求额外信息。
  • 事件处理器 - 客户端的处理器,在某个服务端事件发生时收到通知:
  • 工具变更通知 - 当服务端可用工具列表变化时
  • 资源变更通知 - 当服务端可用资源列表变化时。
  • 提示词变更通知 - 当服务端可用提示词列表变化时。
  • 日志处理器 - 一种标准化方式,让服务端向客户端发送结构化日志消息。
  • 进度处理器 - 一种标准化方式,让服务端向客户端发送结构化进度消息。

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

客户端定制示例

视你应用的需要,你可以为同步客户端实现 McpCustomizer<McpClient.SyncSpec>,或为异步客户端实现 McpCustomizer<McpClient.AsyncSpec>。

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

        // Customize the request timeout configuration
        spec.requestTimeout(Duration.ofSeconds(30));

        // Sets the root URIs that this client can access.
        spec.roots(roots);

        // Sets a custom sampling handler for processing message creation requests.
        spec.sampling((CreateMessageRequest messageRequest) -> {
            // Handle sampling
            CreateMessageResult result = ...
            return result;
        });

        // Sets a custom elicitation handler for processing elicitation requests.
        spec.elicitation((ElicitRequest request) -> {
          // handle elicitation
          return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));
        });

        // Adds a consumer to be notified when progress notifications are received.
        spec.progressConsumer((ProgressNotification progress) -> {
         // Handle progress notifications
        });

        // Adds a consumer to be notified when the available tools change, such as tools
        // being added or removed.
        spec.toolsChangeConsumer((List<McpSchema.Tool> tools) -> {
            // Handle tools change
        });

        // Adds a consumer to be notified when the available resources change, such as resources
        // being added or removed.
        spec.resourcesChangeConsumer((List<McpSchema.Resource> resources) -> {
            // Handle resources change
        });

        // Adds a consumer to be notified when the available prompts change, such as prompts
        // being added or removed.
        spec.promptsChangeConsumer((List<McpSchema.Prompt> prompts) -> {
            // Handle prompts change
        });

        // Adds a consumer to be notified when logging messages are received from the server.
        spec.loggingConsumer((McpSchema.LoggingMessageNotification log) -> {
            // Handle log messages
        });
    }
}

serverConfigurationName 参数是该定制器正被应用到的、且为之创建了 MCP 客户端的那个服务端配置的名称。

MCP 客户端自动配置会自动检测并应用应用上下文中发现的任何定制器。

传输支持

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

  • 标准 I/O(Stdio)(由 spring-ai-starter-mcp-client 和 spring-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 客户端 Boot Starter 支持通过 McpToolFilter 接口过滤所发现的工具。这让你能依据自定义标准(如 MCP 连接信息或工具属性)选择性地纳入或排除工具。

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

java
@Component
public class CustomMcpToolFilter implements McpToolFilter {

    @Override
    public boolean test(McpConnectionInfo connectionInfo, McpSchema.Tool tool) {
        // Filter logic based on connection information and tool properties
        // Return true to include the tool, false to exclude it

        // Example: Exclude tools from a specific client
        if (connectionInfo.clientInfo().name().equals("restricted-client")) {
            return false;
        }

        // Example: Only include tools with specific names
        if (tool.name().startsWith("allowed_")) {
            return true;
        }

        // Example: Filter based on tool description or other properties
        if (tool.description() != null &&
            tool.description().contains("experimental")) {
            return false;
        }

        return true; // Include all other tools by default
    }
}

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

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

该过滤器会被自动检测并应用到同步和异步的 MCP 工具回调提供者。 若未提供自定义过滤器,默认纳入所有发现到的工具。

注意:应用上下文中应只定义一个 McpToolFilter bean。 若需要多个过滤器,把它们组合成一个单一的复合过滤器实现。

工具名前缀生成

MCP 客户端 Boot Starter 支持通过 McpToolNamePrefixGenerator 接口进行可定制的工具名前缀生成。这一特性通过给工具名添加唯一前缀,帮助你在集成来自多个 MCP 服务端的工具时避免命名冲突。

默认情况下,若未提供自定义 McpToolNamePrefixGenerator bean,starter 会使用 DefaultMcpToolNamePrefixGenerator,它确保所有 MCP 客户端连接间工具名唯一。该默认生成器:

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

例如:

  • 工具 search 的首次出现 → search
  • 来自另一连接的工具 search 的第二次出现 → alt_1_search
  • 带特殊字符的工具 my-special-tool → my_special_tool

你可以通过提供你自己的实现来定制这一行为:

java
@Component
public class CustomToolNamePrefixGenerator implements McpToolNamePrefixGenerator {

    @Override
    public String prefixedToolName(McpConnectionInfo connectionInfo, Tool tool) {
        // Custom logic to generate prefixed tool names

        // Example: Use server name and version as prefix
        String serverName = connectionInfo.initializeResult().serverInfo().name();
        String serverVersion = connectionInfo.initializeResult().serverInfo().version();
        return serverName + "_v" + serverVersion.replace(".", "_") + "_" + tool.name();
    }
}

McpConnectionInfo record 提供关于 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。

DANGER

当把 McpToolNamePrefixGenerator.noPrefix() 与多个 MCP 服务端一起使用时,重复工具名会导致 IllegalStateException。默认的 DefaultMcpToolNamePrefixGenerator 通过自动给重复工具名添加唯一前缀来避免这一点。

NOTE

该生成器只在 MCP 连接之间对名称去重;它看不到本地 @Tool 方法。

关于本地/远端冲突情形以及哪些调用路径真的会防范它,参见组合本地与 MCP 工具。

工具上下文到 MCP Meta 转换器

MCP 客户端 Boot Starter 支持通过 ToolContextToMcpMetaConverter 接口,把 Spring AI 的 工具上下文 可定制地转换为 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,starter 会使用 ToolContextToMcpMetaConverter.defaultConverter(),它会:

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

你可以通过提供你自己的实现来定制这一行为:

java
@Component
public class CustomToolContextToMcpMetaConverter implements ToolContextToMcpMetaConverter {

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

        // Custom logic to convert tool context to MCP metadata
        Map<String, Object> metadata = new HashMap<>();

        // Example: Add custom prefix to all keys
        for (Map.Entry<String, Object> entry : toolContext.getContext().entrySet()) {
            if (entry.getValue() != null) {
                metadata.put("app_" + entry.getKey(), entry.getValue());
            }
        }

        // Example: Add additional metadata
        metadata.put("timestamp", System.currentTimeMillis());
        metadata.put("source", "spring-ai");

        return metadata;
    }
}

内建转换器

框架提供内建转换器:

  • ToolContextToMcpMetaConverter.defaultConverter() - 过滤掉 MCP 交换键和 null 值(若未提供自定义 bean 则默认使用)
  • ToolContextToMcpMetaConverter.noOp() - 返回一个空 map,实际上禁用上下文到元数据的转换

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

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 客户端 Boot Starter 会自动检测并注册带注解的方法,以处理各种 MCP 客户端操作:

  • @McpLogging - 处理来自 MCP 服务端的日志消息通知
  • @McpSampling - 处理来自 MCP 服务端对 LLM 补全的 sampling 请求
  • @McpElicitation - 处理用于向用户收集额外信息的 elicitation 请求
  • @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) {
        // Process the request and generate a response
        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");
        // Update local tool registry
        toolRegistry.updateTools(updatedTools);
    }
}

这些注解支持同步与异步两种实现,并可用 clients 参数为特定客户端配置:

java
@McpLogging(clients = "server1")
public void handleServer1Logs(LoggingMessageNotification notification) {
    // Handle logs from specific server
    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 客户端注解文档。

用法示例

把合适的 starter 依赖添加到你的项目,并在 application.properties 或 application.yml 中配置客户端:

yaml
spring:
  ai:
    mcp:
      client:
        enabled: true
        name: my-mcp-client
        version: 1.0.0
        request-timeout: 30s
        type: SYNC  # or ASYNC for reactive applications
        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;  // For sync client

// OR

@Autowired
private List<McpAsyncClient> mcpAsyncClients;  // For async client

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

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

示例应用

其他资源

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。