Spring AI MCP学习目录
一、MCP 原理详解
二、MCP 客户端
三、MCP 客户端
四、MCP 服务端
五、SpringAI MCP 服务端
六、SpringAI MCP 服务端 STDIO & SSE
七、SpringAI MCP 服务端 Streamable-HTTP
八、SpringAI MCP 服务端 Stateless Streamable-HTTP
九、 MCP 安全(Security)
十、SpringAI MCP 安全(Security)
十一、SpringAI MCP 客户端注解
十二、SpringAI MCP 服务端注解
十三、SpringAI MCP 特殊参数(Special Parameters)


一、简介

Spring AI MCP(模型上下文协议)客户端启动器为Spring Boot应用提供MCP客户端的自动配置,支持同步/异步客户端实现及多种传输协议。

核心功能包括:

  • 多客户端实例管理
  • 自动初始化(可选)
  • 支持STDIO/Http/SSE/Streamable HTTP传输
  • 与Spring AI工具执行框架集成
  • 工具过滤(按需启用/禁用)
  • 可自定义工具名前缀(避免冲突)
  • 应用关闭时自动清理资源
  • 通过自定义器配置客户端创建

MCP 客户端应支持:

功能 说明
✅ 构造 MCP 请求 在标准 LLM 请求基础上,添加 context 字段(含 tools/retrieval/images 等)
✅ 自动序列化/反序列化 将工具函数、检索配置转为 MCP JSON Schema
✅ 处理 Tool Call 响应 解析模型返回的 tool_calls,执行本地函数并回传结果
✅ 降级兼容 当后端不支持 MCP 时,自动转为传统 prompt 拼接模式
✅ 与主流框架集成 如 LangChain、LlamaIndex、Spring AI

MCP 客户端工作流程

应用代码 MCP 客户端 支持 MCP 的 AI 服务 本地工具 调用 generate("查北京天气", tools=[get_weather]) 构建 MCP 请求(含 context.tools) POST /chat/completions (MCP 格式) 返回 { "tool_calls": [{ "name": "get_weather", "args": {"city":"北京"} }] } 自动调用 get_weather("北京") 返回 {"temp": 25, "condition": "晴"} 发送第二轮请求(附工具结果) 返回最终答案:“北京今天晴,25°C” 返回自然语言结果 应用代码 MCP 客户端 支持 MCP 的 AI 服务 本地工具

二、启动器

Standard MCP Client

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

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

WebFlux Client

WebFlux启动器与标准启动器功能类似,但采用基于WebFlux的Streamable-HTTP、无状态Streamable-HTTP和SSE传输实现‌。

<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 客户端类型(SYNC或ASYNC)。所有客户端必须同为同步或异步,不支持混合 SYNC
root-change-notification 为所有客户端启用/禁用根变更通知 true
toolcallback.enabled 启用/禁用MCP工具回调与Spring AI工具执行框架的集成 true

注解

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

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

Stdio

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

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

样例:

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"

Streamable-HTTP

用于连接 Streamable-HTTP 和无状态 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

样例:

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

样例:

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

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
样例:
spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            server1:
              url: http://localhost:8080
            server2:
              url: http://otherserver:8081
              endpoint: /custom-sse

四、特性

1、同步/异步

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

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

  • 异步客户端‌ - 适用于采用非阻塞操作的响应式应用,通过配置 spring.ai.mcp.client.type=ASYNC 启用

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

2、客户自定义

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

提供以下定制选项:

  • 请求配置‌:设置自定义请求超时
  • 自定义采样处理器‌:服务器通过客户端向LLM请求采样(补全或生成)的标准化方式。该流程允许客户端保持对模型访问、选择和权限的控制,同时使服务器能够利用AI能力——无需服务器API密钥
  • 文件系统(根目录)访问‌:客户端向服务器暴露文件系统根目录的标准化方式。根目录定义了服务器在文件系统中可操作的范围边界,使其了解可以访问哪些目录和文件。服务器可以从支持客户端请求根目录列表,并在该列表发生变化时接收通知
  • 信息征询处理器‌:服务器在交互过程中通过客户端向用户请求额外信息的标准化方式
  • 事件处理器‌:当特定服务器事件发生时通知客户端的处理器:
    • 工具变更通知 - 当可用服务器工具列表发生变化时
    • 资源变更通知 - 当可用服务器资源列表发生变化时
    • 提示词变更通知 - 当可用服务器提示词列表发生变化时
  • 日志处理器‌:服务器向客户端发送结构化日志消息的标准化方式
  • 进度处理器‌:服务器向客户端发送结构化进度消息的标准化方式
    客户端可通过设置最低日志级别来控制日志详细程度
    样例:
