Spring AI + MCP Client 配置与使用详解
前言
随着大模型技术的快速发展,Model Coordination Protocol (MCP) 逐渐成为连接本地系统和远程AI服务的重要桥梁。Spring AI 是 Spring 官方推出的 AI 开发框架,支持多种语言模型接口,而 MCP Client 则是其集成远程推理能力的核心组件之一。
本文将详细介绍如何在 Spring Boot 项目中配置和使用 Spring AI 的 MCP Client,包括环境准备、依赖引入、配置方式、代码实现、扩展机制以及常见问题排查等内容。
一、什么是 MCP?
Model Coordination Protocol (MCP) 是一种用于协调本地应用与远程 AI 模型服务之间交互的协议。它允许你:
- 向远程模型服务器发送请求;
- 获取模型输出结果;
- 管理模型状态(如会话上下文);
- 支持多模型切换、流式响应等高级功能。
Spring AI 提供了对 MCP 协议的支持,通过 spring-ai-mcp-client
模块可以轻松对接基于 MCP 协议的模型服务。
二、准备工作
1. Java 版本要求
- JDK 17 或以上版本
- Spring Boot 3.x(建议使用 3.2+)
2. Maven 依赖
<dependencies><!-- Spring AI 核心 --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-core</artifactId><version>0.8.1</version></dependency><!-- Spring AI MCP Client --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-mcp-client</artifactId><version>0.8.1</version></dependency><!-- WebClient 支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>
</dependencies>
三、MCP Server 要求
你需要一个支持 MCP 协议的服务端,例如:
- 自建的 MCP 服务(可基于 Python 实现)
- 第三方提供 MCP 接口的模型服务
MCP 服务通常需要暴露以下接口:
方法
路径
功能
POST
/v1/models/{model}/generate
生成文本
POST
/v1/models/{model}/chat
对话模式
GET
/v1/models
获取可用模型列表
四、配置 MCP Client
1. application.yml 配置
spring:ai:mcp:client:base-url: http://localhost:8080 # MCP Server 地址model-name: qwen-3b # 默认模型名称timeout: 60s # 请求超时时间
五、代码示例
1. 创建 MCP Client Bean
你可以通过自动装配来使用 McpClient
:
import org.springframework.ai.mcp.client.McpClient;
import org.springframework.stereotype.Service;@Service
public class AIClientService {private final McpClient mcpClient;public AIClientService(McpClient mcpClient) {this.mcpClient = mcpClient;}public String generateText(String prompt) {return mcpClient.generate(prompt);}
}
2. 使用 WebClient 手动调用
如果你希望更灵活地控制请求,也可以直接注入 WebClient
:
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;@Service
public class CustomAIService {private final WebClient webClient;public CustomAIService(WebClient.Builder webClientBuilder) {this.webClient = webClientBuilder.baseUrl("http://localhost:8080/v1").build();}public Mono<String> chatWithModel(String model, String prompt) {var body = Map.of("model", model, "prompt", prompt);return webClient.post().uri("/models/{model}/generate", model).bodyValue(body).retrieve().bodyToMono(Map.class).map(response -> response.get("content").toString());}
}
六、使用 Stream 流式输出
Spring AI 支持流式响应处理,适用于需要逐步接收模型输出的场景。
Flux<String> stream = mcpClient.stream("请写一首关于夏天的诗");stream.subscribe(System.out::println); // 输出每一行生成内容
七、模型切换与多模型支持
你可以在运行时动态指定不同的模型名称:
String response = mcpClient.withModel("llama-3-8b").generate("讲个笑话");
或使用配置文件设置默认模型,并在代码中覆盖:
spring:ai:mcp:client:base-url: http://localhost:8080model-name: mistral-nemo
八、自定义配置与拦截器
你可以通过配置类来自定义 WebClient 行为,比如添加请求头、日志拦截等。
@Configuration
public class WebClientConfig {@Beanpublic WebClientCustomizer webClientCustomizer() {return webClient -> webClient.defaultHeader("Authorization", "Bearer your_token");}
}
九、MCP Client 的扩展点详解
Spring AI 提供了良好的可扩展性设计,允许开发者通过自定义组件来增强或修改 McpClient
的行为。下面我们将详细介绍几个主要的扩展点及其使用方式。
1. McpRequestInterceptor
—— 请求拦截器
这是一个在请求发送前进行处理的接口,你可以用来添加认证头、日志记录、参数修改等操作。
示例代码:
import org.springframework.ai.mcp.client.McpRequest;
import org.springframework.ai.mcp.client.McpRequestInterceptor;public class AuthRequestInterceptor implements McpRequestInterceptor {@Overridepublic void intercept(McpRequest request) {// 添加认证头request.headers().set("Authorization", "Bearer your_token_here");// 打印请求信息System.out.println("Intercepting request to model: " + request.model());}
}
注册方式:
@Configuration
public class McpConfig {@Beanpublic McpRequestInterceptor authRequestInterceptor() {return new AuthRequestInterceptor();}
}
2. McpResponsePostProcessor
—— 响应后处理器
该接口用于在接收到模型返回结果后对响应进行加工处理,例如日志记录、格式转换、异常封装等。
示例代码:
import org.springframework.ai.mcp.client.McpResponse;
import org.springframework.ai.mcp.client.McpResponsePostProcessor;public class LoggingResponsePostProcessor implements McpResponsePostProcessor {@Overridepublic void process(McpResponse response) {System.out.println("Received response from model: " + response.model());System.out.println("Response content length: " + response.content().length());}
}
注册方式:
@Bean
public McpResponsePostProcessor loggingResponsePostProcessor() {return new LoggingResponsePostProcessor();
}
3. McpModelSelector
—— 模型选择器
这个扩展点用于根据上下文动态选择使用的模型。比如可以根据用户身份、输入内容类型、负载情况等决定调用哪个模型。
示例代码:
import org.springframework.ai.mcp.client.McpModelSelector;public class SmartModelSelector implements McpModelSelector {@Overridepublic String selectModel(String input) {if (input.contains("code")) {return "codellama";} else if (input.contains("math")) {return "deepseek-math";} else {return "qwen-3b"; // 默认模型}}
}
注册方式:
@Bean
public McpModelSelector smartModelSelector() {return new SmartModelSelector();
}
注意:需要确保你的
McpClient
配置启用了该选择器。
4. 自定义 WebClient 行为(如重试机制)
你还可以通过 WebClientCustomizer
来定制底层的 WebClient
实例,实现诸如自动重试、超时控制等功能。
示例代码:
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.boot.web.reactive.function.client.WebClientCustomizer;
import org.springframework.stereotype.Component;@Component
public class RetryWebClientCustomizer implements WebClientCustomizer {@Overridepublic void customize(WebClient.Builder webClientBuilder) {webClientBuilder.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024));webClientBuilder.filters(exchangeFilterFunctions -> {exchangeFilterFunctions.add((clientRequest, next) ->next.exchange(clientRequest).doOnError(ex -> System.err.println("Error occurred during request: " + ex.getMessage())).retryWhen(Retry.backoff(3, Duration.ofSeconds(1)).filter(ex -> ex instanceof IOException));});}
}
十、常见问题与解决方案详解
1. 连接失败或超时
现象:
应用启动时报错 Connection refused
或 TimeoutException
。
可能原因:
- MCP Server 未启动;
- 地址或端口错误;
- 网络不通或防火墙限制;
- 超时时间设置过短;
- 服务端未正确监听请求路径。
解决方案:
-
检查 MCP Server 是否运行正常
-
使用
curl http://localhost:8080/v1/models
测试是否能访问模型列表 -
查看日志文件确认服务是否报错
-
在
application.yml
中增加超时时间:spring:
ai:
mcp:
client:
timeout: 120s -
如果部署在远程服务器,检查网络连通性和防火墙规则。
2. 返回格式错误 / 数据解析失败
现象:
抛出 JsonProcessingException
或无法提取 content
字段。
可能原因:
- MCP Server 返回的数据结构不符合预期;
- 缺少
content
字段; - 返回 JSON 格式不合法;
- 服务端返回错误码但未被正确处理。
解决方案:
确保服务端返回如下格式:
{"content": "这是模型的回答","model": "qwen-3b"
}
在客户端加入日志打印中间响应体:
Flux<String> stream = mcpClient.stream("你好");
stream.doOnNext(System.out::println).subscribe();
使用 exchange()
方法获取原始响应并手动处理:
Mono<ClientResponse> responseMono = webClient.post().uri("/models/qwen/generate").bodyValue(Map.of("prompt", "Hello")).exchangeToMono(response -> {if (response.statusCode().isError()) {return response.bodyToMono(String.class).flatMap(errorBody -> Mono.error(new RuntimeException("Server error: " + errorBody)));}return response.bodyToMono(Map.class);});
3. 不支持流式输出
现象:
调用 .stream()
方法时没有输出或抛出异常。
可能原因:
- 服务端未启用
text/event-stream
类型的响应; - WebClient 未正确配置以处理事件流;
- 服务端未按规范返回 SSE(Server-Sent Events)数据。
解决方案:
检查服务端是否返回正确的 Content-Type:
Content-Type: text/event-stream
确保服务端每行返回一个 data:
字段:
data: {"content":"这"}
data: {"content":"是"}
data: {"content":"一"}
data: {"content":"句"}
data: {"content":"话"}
在客户端使用 retrieve().bodyToFlux(String.class)
接收流式响应:
Flux<String> stream = webClient.get().uri("/models/qwen/chat").accept(MediaType.TEXT_EVENT_STREAM).retrieve().bodyToFlux(String.class);stream.subscribe(System.out::println);
若使用默认的 McpClient
,请确保其内部 WebClient 支持流式传输。
4. 模型切换无效
现象:
调用 .withModel("xxx")
后仍然使用默认模型。
可能原因:
- 服务端不支持多模型;
- URL 路径中未包含
{model}
参数; McpModelSelector
逻辑冲突;- 请求未正确携带模型名称。
解决方案:
检查服务端是否支持多个模型,并可通过 /v1/models
获取列表
检查 MCP Client 的 Base URL 是否为 /v1
开头
查看日志中实际请求的 URL 是否包含目标模型名
如果使用 McpModelSelector
,可在其 selectModel
方法中加日志调试
5. 日志信息太少,难以排查问题
解决方案:
启用 Spring Boot 的 debug 日志级别:
logging:level:org.springframework.ai: DEBUGreactor: DEBUG
在 McpRequestInterceptor
和 McpResponsePostProcessor
中加入详细的日志输出
使用 WireShark 或 Fiddler 抓包查看实际请求内容
总结
通过本节的深入讲解,你应该已经掌握了以下能力:
- 如何通过
McpRequestInterceptor
和McpResponsePostProcessor
对请求和响应进行拦截和处理 - 如何实现
McpModelSelector
动态选择模型 - 如何自定义 WebClient 实现高级功能(如重试、日志、流式处理)
- 如何排查连接失败、格式错误、流式输出异常等问题
这些扩展能力和排错技巧对于构建稳定、灵活的企业级 AI 应用非常关键。如果你正在开发一个生产级别的系统,建议将这些扩展点作为标准模块进行封装复用。
参考链接
- Spring AI GitHub
- MCP 协议文档
- Spring Boot WebFlux 文档