Spring AI 搭建 MCP
·
一、MCP 概念介绍
1.1 什么是 MCP?
MCP (Model Context Protocol) 是由 Anthropic 提出的一个开放协议,用于标准化 AI 模型与外部工具、数据源之间的交互方式。它提供了一种统一的接口,让 AI 模型能够安全、可控地访问外部资源。
1.2 MCP 的核心优势
| 特性 | 说明 |
|---|---|
| 标准化 | 提供统一的工具定义和调用规范 |
| 解耦 | 工具服务与 AI 应用独立部署、独立扩展 |
| 安全 | 工具调用经过明确的权限控制和参数校验 |
| 可扩展 | 支持动态添加新工具,无需修改 AI 应用代码 |
| 复用 | 同一个 MCP 服务可被多个 AI 应用共享使用 |
1.3 MCP 架构
┌─────────────────────────────────────────────────────────────────┐
│ AI 应用 (MCP Client) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ ChatClient │───▶│ ChatModel │───▶│ ToolCallbackProvider │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└────────────────────────────────┬────────────────────────────────┘
│ SSE (Server-Sent Events)
▼
┌─────────────────────────────────────────────────────────────────┐
│ MCP Server (工具服务) │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ ToolCallbackProvider ││
│ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ││
│ │ │ WeatherService │ │ OtherService │ │ AnotherTool │ ││
│ │ │ @Tool方法 │ │ @Tool方法 │ │ @Tool方法 │ ││
│ │ └───────────────┘ └───────────────┘ └───────────────┘ ││
│ └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
1.4 MCP 通信方式
MCP 支持两种主要通信方式:
- SSE (Server-Sent Events) - 基于 HTTP 的服务端推送,适合 Web 应用
- Stdio - 基于标准输入输出,适合本地进程间通信
二、Spring AI Tool 使用指南
2.1 核心注解
@Tool 注解
用于标记一个方法为可被 AI 调用的工具。
@Tool(description = "工具功能的详细描述")
public ReturnType toolMethod(@ToolParam(description = "参数说明") String param) {
// 工具实现
}
属性说明:
description:工具功能的描述,AI 会根据此描述决定是否调用该工具
@ToolParam 注解
用于描述工具方法的参数。
@ToolParam(description = "参数的详细说明,帮助 AI 理解参数含义", required = true)
String paramName
属性说明:
description:参数描述required:是否必需参数(默认 true)
2.2 ToolCallbackProvider
Spring AI 提供了 ToolCallbackProvider 接口,用于将工具方法注册到 AI 模型。
@Bean
public ToolCallbackProvider myTools(MyService myService) {
return MethodToolCallbackProvider.builder()
.toolObjects(myService) // 注册整个服务对象
.build();
}
2.3 工具调用流程
用户输入 ──▶ AI 分析 ──▶ 决定调用工具 ──▶ 执行工具方法 ──▶ 返回结果 ──▶ AI 生成回答
三、MCP 服务端实现
3.1 项目结构
weather-mcp-server/
├── src/main/java/com/ai/weather/mcp/
│ ├── WeatherMcpServerApplication.java # 启动类
│ ├── config/
│ │ └── ToolCallbackProviderConfig.java # 工具注册配置
│ ├── model/
│ │ └── WeatherResponse.java # 响应模型
│ └── service/
│ └── WeatherService.java # 天气服务(工具实现)
└── src/main/resources/
└── application.yml # 配置文件
3.2 Maven 依赖
<properties>
<java.version>17</java.version>
<spring-ai.version>1.0.1</spring-ai.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MCP Server 依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3.3 配置文件
server:
port: 8889
spring:
ai:
mcp:
server:
name: weather-mcp-server # MCP 服务名称
sse-message-endpoint: /mcp/weather # SSE 端点路径
logging:
level:
com.ai.weather.mcp: DEBUG
3.4 工具服务实现
package com.ai.weather.mcp.service;
import com.ai.weather.mcp.model.WeatherResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
@Slf4j
@Service
@RequiredArgsConstructor
public class WeatherService {
private static final String WEATHER_API_URL = "https://uapis.cn/api/v1/misc/weather";
private final ObjectMapper objectMapper = new ObjectMapper();
private final HttpClient httpClient = HttpClient.newHttpClient();
@Tool(description = "查询指定城市的天气信息,返回温度、湿度、风向、天气状况等详细信息")
public WeatherResponse getWeather(
@ToolParam(description = "城市名称,如:北京、上海、广州、深圳等") String city) {
try {
log.info("正在查询城市天气: {}", city);
String url = UriComponentsBuilder.fromHttpUrl(WEATHER_API_URL)
.queryParam("city", city)
.build()
.encode()
.toUriString();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.GET()
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
WeatherResponse weatherResponse = objectMapper.readValue(
response.body(), WeatherResponse.class);
log.info("天气查询成功: {}", weatherResponse);
return weatherResponse;
} else {
log.error("天气查询失败,状态码: {}", response.statusCode());
throw new RuntimeException("天气查询失败,状态码: " + response.statusCode());
}
} catch (Exception e) {
log.error("查询天气时发生错误: {}", e.getMessage(), e);
throw new RuntimeException("查询天气时发生错误: " + e.getMessage(), e);
}
}
}
3.5 工具注册配置
package com.ai.weather.mcp.config;
import com.ai.weather.mcp.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;
@Configuration
public class ToolCallbackProviderConfig {
@Bean
public ToolCallbackProvider livingCityTools(WeatherService weatherService) {
return MethodToolCallbackProvider.builder()
.toolObjects(weatherService) // 注册 WeatherService 中的所有 @Tool 方法
.build();
}
}
3.6 响应模型
package com.ai.weather.mcp.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class WeatherResponse {
private String province;
private String city;
private String adcode;
private String weather;
@JsonProperty("weather_icon")
private String weatherIcon;
private Integer temperature;
@JsonProperty("wind_direction")
private String windDirection;
@JsonProperty("wind_power")
private String windPower;
private Integer humidity;
@JsonProperty("report_time")
private String reportTime;
}
3.7 日志
启动时,会打印已注册的工具数
2026-03-19T16:27:11.990+08:00 INFO 3528 --- [ main] o.s.a.m.s.a.McpServerAutoConfiguration : Enable tools capabilities, notification: true
2026-03-19T16:27:12.025+08:00 INFO 3528 --- [ main] o.s.a.m.s.a.McpServerAutoConfiguration : Registered tools: 1
四、MCP 客户端实现
4.1 项目结构
spring-ai/
├── src/main/java/com/ai/springai/
│ ├── SpringAiApplication.java # 启动类
│ ├── config/
│ │ └── ChatConfig.java # ChatClient 配置
│ └── controller/
│ └── WeatherController.java # 天气对话接口
└── src/main/resources/
└── application.yml # 配置文件
4.2 Maven 依赖
<properties>
<java.version>17</java.version>
<spring-ai.version>1.0.1</spring-ai.version>
</properties>
<dependencies>
<!-- MCP Client 依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>
<!-- OpenAI 模型支持 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
4.3 配置文件
server:
port: 8888
spring:
ai:
mcp:
client:
sse:
connections:
weather-service: # 连接名称(自定义)
url: http://localhost:8889 # MCP Server 地址
toolcallback:
enabled: true # 启用工具回调
openai:
base-url: https://ark.cn-beijing.volces.com/api/v3
api-key: your-api-key
chat:
options:
model: doubao-seed-2-0-code-preview-260215
logging:
level:
org.springframework.ai: debug
关键配置说明:
| 配置项 | 说明 |
|---|---|
spring.ai.mcp.client.sse.connections | MCP Server 连接配置 |
spring.ai.mcp.client.toolcallback.enabled | 是否自动注册 MCP 工具到 ChatClient |
spring.ai.mcp.client.sse.connections.xxx.url | MCP Server 的地址 |
4.4 ChatClient 配置
package com.ai.springai.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
@Slf4j
@Configuration
public class ChatConfig {
@Value("${spring.ai.openai.base-url}")
private String baseUrl;
@Value("${spring.ai.openai.api-key}")
private String apiKey;
@Value("${spring.ai.openai.chat.options.model}")
private String model;
@Bean
public OpenAiApi openAiApi() {
return OpenAiApi.builder()
.baseUrl(baseUrl)
.apiKey(apiKey)
.completionsPath("/chat/completions")
.embeddingsPath("/embeddings")
.build();
}
@Bean
public ChatModel chatModel(OpenAiApi openAiApi) {
OpenAiChatOptions options = OpenAiChatOptions.builder()
.model(model)
.build();
return OpenAiChatModel.builder()
.openAiApi(openAiApi)
.defaultOptions(options)
.build();
}
@Bean
public ChatClient chatClient(ChatModel chatModel,
List<ToolCallbackProvider> toolCallbackProviders) {
log.debug("初始化ChatClient...");
ChatClient.Builder builder = ChatClient
.builder(chatModel)
.defaultSystem("你是一个智能助手,帮助用户解决问题。你可以使用天气工具查询城市的天气信息。");
// 注册所有工具回调(包括 MCP Client 自动提供的工具)
for (ToolCallbackProvider provider : toolCallbackProviders) {
builder.defaultToolCallbacks(provider.getToolCallbacks());
}
return builder.build();
}
}
4.5 控制器实现
package com.ai.springai.controller;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@Slf4j
@RestController
@RequestMapping("/ai")
@RequiredArgsConstructor
public class WeatherController {
private final ChatClient chatClient;
@GetMapping(value = "/weather/chat", produces = "text/html;charset=utf-8")
public Flux<String> weatherChat(@RequestParam String prompt) {
log.info("用户询问天气: {}", prompt);
return chatClient.prompt()
.user(prompt)
.stream()
.content();
}
}
五、调用示例
5.1 启动服务
步骤 1:启动 MCP Server(天气服务)
cd weather-mcp-server
mvn spring-boot:run
服务启动在 http://localhost:8889
步骤 2:启动 MCP Client(AI 应用)
cd spring-ai
mvn spring-boot:run
服务启动在 http://localhost:8888
5.2 API 调用
请求示例
GET http://localhost:8888/ai/weather/chat?prompt=北京今天天气怎么样
5.3 调用流程详解
1. 用户发送请求
└── GET /ai/weather/chat?prompt=北京今天天气怎么样
2. Controller 调用 Spring AI ChatClient
└──此处Spring AI会构建请求(ChatCompletionRequest request = createRequest(prompt, true);)
{
"messages" : [ {
"content" : "你是一个智能助手,帮助用户解决问题,不要脱离这个设定。你可以使用天气工具查询城市的天气信息。",
"role" : "SYSTEM"
}, {
"content" : "北京今天天气怎么样",
"role" : "USER"
} ],
"model" : "doubao-seed-2-0-code-preview-260215",
"stream" : true,
"tools" : [ {
"function" : {
"description" : "查询指定城市的天气信息,返回温度、湿度、风向、天气状况等详细信息",
"name" : "spring_ai_mcp_client_weather_service_getWeather",
"parameters" : {
"additionalProperties" : false,
"type" : "object",
"properties" : {
"city" : {
"type" : "string",
"description" : "城市名称,如:北京、上海、广州、深圳等"
}
},
"required" : [ "city" ]
}
},
"type" : "FUNCTION"
} ]
}
3. MCP Client(启动时)已完成:
└── 建立 SSE 连接
└── 拉取 tools
└── 注册到 ToolCallingManager
└── 工具名转换:
getWeather → spring_ai_mcp_client_weather_service_getWeather
4. AI 分析用户意图
└── 判断需要调用工具(天气查询)
5. AI 返回 Tool Call(不是直接执行)
{
"choices": [
{
"delta": {
"content": "",
"role": "assistant",
"tool_calls": [
{
"function": {
"arguments": "",
"name": "spring_ai_mcp_client_weather_service_getWeather"
},
"id": "call_cs71398kwr3uxqkcs6wso4xe",
"index": 0,
"type": "function"
}
]
},
"index": 0
}
],
"created": 1773915311,
"id": "021773915303316a865bad2195e810a7735887290a9a7b686b37d",
"model": "doubao-seed-2-0-code-preview-260215",
"service_tier": "default",
"object": "chat.completion.chunk",
"usage": null
}
└── spring_ai_mcp_client_weather_service_getWeather(city="北京")
6. Spring AI ToolCallingManager 执行工具
└── 打印日志:
Executing tool call: spring_ai_mcp_client_weather_service_getWeather
7. MCP Client 发起远程调用
└── POST http://localhost:8889/sse
└── tool = getWeather
8. MCP Server 接收请求
└── 路由到 @Tool 方法
9. 执行业务逻辑
└── WeatherService.getWeather("北京")
10. 返回 WeatherResponse
11. Spring AI 接收 ToolResult
12. 再次调用大模型(关键步骤)
└── 将 ToolResult 注入上下文
13. AI 生成最终自然语言回答
14. 通过 SSE 流式返回给用户
5.4 响应
客户端:
2026-03-19T16:47:46.558+08:00 INFO 25284 --- [nio-8888-exec-1] c.a.s.controller.WeatherController : 用户询问天气: 北京今天天气怎么样
2026-03-19T16:48:07.954+08:00 DEBUG 25284 --- [oundedElastic-2] o.s.a.m.tool.DefaultToolCallingManager : Executing tool call: spring_ai_mcp_client_weather_service_getWeather
mcp服务端:
2026-03-19T16:48:07.970+08:00 INFO 3528 --- [oundedElastic-1] c.ai.weather.mcp.service.WeatherService : 正在查询城市天气: 北京
2026-03-19T16:48:08.219+08:00 INFO 3528 --- [oundedElastic-1] c.ai.weather.mcp.service.WeatherService : 天气查询成功: WeatherResponse(province=北京市, city=北京, adcode=110000, weather=晴, weatherIcon=100, temperature=16, windDirection=南风, windPower=2级, humidity=9, reportTime=2026-03-19 15:57:48)
响应:
北京今天天气晴朗,气温25℃,湿度45%,东南风3级。总体来说是个不错的天气,适合外出活动。
更多推荐



所有评论(0)