一、前言
随着 Spring AI 生态不断完善,MCP(Model Context Protocol) 成为了 AI 模型与本地自定义工具通信的核心协议。通过 MCP 协议,我们可以将本地自定义的业务工具方法暴露为 AI 可调用的工具,让大模型自动调用本地接口完成业务逻辑,极大拓展 AI 应用的落地能力。
本文将从零搭建 MCP 服务端(WebFlux 异步)+ MCP 客户端 完整工程,实现:
- 对比「启用 MCP 工具调用」和「普通大模型调用」的差异
- 解决 MCP 启动失败、Web 容器冲突等经典踩坑问题
整套案例基于 Spring Boot + Spring AI + 阿里 DashScope 实现,可直接落地复用。
二、核心原理与踩坑前置说明
2.1 MCP 核心作用
MCP 协议实现了 大模型 <-> 本地工具 的双向通信,客户端向 MCP 服务端发现工具、传递参数,服务端执行本地业务逻辑并返回结果,大模型基于结果生成最终回答。
2.2 关键避坑点
spring-ai-starter-mcp-server-webflux依赖 绝对不能与 spring-boot-starter-web 共存!
- web 依赖会强制使用 Tomcat 容器启动
- MCP WebFlux 依赖需要 Netty 容器支撑
- 两者共存时,程序可正常启动,但 MCP 服务端异常,客户端无法连接调用工具
✅ 解决方案:MCP 服务端仅引入 webflux 相关依赖,剔除 web 依赖;客户端可正常引入 web 依赖。
三、MCP 服务端搭建
服务端核心职责:定义自定义工具、注册 MCP 工具回调、开启异步 MCP 服务,对外暴露工具调用能力。
3.1 Pom 核心依赖
服务端禁止引入 spring-boot-starter-web,仅保留核心启动器和 MCP WebFlux 依赖:
<dependencies>
<!-- Spring Boot 核心启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- MCP 服务端 WebFlux 异步依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
</dependencies>3.2 服务端配置文件 application.yml
# 服务端口
server.port=8014
# 全局编码配置
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8
# 应用名称
spring.application.name=SAA-14LocalMcpServer
# MCP 服务端核心配置
spring.ai.mcp.server.type=async
spring.ai.mcp.server.name=customer-define-mcp-server
spring.ai.mcp.server.version=1.0.03.3 自定义工具业务类(天气查询)
通过 @Tool 注解标记工具方法,配置方法描述,用于大模型识别工具能力:
package com.atguigu.study.service;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
* 自定义MCP工具服务:天气查询工具
*/
@Service
public class WeatherService
{
/**
* @Tool 注解:声明为AI可调用工具,description为工具描述,供大模型识别用途
*/
@Tool(description = "根据城市名称获取天气预报")
public String getWeatherByCity(String city)
{
Map<String, String> weatherMap = Map.of(
"北京", "11111降雨频繁,其中今天和后天雨势较强,部分地区有暴雨并伴强对流天气,需注意",
"上海", "22222多云,15℃~27℃,南风3级,当前温度27℃。",
"深圳", "333333多云40天,阴16天,雨30天,晴3天"
);
return weatherMap.getOrDefault(city, "抱歉:未查询到对应城市!");
}
}3.4 MCP 工具注册配置类
将自定义的工具类注册为 ToolCallbackProvider,暴露给 MCP 客户端调用:
package com.atguigu.study.config;
import com.atguigu.study.service.WeatherService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* MCP服务配置:注册自定义工具,对外暴露调用能力
*/
@Configuration
public class McpServerConfig
{
/**
* 将自定义工具方法注册为MCP可调用工具
*/
@Bean
public ToolCallbackProvider weatherTools(WeatherService weatherService)
{
return MethodToolCallbackProvider.builder()
.toolObjects(weatherService)
.build();
}
}四、MCP 客户端搭建
客户端核心职责:连接远程 MCP 服务端、加载远程工具、结合大模型实现自动工具调用、提供接口测试能力。客户端可正常引入 web 依赖。
4.1 Pom 核心依赖
<dependencies>
<!-- Web依赖:客户端需要提供接口测试能力 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 阿里通义千问大模型依赖 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<!-- MCP 客户端依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
</dependencies>4.2 客户端配置文件 application.yml
# 服务端口
server.port=8015
# 全局编码配置
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8
# 应用名称
spring.application.name=SAA-15LocalMcpClient
# 阿里通义千问API密钥(替换为自己的密钥)
spring.ai.dashscope.api-key=${aliQwen-api}
# MCP客户端核心配置
spring.ai.mcp.client.type=async
spring.ai.mcp.client.request-timeout=60s
# 开启MCP工具回调
spring.ai.mcp.client.toolcallback.enabled=true
# 绑定本地MCP服务端地址
spring.ai.mcp.client.sse.connections.mcp-server1.url=http://localhost:80144.3 ChatClient 集成 MCP 工具配置
将 MCP 远程工具注入 ChatClient,实现大模型自动感知并调用远程工具:
package com.atguigu.study.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* AI 客户端配置:集成MCP远程工具
*/
@Configuration
public class SaaLLMConfig
{
/**
* 构建集成MCP工具的ChatClient
* 自动加载MCP服务端暴露的所有工具方法
*/
@Bean
public ChatClient chatClient(ChatModel chatModel, ToolCallbackProvider tools)
{
return ChatClient.builder(chatModel)
// 注入MCP远程工具回调
.defaultToolCallbacks(tools.getToolCallbacks())
.build();
}
}4.4 测试控制器(对比MCP启用/关闭效果)
提供两个接口:分别为启用MCP工具调用、原生大模型调用(无工具),直观对比差异:
package com.atguigu.study.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
/**
* MCP客户端测试控制器
*/
@RestController
public class McpClientController
{
// 集成MCP工具的AI客户端
@Resource
private ChatClient chatClient;
// 原生AI模型(无MCP工具)
@Resource
private ChatModel chatModel;
/**
* 带MCP工具调用的流式对话
* 大模型会自动调用MCP服务端的天气工具
*/
@GetMapping("/mcpclient/chat")
public Flux<String> chat(@RequestParam(name = "msg",defaultValue = "北京") String msg)
{
System.out.println("【使用MCP工具调用】");
return chatClient.prompt(msg).stream().content();
}
/**
* 原生大模型调用(无本地工具)
* 大模型仅通过自身知识库回答,无法获取本地自定义数据
*/
@GetMapping("/mcpclient/chat2")
public Flux<String> chat2(@RequestParam(name = "msg",defaultValue = "北京") String msg)
{
System.out.println("【未使用MCP工具调用】");
return chatModel.stream(msg);
}
}五、项目启动与测试
5.1 启动顺序
- 先启动 MCP 服务端(8014),保证 MCP 服务正常监听
- 再启动 MCP 客户端(8015),自动连接服务端加载工具
5.2 接口测试
1、启用 MCP 工具调用
请求地址:http://localhost:8015/mcpclient/chat?msg=上海天气怎么样
效果:大模型自动识别需要调用本地天气工具,请求 8014 服务端接口,返回自定义的本地天气数据。
2、未启用 MCP 工具调用
请求地址:http://localhost:8015/mcpclient/chat2?msg=上海天气怎么样
效果:大模型仅通过自身知识库回答实时天气,无法读取我们自定义的本地天气数据。
六、常见问题总结
6.1 MCP客户端连接不上服务端
原因:服务端引入了 spring-boot-starter-web,导致容器变为 Tomcat,MCP 基于 Netty 的 WebFlux 服务失效。
解决:服务端删除 web 依赖,仅保留 MCP webflux 依赖。
6.2 大模型不会自动调用工具
- 检查 @Tool 注解的 description 是否清晰准确,大模型依赖描述识别工具用途
- 检查客户端是否正确注入 ToolCallbackProvider
- 确认 MCP 客户端配置的服务端地址正确、网络通畅
6.3 工具参数匹配失败
保证工具方法参数名、参数类型与大模型推断的参数一致,简单字符串参数为最稳适配方案。
七、总结
本文完整实现了 Spring AI MCP 异步服务端+客户端 落地案例,核心要点如下:
- MCP 服务端基于 WebFlux 异步实现,严格规避 web 依赖冲突
- 通过 @Tool 注解+ToolCallbackProvider 实现自定义工具对外暴露
- 客户端集成 MCP 远程工具,让大模型具备调用本地业务接口的能力
- 区分原生大模型调用与工具调用的核心差异,适配业务落地场景
该方案可快速拓展至数据库查询、接口调用、文件处理等各类本地业务工具,是 Spring AI 本地化 AI 应用开发的核心方案。