Spring AI 1.x 系列【40】MCP 客户端 Spring Boot 启动器
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)模式(两种模式不可混用)。
<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传输。
<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):
spring:ai:mcp:client:stdio:root-change-notification:trueconnections:server1:command:/path/to/serverargs:---port=8080---mode=productionenv:API_KEY:your-api-keyDEBUG:"true"引用外部 JSON 配置文件(兼容 Claude Desktop 格式):
spring:ai:mcp:client:stdio:servers-configuration:classpath:mcp-servers.jsonmcp-servers.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):
{"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"]}}}跨平台代码式配置:
通过代码判断操作系统,实现一套配置兼容全平台,同时添加@ConditionalOnMissingBean避免与配置文件自动配置冲突:
@Bean(destroyMethod="close")@ConditionalOnMissingBean(McpSyncClient.class)publicMcpSyncClientmcpClient(){ServerParametersstdioParams;if(isWindows()){// Windows 系统:使用 cmd.exe 包装命令varwinArgs=newArrayList<>(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();}returnMcpClient.sync(newStdioClientTransport(stdioParams,McpJsonMapper.createDefault())).requestTimeout(Duration.ofSeconds(10)).build().initialize();}// 判断当前系统是否为 WindowsprivatestaticbooleanisWindows(){returnSystem.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 |
配置示例:
spring:ai:mcp:client:streamable-http:connections:server1:url:http://localhost:8080server2:url:http://otherserver:8081endpoint:/custom-sse3.5 SSE(服务端推送事件)传输配置
配置前缀:spring.ai.mcp.client.sse
| 配置项 | 说明 | 默认值 |
|---|---|---|
| connections | 命名式 SSE 连接配置集合 | 无 |
| connections.[name].url | MCP 服务端基础地址 | 无 |
| connections.[name].sse-endpoint | SSE 接口后缀路径 | /sse |
配置示例:
spring:ai:mcp:client:sse:connections:server1:url:http://localhost:8080server2:url:http://otherserver:8081sse-endpoint:/custom-sseURL 拆分规则:
完整 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 采样处理器
- 文件根路径权限管理
- 交互式信息收集处理器
- 各类事件监听器(工具/资源/提示词变更、进度通知、日志通知等)
同步客户端扩展示例:
@ComponentpublicclassCustomMcpSyncClientCustomizerimplementsMcpSyncClientCustomizer{@Overridepublicvoidcustomize(StringserverConfigurationName,McpClient.SyncSpecspec){// 自定义超时时间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。
@ComponentpublicclassCustomMcpToolFilterimplementsMcpToolFilter{@Overridepublicbooleantest(McpConnectionInfoconnectionInfo,McpSchema.Tooltool){// 过滤指定客户端的所有工具if("restricted-client".equals(connectionInfo.clientInfo().name())){returnfalse;}// 仅保留名称前缀为 allowed_ 的工具if(tool.name().startsWith("allowed_")){returntrue;}// 过滤标注为实验性的工具if(tool.getDescription()!=null&&tool.getDescription().contains("experimental")){returnfalse;}returntrue;}}4.5 工具名称前缀生成
通过McpToolNamePrefixGenerator为工具名添加前缀,解决多服务端工具重名冲突。
框架内置实现:
DefaultMcpToolNamePrefixGenerator(默认):自动去重、特殊字符转下划线、超长截断,保证全局唯一noPrefix():不添加前缀(多服务端场景不推荐,易引发冲突)
自定义前缀规则示例:
@ComponentpublicclassCustomToolNamePrefixGeneratorimplementsMcpToolNamePrefixGenerator{@OverridepublicStringprefixedToolName(McpConnectionInfoconnectionInfo,Tooltool){StringserverName=connectionInfo.initializeResult().serverInfo().name();StringserverVersion=connectionInfo.initializeResult().serverInfo().version().replace(".","_");// 格式:服务名_版本_工具名returnserverName+"_v"+serverVersion+"_"+tool.name();}}关闭前缀功能:
@ConfigurationpublicclassMcpConfiguration{@BeanpublicMcpToolNamePrefixGeneratormcpToolNamePrefixGenerator(){returnMcpToolNamePrefixGenerator.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 | 提示词列表变更通知 |
使用示例:
@ComponentpublicclassMcpClientHandlers{@McpLogging(clients="server1")publicvoidhandleLoggingMessage(LoggingMessageNotificationnotification){System.out.println("日志:"+notification.level()+" - "+notification.data());}@McpSampling(clients="server1")publicCreateMessageResulthandleSamplingRequest(CreateMessageRequestrequest){// 处理LLM请求并返回结果returnCreateMessageResult.builder().role(Role.ASSISTANT).content(newTextContent("响应内容")).model("gpt-4").build();}@McpProgress(clients="server1")publicvoidhandleProgress(ProgressNotificationnotification){doublepercent=notification.progress()*100;System.out.printf("执行进度:%.2f%% %s%n",percent,notification.message());}}注解同步/异步方法均支持,可通过clients属性指定绑定的客户端实例。
6. 项目使用示例
6.1 完整 YAML 配置
spring:ai:mcp:client:enabled:truename:my-mcp-clientversion:1.0.0request-timeout:30stype:SYNCsse:connections:server1:url:http://localhost:8080server2:url:http://otherserver:8081streamable-http:connections:server3:url:http://localhost:8083endpoint:/mcpstdio:root-change-notification:falseconnections:server1:command:/path/to/serverargs:---port=8080---mode=productionenv:API_KEY:your-api-keyDEBUG:"true"6.2 代码注入使用
// 同步客户端注入@AutowiredprivateList<McpSyncClient>mcpSyncClients;// 异步客户端注入@AutowiredprivateList<McpAsyncClient>mcpAsyncClients;// 工具回调注入@AutowiredprivateSyncMcpToolCallbackProvidertoolCallbackProvider;