Spring AI + MCP Client 配置与使用详解_sping 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> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-core</artifactId> <version>0.8.1</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-mcp-client</artifactId> <version>0.8.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency></dependencies>
三、MCP Server 要求
你需要一个支持 MCP 协议的服务端,例如:
- 自建的 MCP 服务(可基于 Python 实现)
- 第三方提供 MCP 接口的模型服务
MCP 服务通常需要暴露以下接口:
/v1/models/{model}/generate
/v1/models/{model}/chat
/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;@Servicepublic 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;@Servicepublic 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:8080 model-name: mistral-nemo
八、自定义配置与拦截器
你可以通过配置类来自定义 WebClient 行为,比如添加请求头、日志拦截等。
@Configurationpublic class WebClientConfig { @Bean public 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 { @Override public void intercept(McpRequest request) { // 添加认证头 request.headers().set(\"Authorization\", \"Bearer your_token_here\"); // 打印请求信息 System.out.println(\"Intercepting request to model: \" + request.model()); }}
注册方式:
@Configurationpublic class McpConfig { @Bean public 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 { @Override public void process(McpResponse response) { System.out.println(\"Received response from model: \" + response.model()); System.out.println(\"Response content length: \" + response.content().length()); }}
注册方式:
@Beanpublic McpResponsePostProcessor loggingResponsePostProcessor() { return new LoggingResponsePostProcessor();}
3. McpModelSelector
—— 模型选择器
这个扩展点用于根据上下文动态选择使用的模型。比如可以根据用户身份、输入内容类型、负载情况等决定调用哪个模型。
示例代码:
import org.springframework.ai.mcp.client.McpModelSelector;public class SmartModelSelector implements McpModelSelector { @Override public String selectModel(String input) { if (input.contains(\"code\")) { return \"codellama\"; } else if (input.contains(\"math\")) { return \"deepseek-math\"; } else { return \"qwen-3b\"; // 默认模型 } }}
注册方式:
@Beanpublic 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;@Componentpublic class RetryWebClientCustomizer implements WebClientCustomizer { @Override public 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: DEBUG reactor: DEBUG
在 McpRequestInterceptor
和 McpResponsePostProcessor
中加入详细的日志输出
使用 WireShark 或 Fiddler 抓包查看实际请求内容
总结
通过本节的深入讲解,你应该已经掌握了以下能力:
- 如何通过
McpRequestInterceptor
和McpResponsePostProcessor
对请求和响应进行拦截和处理 - 如何实现
McpModelSelector
动态选择模型 - 如何自定义 WebClient 实现高级功能(如重试、日志、流式处理)
- 如何排查连接失败、格式错误、流式输出异常等问题
这些扩展能力和排错技巧对于构建稳定、灵活的企业级 AI 应用非常关键。如果你正在开发一个生产级别的系统,建议将这些扩展点作为标准模块进行封装复用。
参考链接
- Spring AI GitHub
- MCP 协议文档
- Spring Boot WebFlux 文档