@Component
public class CustomMcpAsyncClientCustomizer implements McpAsyncClientCustomizer {
    @Override
    public void customize(String serverConfigurationName, McpClient.AsyncSpec spec) {
        // Customize the async client configuration
        spec.requestTimeout(Duration.ofSeconds(30));
    }
}

3、传输协议

自动配置支持以下传输类型:

  • 标准I/O(Stdio)‌:通过spring-ai-starter-mcp-client和spring-ai-starter-mcp-client-webflux激活,适用于进程内通信‌。
  • HTTP/SSE与Streamable-HTTP‌:
    • 基于HttpClient的实现(spring-ai-starter-mcp-client)‌。
    • 基于WebFlux的实现(spring-ai-starter-mcp-client-webflux),适用于响应式高并发场景‌。

注:SSE(服务器发送事件)和Streamable-HTTP均为流式传输协议,后者为前者的演进版本‌。

4、Tool Filtering

MCP客户端启动器通过McpToolFilter接口支持对发现工具进行过滤,可以根据MCP连接信息或工具属性等自定义条件选择性包含或排除工具。

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

@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。如需多个过滤器,请将其组合到单个复合过滤器实现中。

5、Tool Name Prefix Generation

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

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

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

例如:

  • 首次出现的search工具 → search
  • 来自不同连接的第二个search工具 → alt_1_search
  • 包含特殊字符的工具my-special-tool → my_special_tool

样例:

@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();
    }
}

6、MCP Meta 转换

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

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

Copy Code
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)
  • 过滤掉值为null的条目
  • 将所有其他上下文条目作为元数据透传

五、MCP客户端注解

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

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

样例:

@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(Role.ASSISTANT)
            .content(new TextContent(response))
            .model("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);
    }
}

六、样例

样例代码:https://gitee.com/mqiqe/zixiai
调用天气mcp的样例:

Maven配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.zixi.ai</groupId>
        <artifactId>zixi-ai-eaxmple</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <groupId>com.zixi.ai.eaxmple.mcp.weather.client</groupId>
    <artifactId>mcp-weather-client</artifactId>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

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

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

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-ollama</artifactId>
        </dependency>
    </dependencies>
</project>

相关代码:

package com.zixi.ai.eaxmple.mcp.weather.client;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;

@SpringBootApplication(exclude = {
		org.springframework.ai.mcp.client.autoconfigure.SseHttpClientTransportAutoConfiguration.class
})
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

	// 直接硬编码中文问题,避免配置文件编码问题
	// @Value("${ai.user.input}")
	// private String userInput;
	private String userInput1 = "青岛天气如何?";

	private String userInput2 = "将字符串:Wfg heloa,wfgxif 转为大写";

	@Bean
	public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, ToolCallbackProvider tools,
			ConfigurableApplicationContext context) {

		return args -> {

			var chatClient = chatClientBuilder
					.defaultToolCallbacks(tools)
					.build();

			System.out.println("\n>>> QUESTION: " + userInput1);
			System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(userInput1).call().content());

			System.out.println("\n>>> QUESTION: " + userInput2);
			System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(userInput2).call().content());

			context.close();
		};
	}
}

配置文件

server:
  port: 8888
  servlet:
    encoding:
      charset: UTF-8
      enabled: true
      force: true

spring:
  application:
    name: mcp
  main:
    web-application-type: none
  ai:
    ollama:
      base-url: http://localhost:11434
      chat:
#          model: qwen3:0.6b
          enabled: true
          options:
            model: qwen3:0.6b
            temperature: 0.7
    mcp:
      client:
        sse:
          connections:
            server1:
              # 实际的连接地址为:http://localhost:8080/sse/mcp
              url: http://localhost:8080/
  mandatory-file-encoding: UTF-8

# 调试日志
logging:
  level:
    io:
      modelcontextprotocol:
        client: DEBUG
        spec: DEBUG

ai:
  user:
    input: 北京的天气如何?

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