WebFlux MCP客户端
Spring AI MCP Client with WebFlux(Reactive)和Ollama LLM示例项目。
使用WebFlux MCP服务器上的工具,使本地LLM可以利用外部API数据。
特点
- 反应式堆栈:基于Spring WebFlux的完全无阻塞体系结构
- 异步处理:使用Mono/Flux进行主动编程
- 高性能:以较少的线程处理大量并发请求
- MCP工具集成:LLM动态使用远程MCP服务器上的工具
- 生产就绪:Spring AI官方推荐方式
首选参数
标准框架执行环境5.0(Boot应用)
| 项目 | 版本 |
|---|---|
| JDK | 17 |
| 雅加达EE | 10 |
| Servlet | 6.0 |
| 弹簧框架 | 6.2.11 |
| 弹簧靴 | 3.5.6 |
| 春季AI | 1.1.2 |
开发和构建工具
| 项目 | 版本 |
|---|---|
| Maven | 3.9.9 |
| Docker | 28.0.4 |
外部服务
项目版本备注 | :--- | :--- | :--- | Ollama 0.16.0 LLM型号服务 | PostgreSQL | 16 | Docker图片: postgres:16 (端口5433)|
动作流(Reactive)
[사용자]
↓
[REST API /api/chat] (Reactive)
↓
[ChatController] → Mono
↓
[ChatService] → Mono
↓ (subscribeOn: boundedElastic)
[Ollama LLM] ←→ [AsyncMcpToolCallbackProvider] ←→ [MCP Server (http://localhost:9090)]
↓ (블로킹 작업을 별도 스레드에서 실행) ↓
[Mono 응답] [Tools: getTouristWeatherIndex, getCityInfo, getCurrentTime]项目结构
my-webflux-mcp-client/
├── pom.xml # Maven 설정 (WebFlux, MCP Client)
├── README.md
└── src/main/
├── java/com/example/client/
│ ├── ClientApplication.java # Main Application
│ ├── config/
│ │ ├── OllamaConfig.java # Ollama API 설정
│ │ └── SwaggerConfig.java # Swagger 설정
│ ├── controller/
│ │ └── ChatController.java # Reactive REST API (Mono 반환)
│ └── service/
│ └── ChatService.java # Reactive LLM + MCP Tool 통합
└── resources/
└── application.properties # Ollama, MCP 서버, 타임아웃 설정事前准备
1.安装Ollama并下载型号
# Ollama 설치 (https://ollama.com/download)
# 모델 다운로드 (Tool Calling 지원 모델 필요)
ollama pull qwen2.5:7b
# Ollama 서버 실행 확인
ollama serveOllama服务器http://localhost:11434必须在中运行。
2.运行MCP服务器
首先,您需要运行WebFlux MCP服务器:
cd C:\workspace-test\webflux-mcp-sample\my-webflux-mcp-server
mvn clean package
java -jar target/webflux-mcp-0.0.1-SNAPSHOT.jar服务器http://localhost:9090必须在中运行。
构建和运行
1.构建
cd C:\workspace-test\webflux-mcp-sample\my-webflux-mcp-client
mvn clean package2.运行
java -jar target/webflux-mcp-client-0.0.1-SNAPSHOT.jar客户端http://localhost:8080在中运行。
检查启动日志:
INFO o.s.b.w.e.netty.NettyWebServer : Netty started on port 8080
^^^^^^ WebFlux는 Netty 사용
INFO c.e.c.ClientApplication : Started ClientApplication测试
测试方案
通过以下流验证MCP Client是否正常运行:
- 向客户机提问 →向REST API发送问题
- 由本地LLM判断 →确定是否需要Tool
- MCP服务器的Tool调用 →在服务器上查看公共API数据
- 确认响应 →LLM使用Tool结果生成答案
1.景区天气查询测试
# GET 방식
curl "http://localhost:8080/api/chat?message=서울 강남구 관광지 날씨 알려줘"
# POST 방식
curl -X POST http://localhost:8080/api/chat \
-H "Content-Type: application/json" \
-d '{"message": "제주도 관광지 TCI 지수는?"}'预期动作:
- Ollama LLM分析问题
getCityInfo使用Tool检查城市代码getTouristWeatherIndex认为需要Tool- 向MCP服务器请求Tool调用
- 在公共API中查看旅游景点气候指数数据
- LLM用自然语言回答结果
2.测试时间查询
curl "http://localhost:8080/api/chat?message=서울 시간대의 현재 시간은?"
# 또는
curl -X POST http://localhost:8080/api/chat \
-H "Content-Type: application/json" \
-d '{"message": "Asia/Seoul 타임존의 현재 날짜와 시간 알려줘"}'预期动作:
- Ollama LLM分析问题
getCurrentDateTimeWithZone认为需要Tool- 向MCP服务器请求Tool调用
- 在服务器上查看当前时间
- LLM用自然语言回答结果
3.确认日志
您可以在客户端控制台中查看以下日志:
INFO c.e.c.service.ChatService - User message: 서울 강남구 관광지 날씨 알려줘
INFO c.e.c.service.ChatService - Available tools: [getTouristWeatherIndex, getTouristWeatherByDate, getCityInfo, getCurrentDateTimeWithZone]
INFO c.e.c.service.ChatService - AI response: ...测试成功标准
✅ 成功测试:
- MCP Client连接到服务器并获取工具列表
- LLM为您的问题选择合适的工具
- 调用MCP服务器上的Tool以返回实际数据
- LLM使用Tool结果生成自然语言响应
主要设置
application.properties
# Ollama LLM 설정
spring.ai.ollama.base-url=http://localhost:11434
spring.ai.ollama.chat.options.model=qwen3-4b:Q4_K_M
spring.ai.ollama.chat.options.temperature=0.7
# Ollama 타임아웃 설정 (Tool Calling은 시간이 오래 걸림)
spring.ai.ollama.chat.timeout=120s
spring.ai.retry.max-attempts=3
# MCP Client Type (ASYNC for WebFlux)
spring.ai.mcp.client.type=ASYNC
# MCP Client 연결 설정
spring.ai.mcp.client.sse.connections.webflux-weather-api.url=http://localhost:9090/mcp/sse
spring.ai.mcp.client.init-timeout=60000使用不同的LLM模型
要使用Ollama的其他型号(仅限支持Tool Calling的型号):
# Tool Calling 지원 모델 다운로드
ollama pull llama3.1
ollama pull mistral
# application.properties 수정
spring.ai.ollama.chat.options.model=llama3.1注意:要使用Tool Calling,必须使用支持的模型(Llama 3.1+、Mistral、Qwen等)。
故障射击
1.“拒绝连接”错误
原因:MCP服务器未运行
解决:
cd C:\workspace-test\webflux-mcp-sample\my-webflux-mcp-server
java -jar target/webflux-mcp-0.0.1-SNAPSHOT.jar2.“Ollama not available”错误
原因:Ollama服务器无法运行
解决:
ollama serve3.不调用Tool
原因:LLM不认为需要工具
解决:更具体地更改问题
- “天气怎么样?”
- “告诉我首尔江南区观光地的天气”
- “济州岛观光地TCI指数是?”
扩展想法
- 添加Web UI:使用React、Vue等实现聊天界面
- 对话历史记录:记忆以前对话内容的功能
- 多MCP服务器:同时连接多个MCP服务器
- 流响应:实时响应流到SSE
WebFlux Reactive特性
响应式编程
// ChatController (Reactive)
@PostMapping
public Mono chat(@RequestBody ChatRequest request) {
return chatService.chat(request.message())
.map(ChatResponse::new); // 논블로킹 변환
}
// ChatService (Reactive)
public Mono chat(String userMessage) {
return Mono.fromCallable(() -> {
// 블로킹 작업 (Ollama LLM 호출)
return chatModel.call(prompt);
})
.subscribeOn(Schedulers.boundedElastic()) // 별도 스레드에서 실행
.map(response -> response.replaceAll(".*?", ""));
}subscribeOn(Schedulers.bounded弹性())的作用
- 问题:Ollama LLM调用是拦截操作
- WebFlux限制:禁止在事件循环线程中拦网
- 解决:
boundedElastic()在线程池中执行拦网操作
요청 → WebFlux 이벤트 루프 (reactor-http-nio-6)
↓
subscribeOn(boundedElastic)
↓
별도 스레드 (boundedElastic-1)
↓ (여기서 블로킹 가능!)
chatModel.call(prompt)
↓
WebFlux로 결과 반환WebMVC与WebFlux比较
| 主题 | WebMVC | WebFlux(当前) |
|---|---|---|
| 处理模型 | 同步/拦网 | 异步/无拦网 |
| 编程 命令式响应(Mono/Flux) | ||
| 主题 | 每个请求1个线程 | 事件循环(4-8个线程) |
| 依赖性 | spring-boot-starter-web | spring-boot-starter-webflux |
| 服务器 | Tomcat | Netty |
| MCP客户端 | spring-ai-starter-mcp-client | spring-ai-starter-mcp-client-webflux |
| 性能 | 适合并发100人 | 并发1000人+可处理 |
| 学习曲线 低高(Reactive) | ||
| Spring AI建议 | 开发/测试 | 生产 |
WebFlux的优点
- 用较少的内存处理大量并发请求
- 无阻塞I/O,高吞吐量
- 自动背压(backpressure)
- Spring AI官方推荐方式
主要依赖性
pom.xml文件
org.springframework.boot
spring-boot-starter-webflux
org.springframework.ai
spring-ai-starter-mcp-client-webflux
org.springframework.ai
spring-ai-starter-model-ollama
org.springdoc
springdoc-openapi-starter-webflux-ui
性能特性
预计响应时间
任务时间说明 |------|------|------| |简单问题(无工具)| 2~5秒|仅LLM推论| | 1次调用Tool 5~15秒getCityInfo等 |调用Tool 2至3次15~30秒传唤多阶段Tool
设置超时
# Ollama LLM 타임아웃 (120초)
spring.ai.ollama.chat.timeout=120s
# MCP Client 초기화 타임아웃 (60초)
spring.ai.mcp.client.init-timeout=60000故障射击
1.读取超时异常
症状: io.netty.handler.timeout.ReadTimeoutException
原因:Tool Calling比超时时间长
解决:
spring.ai.ollama.chat.timeout=180s # 3분으로 증가2.非法状态异常:block()不受支持
症状: block()/blockFirst()/blockLast() are blocking
原因:在WebFlux事件循环线程中调用拦网
解决: subscribeOn(Schedulers.boundedElastic()) 已启用(已应用)
3.Swagger用户界面404
验证路径:
/swagger-ui.html/webjars/swagger-ui/index.html
验证依赖性:
springdoc-openapi-starter-webflux-ui