MCP(模型上下文协议:Model Context Protocol)为 AI 应用与外部工具、资源的交互提供了标准化方式。Spring 早期就作为核心贡献者加入 MCP 生态,参与开发并维护官方 MCP Java SDK,为基于 Java 的 MCP 实现奠定基础。在此贡献之上,Spring AI 通过专属的 Boot Starter 与 MCP Java 注解全面支持 MCP,让构建可无缝对接外部系统的复杂 AI 应用变得前所未有的简单。
什么是模型上下文协议(MCP)?
模型上下文协议(MCP)是一套标准化协议,让 AI 模型以结构化方式与外部工具和资源交互。 可以把它看作 AI 模型与现实世界之间的桥梁 — 支持 AI 通过统一接口访问数据库、API、文件系统及其他外部服务。
MCP 客户端 – 服务端架构
MCP 采用客户端 – 服务端架构,职责边界清晰:
- MCP 服务端: 对外暴露第三方服务的特定能力(工具、资源、提示词模板)。
- MCP 客户端: 由宿主应用实例化,用于与指定 MCP 服务端通信;一个客户端只与一个服务端直连。
- 宿主: 用户直接交互的 AI 应用。
MCP 协议保证客户端与服务端之间完全跨语言、无绑定地交互操作。Java、Python、TypeScript 编写的客户端可与任意语言的服务端通信,反之亦然。
该架构自然划分出两类开发者:
1. AI 应用 / 宿主开发者
负责编排多个 MCP 服务端、集成 AI 模型,构建 AI 应用,实现:
- 通过 MCP 客户端消费多个 MCP 服务端能力
- AI 模型集成与提示词工程
- 管理对话上下文与用户交互
- 跨服务编排复杂工作流
2. MCP 服务端(提供方)开发者
专注将第三方服务能力封装为 MCP 服务端,实现:
- 包装数据库、文件系统、外部 API 等
- 通过标准化 MCP 原语(工具、资源、提示词)暴露能力
- 处理服务自身的身份认证与授权
这种分工让:
- 数据库专家可编写 PostgreSQL 的 MCP 服务端,无需懂 LLM 提示词;
- AI 应用开发者可使用该服务端,无需懂 SQL 底层。
MCP 协议就是二者之间的通用语言。
Spring AI 通过 MCP 客户端与MCP 服务端两大 Boot Starter 支持该架构,让 Spring 开发者既能构建消费 MCP 服务的 AI 应用,也能创建暴露 Spring 服务的 MCP 服务端。
MCP 核心能力
MCP 在客户端与服务端之间共享,提供了丰富的功能集,实现了 AI 应用与外部服务之间的无缝通信:
- 暴露可供 AI 模型调用的tools
- 与 AI 应用共享资源和数据
- 提供提示词模板以实现一致交互
- 为提示词和资源 URI 提供参数自动补全建议
- 处理实时通知与进度更新
- 支持客户端侧采样、信息抽取、结构化日志与进度跟踪
- 支持多种传输协议:标准输入输出(STDIO)、流式 HTTP(Streamable-HTTP)以及服务器发送事件(SSE)
可以总结为下表:
| 分类 | 核心功能 |
|---|---|
| 共享能力 | Ping、取消、进度通知、日志 |
| 客户端 | 采样、抽取、完成 |
| 服务端 | 工具、资源、提示词模板、根路径 |
| 传输协议 | STDIO、Streamable-HTTP、SSE |
注意:工具由 LLM 拥有。LLM(而非宿主)决定是否、何时、以何种顺序调用工具;宿主仅控制向 LLM 提供哪些工具描述。
构建 MCP 服务端
以天气查询服务为例,构建一个基于 Streamable-HTTP 的 MCP 服务端。
1. 创建 Spring Boot 服务端应用
|
1 2 3 4 5 6 |
@SpringBootApplication public class McpServerApplication { public static void main(String[] args) { SpringApplication.run(McpServerApplication.class, args); } } |
2. 引入依赖
|
1 2 3 4 |
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId> </dependency> |
3. 配置传输协议
在 application.properties` 中启用 Streamable HTTP:
|
1 |
spring.ai.mcp.server.protocol=STREAMABLE |
以上配置支持:STREAMABLE、STATELESS、SSE;如需 STDIO,设置:
|
1 |
spring.ai.mcp.server.stdio=true |
4. 编写天气服务(注册 MCP 工具)
使用 @McpTool 和 @McpToolParam 注解,将方法注册为 MCP 工具:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@Service public class WeatherService { public record WeatherResponse(Current current) { public record Current(LocalDateTime time, int interval, double temperature_2m) {} } @McpTool(description = "获取指定地点的气温(摄氏度)") public WeatherResponse getTemperature( @McpToolParam(description = "纬度") double latitude, @McpToolParam(description = "经度") double longitude) { return RestClient.create() .get() .uri("https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}¤t=temperature_2m", latitude, longitude) .retrieve() .body(WeatherResponse.class); } } |
5. 构建并运行
|
1 2 |
./mvnw clean install -DskipTests java -jar target/mcp-weather-server-0.0.1-SNAPSHOT.jar |
使用 MCP 服务端
使用方式
方式 1:MCP Inspector(调试工具)
|
1 |
npx @modelcontextprotocol/inspector |
设置:
- Transport Type:Streamable HTTP
- URL:
http://localhost:8080/mcp点击 Connect,即可列出并调用 getTemperature 工具。
方式 2:Java SDK 直连
调用方式如下:
|
1 2 3 4 5 6 7 8 9 10 11 |
var client = McpClient.sync( HttpClientStreamableHttpTransport .builder("http://localhost:8080").build()) .build(); client.initialize(); CallToolResult weather = client.callTool( new CallToolRequest("getTemperature", Map.of("latitude", "47.6062", "longitude", "-122.3321"))); |
方式 3:接入 Claude Desktop
在配置中添加:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "mcpServers": { "spring-ai-mcp-weather": { "command": "java", "args": [ "-Dspring.ai.mcp.server.stdio=true", "-Dspring.main.web-application-type=none", "-jar", "/path/to/mcp-weather-server-0.0.1.jar" ] } } } |
服务端高级特性:日志、进度、采样
我们扩展天气服务,演示三大高级能力:
- 结构化日志: 向客户端发送调试日志
- 进度跟踪: 长任务实时上报进度
- 采样(Sampling): 服务端请求客户端 LLM 生成内容(双向 AI 交互)
在这个增强版本中,天气服务端会将操作日志发送给客户端以保证透明性,在获取和处理天气数据的过程中上报进度,并请求客户端的大语言模型来实现诗歌化描述的天气预报。
下面是更新后的实现版本:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
@Service public class WeatherService { public record WeatherResponse(Current current) { public record Current(LocalDateTime time, int interval, double temperature_2m) {} } @McpTool(description = "获取指定地点气温") public String getTemperature( McpSyncServerExchange exchange, @McpToolParam double latitude, @McpToolParam double longitude, @McpProgressToken String progressToken) { // 1. 发送日志 exchange.loggingNotification(LoggingMessageNotification.builder() .level(LoggingLevel.DEBUG) .data("调用 getTemperature:" + latitude + ", " + longitude) .build()); WeatherResponse weatherResponse = RestClient.create() .get() .uri("https://api.open-meteo.org/...") .retrieve() .body(WeatherResponse.class); String epicPoem = "客户端不支持采样"; // 2. 支持采样则请求 LLM if (exchange.getClientCapabilities().sampling() != null) { exchange.progressNotification(new ProgressNotification(progressToken, 0.5, 1.0, "开始生成天气诗")); String prompt = "气温:%s℃,经纬度:%s/%s,用莎士比亚风格写一首天气诗".formatted( weatherResponse.current().temperature_2m(), latitude, longitude); CreateMessageResult samplingResponse = exchange.createMessage(CreateMessageRequest.builder() .systemPrompt("你是诗人") .messages(List.of(new SamplingMessage(Role.USER, new TextContent(prompt)))) .build()); epicPoem = ((TextContent) samplingResponse.content()).text(); } // 3. 完成进度 exchange.progressNotification(new ProgressNotification(progressToken, 1.0, 1.0, "任务完成")); return "天气:%s\n气温:%s℃".formatted(epicPoem, weatherResponse.current().temperature_2m()); } } |
关键点说明:
- McpSyncServerExchange: exchange 参数提供了服务端与客户端之间的通信能力,允许服务端向客户端发送通知并发起反向请求。
- @ProgressToken: progressToken 参数用于实现进度跟踪。该令牌由客户端提供,服务端通过它来发送进度更新。
- 日志通知: 向客户端发送结构化日志消息,用于调试与监控。
- 进度更新: 向客户端上报操作进度(本例中为 50%)并附带描述性信息。
- 采样能力: 这是最强大的特性:服务端可以请求客户端的大语言模型生成内容。
以上这些能力使得服务端能够利用客户端的 AI 能力,形成双向 AI 交互模式。
增强版的天气服务现在不仅会返回天气数据,还会生成一段关于天气预报的创意诗歌,充分展现了 MCP 服务端与 AI 模型之间强大的协同能力。
构建 MCP 客户端
构建一个连接 MCP 服务端的 AI 应用。
1. 客户端依赖
使用以下依赖构建一个 springboot 项目:
|
1 2 3 4 5 6 7 8 |
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-client</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-anthropic</artifactId> </dependency> |
2. 配置连接
在配置文件中,创建和 MCP 服务端的连接:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
spring: main: web-application-type: none ai: anthropic: api-key: ${ANTHROPIC_API_KEY} mcp: client: streamable-http: connections: my-weather-server: url: http://localhost:8080 |
注意: 在配置文件中,把“my-weather-server“这个名称分配给了服务端连接。
3. SpringBoot 客户端应用
使用ChatClient创建一个客户端应用,这个应用会连接到 LLM 以及 MCP 天气服务端:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
@SpringBootApplication public class McpClientApplication { public static void main(String[] args) { SpringApplication.run(McpClientApplication.class, args).close(); } @Bean public ChatClient chatClient(ChatClient.Builder builder) { return builder.build(); } String prompt = "查询阿姆斯特丹当前天气,并给出创意回答!"; @Bean public CommandLineRunner run(ChatClient chatClient, ToolCallbackProvider mcpToolProvider) { return args -> System.out.println( chatClient.prompt(prompt) .toolContext(Map.of("progressToken", "token-" + new Random().nextInt())) .toolCallbacks(mcpToolProvider) .call() .content()); } } |
简单解释下上面的代码:
- 应用生命周期管理: 应用启动后执行天气查询、展示结果,随后正常退出。
- ChatClient 配置: 使用 Spring AI 自动配置的构建器创建已配置好的 ChatClient Bean。构建器会自动加载以下内容:
- AI 模型配置(本例中为 Anthropic Claude)
- 来自 application.properties 的默认设置与配置项
- CommandLineRunner: 在应用上下文完全加载后自动运行。它会注入已配置好的 ChatClient 用于与 AI 模型交互,同时注入
ToolCallbackProvider,其中包含来自已连接服务端的所有已注册 MCP 工具。 - AI 提示词: 指示 AI 模型获取阿姆斯特丹当前天气。AI 模型会根据提示词自动发现并调用合适的 MCP 工具。
- 进度令牌: 通过
toolContext向带有@McpProgressToken注解参数的 MCP 工具传递唯一的进度令牌。 - MCP 工具集成: 这一关键步骤将 ChatClient 与所有可用的 MCP 工具连接起来:
mcpToolProvider由 Spring AI 的 MCP 客户端启动器自动配置- 包含来自所有已连接 MCP 服务端的工具(通过
spring.ai.mcp.client.*.connections.配置) - AI 模型可在对话过程中自动发现并调用这些工具
4. 客户端处理器(接收服务端通知)
这里会创建一个 Handler 服务类,用于处理来自服务端的 MCP 通知与请求。这些处理器是我们上文实现的服务端高级特性在客户端侧的对应实现,用于实现 MCP 服务端与客户端之间的双向通信。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
@Service public class McpClientHandlers { private final ChatClient chatClient; public McpClientHandlers(@Lazy ChatClient chatClient) { this.chatClient = chatClient; } // 进度回调 @McpProgress(clients = "my-weather-server") public void progress(ProgressNotification notification) { System.out.println("进度:" + notification.progress()); } // 日志回调 @McpLogging(clients = "my-weather-server") public void logging(LoggingMessageNotification msg) { System.out.println("日志:" + msg.data()); } // 采样回调(最核心) @McpSampling(clients = "my-weather-server") public CreateMessageResult sampling(CreateMessageRequest req) { String resp = chatClient.prompt() .system(req.systemPrompt()) .user(((TextContent)req.messages().get(0).content()).text()) .call() .content(); return CreateMessageResult.builder().content(new TextContent(resp)).build(); } } |
解释下这个 Handler 组件:
- 进度处理器: 接收来自服务端耗时操作的实时进度更新。当服务端调用
exchange.progressNotification(...)时触发。例如,天气服务端在开始生成诗歌时发送 50% 进度,完成后发送 100% 进度。常用于展示进度条、更新 UI 状态或记录操作进度。 - 日志处理器: 接收来自服务端的结构化日志消息,用于调试与监控。当服务端调用
exchange.loggingNotification(...)时触发。例如天气服务端会记录:“调用 getTemperature 工具,纬度:X,经度:Y”。可用于服务端操作调试、审计追踪或监控面板展示。 - 采样处理器: 核心最强特性,允许服务端向客户端的大语言模型请求 AI 生成内容,用于实现双向 AI 交互、创意内容生成与动态应答。当服务端完成采样能力检查并调用
exchange.createMessage(...)时触发。执行流程如下:- 若客户端支持采样,则向其请求一首关于天气的诗歌
- 客户端处理器接收请求,通过自身的 ChatClient 调用 LLM 生成诗歌
- 生成的诗歌返回给服务端,并整合到最终的工具响应中
关键设计模式
1. 基于注解的路由
通过 clients = "my-weather-server" 属性,确保处理器只处理来自配置中指定 MCP 服务端连接的通知:
|
1 |
spring.ai.mcp.client.streamable-http.connections.[my-weather-server].url |
如果应用需要连接多个 MCP 服务端,可使用 clients 属性为每个 Handler 指定对应的 MCP 客户端:
|
1 2 3 4 5 6 7 8 9 10 11 |
// 处理来自多个服务端的进度 @McpProgress(clients = {"weather-server", "database-server"}) public void multiServerProgressHandler(ProgressNotification notification) { // 处理来自两个服务端的进度 } // 仅处理来自特定服务端的采样请求 @McpSampling(clients = "specialized-ai-server") public CreateMessageResult specializedSamplingHandler(CreateMessageRequest request) { // 处理专用 AI 服务端的采样请求 } |
在 ChatClient 上使用 @Lazy 注解,可避免因 ChatClient 与 MCP 组件相互依赖而产生的循环依赖问题。
2. 双向AI通信
采样处理器实现了一种强大的交互模式:
- 服务端(领域专家)可以利用客户端的 AI 能力
- 客户端的 LLM 根据服务端提供的上下文生成创意内容
这使得 AI 之间可以实现复杂的交互,而不再局限于简单的工具调用。
该架构让 MCP 客户端成为服务端操作中的主动响应方,支持更复杂的交互逻辑,而不仅仅是被动地使用工具。
连接多个 MCP 服务端
同时连接天气服务与Brave 搜索服务:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
spring: ai: mcp: client: streamable-http: connections: my-weather-server: url: http://localhost:8080 stdio: connections: brave-search: command: npx args: ["-y", "@modelcontextprotocol/server-brave-search"] |
现在可以用一行提示词让大模型整合天气数据以及网络搜索结果,提示词示例:
|
1 |
查询阿姆斯特丹天气并创意展示,然后搜索诗歌出版社,列出前3名。 |
构建和运行
确保 MCP 天气服务端已经准备好并正常运行。
使用如下指令构建并启动客户端:
|
1 2 3 |
./mvnw clean install -DskipTests java -jar target/mcp-weather-client-0.0.1-SNAPSHOT.jar |
结论
Spring 成熟的开发模式 + MCP 标准化协议 = 下一代 AI 应用的强大基石。无论构建聊天机器人、数据分析工具还是开发助手,Spring AI 的 MCP 支持都提供了所需的全部基础组件。
参考资料
- MCP Specification – MCP官方协议文档
- SpringAI MCP 概览 – 包含整体架构和基础概念
- SpringAI MCP Java注解 – MCP客户端和服务端基于注解的方法处理
- 原文档:Spring AI’s MCP Boot Starters
END!!