1. 概述
Spring AI 提供的模型上下文协议(MCP)客户端 Spring Boot 启动器 ,可为 Spring Boot 应用自动配置 MCP 客户端能力。该组件同时支持同步、异步客户端实现,并兼容多种通信传输方式。
本启动器具备以下能力:
- 支持管理多个客户端实例
- 可配置客户端自动初始化
- 兼容多种命名传输方式:标准输入输出(
STDIO)、HTTP/SSE、流式 HTTP - 无缝集成
Spring AI工具调用框架 - 提供工具过滤能力,可按需启用/屏蔽指定工具
- 支持自定义工具名称前缀生成,避免命名冲突
- 完善的生命周期管理:应用上下文关闭时自动释放资源
- 支持通过自定义扩展器定制客户端创建逻辑
2. 启动器依赖
2.1 标准 MCP 客户端
标准启动器可通过进程内 STDIO、SSE、流式 HTTP、无状态流式 HTTP 多种方式,同时连接一个或多个 MCP 服务端。其中 SSE 与流式 HTTP 基于 JDK 原生 HttpClient 实现。
每一条 MCP 服务端连接都会创建独立客户端实例,可选择同步 (SYNC)或异步 (ASYNC)模式(两种模式不可混用)。
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
生产环境推荐搭配 spring-ai-starter-mcp-client-webflux,使用基于 WebFlux 的 SSE/流式 HTTP 连接。
2.2 WebFlux 客户端
功能与标准启动器一致,但底层基于 WebFlux 实现流式 HTTP、无状态流式 HTTP 及 SSE传输。
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
</dependency>
3. 配置项说明
3.1 通用配置
配置前缀:spring.ai.mcp.client
| 配置项 | 说明 | 默认值 |
|---|---|---|
| enabled | 开启/关闭 MCP 客户端 | true |
| name | MCP 客户端实例名称 | spring-ai-mcp-client |
| version | MCP 客户端版本 | 1.0.0 |
| initialized | 创建客户端时是否自动初始化 | true |
| request-timeout | 客户端请求超时时间 | 20s |
| type | 客户端类型:SYNC(同步) / ASYNC(异步),全局只能选一种 | SYNC |
| root-change-notification | 开启/关闭所有客户端的根路径变更通知 | true |
| toolcallback.enabled | 开启/关闭 MCP 工具回调与 Spring AI 工具框架的集成 | true |
3.2 MCP 注解配置
配置前缀:spring.ai.mcp.client.annotation-scanner
| 配置项 | 说明 | 默认值 |
|---|---|---|
| enabled | 开启/关闭 MCP 客户端注解自动扫描 | true |
3.3 标准输入输出(STDIO)传输配置
配置前缀:spring.ai.mcp.client.stdio
| 配置项 | 说明 | 默认值 |
|---|---|---|
| servers-configuration | JSON 格式的 MCP 服务端配置文件地址 | 无 |
| connections | 命名式 STDIO 连接配置集合 | 无 |
| connections.name.command | 启动 MCP 服务端的执行命令 | 无 |
| connections.name.args | 命令行参数列表 | 无 |
| connections.name.env | 服务端进程环境变量 | 无 |
配置示例(YAML):
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 格式):
yaml
spring:
ai:
mcp:
client:
stdio:
servers-configuration: classpath:mcp-servers.json
mcp-servers.json 示例:
json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/username/Desktop",
"/Users/username/Downloads"
]
}
}
}
3.3.1 Windows 平台特殊适配
Windows 系统中,npx、npm、node、python 等均为批处理文件(.cmd),Java 的 ProcessBuilder 无法直接执行批处理 ,必须通过 cmd.exe /c 包裹命令。
Windows 配置示例(JSON):
json
{
"mcpServers": {
"filesystem": {
"command": "cmd.exe",
"args": [
"/c",
"npx",
"-y",
"@modelcontextprotocol/server-filesystem",
"C:\\Users\\username\\Desktop"
]
}
}
}
Linux / macOS 配置示例(JSON):
json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/username/Desktop"
]
}
}
}
跨平台代码式配置:
通过代码判断操作系统,实现一套配置兼容全平台,同时添加 @ConditionalOnMissingBean 避免与配置文件自动配置冲突:
java
@Bean(destroyMethod = "close")
@ConditionalOnMissingBean(McpSyncClient.class)
public McpSyncClient mcpClient() {
ServerParameters stdioParams;
if (isWindows()) {
// Windows 系统:使用 cmd.exe 包装命令
var winArgs = new ArrayList<>(Arrays.asList(
"/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "target"));
stdioParams = ServerParameters.builder("cmd.exe")
.args(winArgs)
.build();
} else {
// Linux / Mac 系统:直接执行命令
stdioParams = ServerParameters.builder("npx")
.args("-y", "@modelcontextprotocol/server-filesystem", "target")
.build();
}
return McpClient.sync(new StdioClientTransport(stdioParams, McpJsonMapper.createDefault()))
.requestTimeout(Duration.ofSeconds(10))
.build()
.initialize();
}
// 判断当前系统是否为 Windows
private static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("win");
}
路径使用说明:
- 相对路径(推荐,可移植性强):基于应用运行目录解析
- 绝对路径 (Windows):使用反斜杠
\或转义正斜杠/
Windows 下需要 cmd.exe 包裹的常用批处理:
npx.cmd、npm.cmd、python.cmd、pip.cmd、mvn.cmd、gradle.cmd 及自定义 .cmd/.bat 脚本。
3.4 流式 HTTP(Streamable-HTTP)传输配置
配置前缀:spring.ai.mcp.client.streamable-http
| 配置项 | 说明 | 默认值 |
|---|---|---|
| connections | 命名式流式 HTTP 连接配置集合 | 无 |
| connections.name.url | MCP 服务端基础地址 | 无 |
| connections.name.endpoint | 接口后缀路径 | /mcp |
配置示例:
yaml
spring:
ai:
mcp:
client:
streamable-http:
connections:
server1:
url: http://localhost:8080
server2:
url: http://otherserver:8081
endpoint: /custom-sse
3.5 SSE(服务端推送事件)传输配置
配置前缀:spring.ai.mcp.client.sse
| 配置项 | 说明 | 默认值 |
|---|---|---|
| connections | 命名式 SSE 连接配置集合 | 无 |
| connections.name.url | MCP 服务端基础地址 | 无 |
| connections.name.sse-endpoint | SSE 接口后缀路径 | /sse |
配置示例:
yaml
spring:
ai:
mcp:
client:
sse:
connections:
server1:
url: http://localhost:8080
server2:
url: http://otherserver:8081
sse-endpoint: /custom-sse
URL 拆分规则:
完整 SSE 地址需拆分为 基础URL + 接口后缀:
| 完整地址 | 基础 url | sse-endpoint 后缀 |
|---|---|---|
| http://localhost:3000/mcp-hub/sse/token123 | localhost:3000 | /mcp-hub/sse/token123 |
| https://api.service.com/v2/events?key=secret | api.service.com | /v2/events?key=secret |
| http://localhost:8080/sse | localhost:8080 | /sse(可省略) |
SSE 连接排错(404 错误):
- 拆分地址时,基础 URL 仅保留协议、域名、端口
- 接口后缀必须以
/开头,包含完整路径与请求参数 - 先通过浏览器或 curl 直接访问完整地址,验证接口可用性
4. 核心功能详解
4.1 同步/异步客户端
- 同步客户端(默认 SYNC):适用于传统阻塞式请求响应场景,仅注册同步类型 MCP 注解方法,异步方法会被忽略。
- 异步客户端(ASYNC):适用于响应式非阻塞应用,仅注册异步类型 MCP 注解方法,同步方法会被忽略。
4.2 客户端自定义扩展
通过扩展接口可深度定制客户端行为,支持超时配置、事件监听、消息处理等。
支持两类扩展接口:
McpSyncClientCustomizer:同步客户端扩展McpAsyncClientCustomizer:异步客户端扩展
可自定义能力:
- 请求超时配置
- LLM 采样处理器
- 文件根路径权限管理
- 交互式信息收集处理器
- 各类事件监听器(工具/资源/提示词变更、进度通知、日志通知等)
同步客户端扩展示例:
java
@Component
public class CustomMcpSyncClientCustomizer implements McpSyncClientCustomizer {
@Override
public void customize(String serverConfigurationName, McpClient.SyncSpec spec) {
// 自定义超时时间
spec.requestTimeout(Duration.ofSeconds(30));
// 根路径配置
spec.roots(roots);
// 采样请求处理
spec.sampling(request -> { /* 业务逻辑 */ });
// 信息收集请求处理
spec.elicitation(request -> { /* 业务逻辑 */ });
// 进度通知监听
spec.progressConsumer(progress -> { /* 业务逻辑 */ });
// 工具列表变更监听
spec.toolsChangeConsumer(tools -> { /* 业务逻辑 */ });
// 资源列表变更监听
spec.resourcesChangeConsumer(resources -> { /* 业务逻辑 */ });
// 提示词列表变更监听
spec.promptsChangeConsumer(prompts -> { /* 业务逻辑 */ });
// 日志消息监听
spec.loggingConsumer(log -> { /* 业务逻辑 */ });
}
}
4.3 传输方式支持
| 传输方式 | 标准启动器 | WebFlux 启动器 |
|---|---|---|
| STDIO 标准输入输出 | ✅ | ✅ |
| HttpClient 版 HTTP/SSE、流式 HTTP | ✅ | ❌ |
| WebFlux 版 HTTP/SSE、流式 HTTP | ❌ | ✅ |
4.4 工具过滤
实现 McpToolFilter 接口,可根据连接信息、工具属性动态过滤工具(启用/禁用),全局仅允许一个过滤 Bean。
java
@Component
public class CustomMcpToolFilter implements McpToolFilter {
@Override
public boolean test(McpConnectionInfo connectionInfo, McpSchema.Tool tool) {
// 过滤指定客户端的所有工具
if ("restricted-client".equals(connectionInfo.clientInfo().name())) {
return false;
}
// 仅保留名称前缀为 allowed_ 的工具
if (tool.name().startsWith("allowed_")) {
return true;
}
// 过滤标注为实验性的工具
if (tool.getDescription() != null && tool.getDescription().contains("experimental")) {
return false;
}
return true;
}
}
4.5 工具名称前缀生成
通过 McpToolNamePrefixGenerator 为工具名添加前缀,解决多服务端工具重名冲突。
框架内置实现:
DefaultMcpToolNamePrefixGenerator(默认):自动去重、特殊字符转下划线、超长截断,保证全局唯一noPrefix():不添加前缀(多服务端场景不推荐,易引发冲突)
自定义前缀规则示例:
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().replace(".", "_");
// 格式:服务名_版本_工具名
return serverName + "_v" + serverVersion + "_" + tool.name();
}
}
关闭前缀功能:
java
@Configuration
public class McpConfiguration {
@Bean
public McpToolNamePrefixGenerator mcpToolNamePrefixGenerator() {
return McpToolNamePrefixGenerator.noPrefix();
}
}
4.6 工具上下文与元数据转换
通过 ToolContextToMcpMetaConverter,将 Spring AI 工具上下文转为 MCP 调用元数据,可传递用户ID、令牌、追踪标识等上下文。
框架内置:
- 默认转换器:过滤空值与内置上下文 Key
noOp():禁用上下文转换
4.7 关闭工具回调自动配置
配置 spring.ai.mcp.client.toolcallback.enabled=false,将不再自动创建工具回调实例。
5. MCP 客户端注解
使用注解以声明式方式处理 MCP 各类事件与请求:
| 注解 | 用途 |
|---|---|
@McpLogging |
接收服务端日志通知 |
@McpSampling |
处理 LLM 采样/补全请求 |
@McpElicitation |
向用户收集补充信息 |
@McpProgress |
接收长任务进度通知 |
@McpToolListChanged |
工具列表变更通知 |
@McpResourceListChanged |
资源列表变更通知 |
@McpPromptListChanged |
提示词列表变更通知 |
使用示例:
java
@Component
public class McpClientHandlers {
@McpLogging(clients = "server1")
public void handleLoggingMessage(LoggingMessageNotification notification) {
System.out.println("日志:" + notification.level() + " - " + notification.data());
}
@McpSampling(clients = "server1")
public CreateMessageResult handleSamplingRequest(CreateMessageRequest request) {
// 处理LLM请求并返回结果
return CreateMessageResult.builder()
.role(Role.ASSISTANT)
.content(new TextContent("响应内容"))
.model("gpt-4")
.build();
}
@McpProgress(clients = "server1")
public void handleProgress(ProgressNotification notification) {
double percent = notification.progress() * 100;
System.out.printf("执行进度:%.2f%% %s%n", percent, notification.message());
}
}
注解同步/异步方法均支持 ,可通过 clients 属性指定绑定的客户端实例。
6. 项目使用示例
6.1 完整 YAML 配置
yaml
spring:
ai:
mcp:
client:
enabled: true
name: my-mcp-client
version: 1.0.0
request-timeout: 30s
type: SYNC
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"
6.2 代码注入使用
java
// 同步客户端注入
@Autowired
private List<McpSyncClient> mcpSyncClients;
// 异步客户端注入
@Autowired
private List<McpAsyncClient> mcpAsyncClients;
// 工具回调注入
@Autowired
private SyncMcpToolCallbackProvider toolCallbackProvider;