基础:SpringBoot, 大模型基础
前言
开发mcp,理解mcp的概念很重要,举个抽象的例子:
想象一下, client 和 server 两个进程之间,有一根"永远开着的电话线"(SSE 长连接)。这根线一旦接通,双方就可以随时互相喊话。
握手阶段,Server 会先告诉 Client:"我支持 MCP 协议 x.y 版本,这里是我当前的能力包"、"我有哪些工具、怎么使用"。之后这根线就一直保持着:
Server 有新工具 → 它在电话线里说一句 "工具列表变了!"(tools/listchanged 事件);
Client 听到后 → 主动再问一次:"给我最新的列表"(tools/list 请求),然后把新的工具元数据写入本地缓存。
Client 在大模型对话的时候,会根据当前问题和上下文,自动判断使用哪个工具。
整个过程不需要重启 Client,因为连接一直在,你随时能接到 Server 的"变更提醒"。
spring ai alibaba封装了这些底层细节,我们只需要根据需要,开发对应的工具即可。
总结就是:server负责提供工具的实现,而client负责获取server的工具列表,并由大模型决定使用哪个工具。
基于 sse 查询天气mcp开发示例
weatherServer
项目结构:

pom
yaml
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
</dependencies>
配置文件:
yaml
server:
port: 8080
spring:
mcp:
server:
name: my-weather-server # 服务名称
version: 1.0.0
# 下面都是默认配置,可以不配置
type: async
sse-endpoint: /sse
sse-message-endpoint: /mcp/message
capabilities:
tool: true
resource: true
prompt: true
completion: true
编写工具:
java
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
@Service
public class OpenMeteoService {
private final WebClient webClient;
// 实时查询天气
public OpenMeteoService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder
.baseUrl("https://api.open-meteo.com/v1")
.defaultHeader("Accept", "application/json")
.defaultHeader("User-Agent", "OpenMeteoClient/1.0")
.build();
}
@Tool(description = "根据经纬度获取天气预报")
public String getWeatherForecastByLocation(
@ToolParam(description = "纬度,例如:39.9042") String latitude,
@ToolParam(description = "经度,例如:116.4074") String longitude) {
try {
String response = webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/forecast")
.queryParam("latitude", latitude)
.queryParam("longitude", longitude)
.queryParam("current", "temperature_2m,wind_speed_10m")
.queryParam("timezone", "auto")
.build())
.retrieve()
.bodyToMono(String.class)
.block();
System.out.printf("当前请求经度:" + longitude + ",纬度:" + latitude + "的天气预报:\n" + response);
// 解析响应并返回格式化的天气信息
return "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的天气信息:\n" + response;
} catch (Exception e) {
return "获取天气信息失败:" + e.getMessage();
}
}
@Tool(description = "根据经纬度获取空气质量信息")
public String getAirQuality(
@ToolParam(description = "纬度,例如:39.9042") String latitude,
@ToolParam(description = "经度,例如:116.4074") String longitude) {
// 模拟数据,实际应用中应调用真实API
return "当前位置(纬度:" + latitude + ",经度:" + longitude + ")的空气质量:\n" +
"- PM2.5: 15 μg/m³ (优)\n" +
"- PM10: 28 μg/m³ (良)\n" +
"- 空气质量指数(AQI): 42 (优)\n" +
"- 主要污染物: 无";
}
}
注册工具:
java
import com.xxxx.lh.service.OpenMeteoService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class StartApplication {
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
@Bean
ToolCallbackProvider weatherTools(OpenMeteoService openMeteoService) {
return MethodToolCallbackProvider.builder()
.toolObjects(openMeteoService) // 将天气工具类注册到tools中
.build();
}
}
至此,我们就完成了server的开发,我们在server中定义了两个工具,分别是根据经纬度查询天气和查询空气质量。 开发主要步骤分为2步:
- 开发工具,通过 @Tool 和 @ToolParam注解,描述方法的参数和作用
- 将方法注册到 ToolCallbackProvider 中。
client 开发
项目结构:

pom
yaml
<dependencies>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>
<!-- Spring AI Starter MCP Client, 这里依赖来自 spring ai bom -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
</dependency>
</dependencies>
配置文件:
yaml
server:
port: 8081
spring:
main:
web-application-type: none
ai:
dashscope:
api-key: sk-xxx # client 需要调用大模型,api-key必填
mcp:
client:
sse:
connections:
server:
url: http://localhost:8080 # 指定server地址,用于mcp连接
大模型调用
java
// 构建chatClient并注入mcp工具
ChatClient chatClient = chatClientBuilder
.defaultToolCallbacks(tools)
.build();
// 大模型交互
String input = "北京天气如何";
System.out.println("\n>>> QUESTION: " + input);
System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(input).call().content());
输出结果:
>>> QUESTION: 北京天气如何
>>> ASSISTANT: 北京当前的天气和空气质量情况如下:
**天气信息:**
- 温度:8.8°C
- 风速:4.8 km/h
- 位置:北京(纬度:39.9042,经度:116.4074)
- 时间:2025-11-07 16:45
**空气质量:**
- PM2.5:15 μg/m³(优)
- PM10:28 μg/m³(良)
- 空气质量指数(AQI):42(优)
- 主要污染物:无
总体来看,北京当前天气较为凉爽,空气质量良好,适合户外活动。
总结:
Server 端启动
注册工具并暴露 MCP 接口。在 weatherServer 中通过 MethodToolCallbackProvider 将 OpenMeteoService 的 @Tool 方法包装成符合 MCP 规范的"Tool 回调"。
spring-ai-starter-mcp-server-webflux 自动暴露 /sse 接口(Server-Sent Events)。当客户端连接时,通过 MCP 协议推送工具列表、参数定义和提示等能力。
OpenMeteoService 的 @Tool 注解包含方法名、描述和参数结构,这些元数据会在连接时标准化并发送至客户端。
Client 端启动
建立 SSE 连接并同步工具。ChatClient 启动时注入 defaultToolCallbacks,指定 MCP 工具入口。
配置文件中设置 spring.ai.mcp.client.sse.connections.server.url=http://localhost:8080,指向 Server 的 SSE 地址。
MCP 客户端使用 WebFlux SSE 连接该地址。连接成功后,Server 按 MCP 规范发送"Capabilities"或"Tools"列表。
客户端自动将工具注册到本地 ToolCallbackProvider,并缓存参数类型和名称等 schema 信息。
大模型问答
模型触发工具调用并由 MCP 转发。执行 chatClient.prompt("北京天气如何") 时,ChatClient 将 MCP 工具列表和 prompt 发送至模型。
模型分析后决定调用工具(如 getWeatherForecastByLocation),并返回符合 OpenAI Function Call 或 MCP Tool Call 格式的信息。
ChatClient 解包 function call 信息,通过 ToolCallbackProvider 调度到实际工具回调。
MCP 工具通过 SSE 连接向 Server 发送 tools/call 消息。Server 动态调用 OpenMeteoService 对应方法(如通过 WebClient 访问 Open-Meteo API),返回结果作为 tools/call.result 消息。
客户端将工具结果包装后交给模型继续推理,最终生成融合工具数据的回答。
连接维护与监听
SSE 是长连接,Server 持续推送工具列表更新和提示等通知。客户端可通过该通道发送资源下载请求。
日志中的 "Server response with Protocol: 2024-11-05, Capabilities: ..." 表示 MCP 握手成功。
连接在应用关闭或上下文退出时自动断开。