|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
×
作者:微信文章
1. 精简介绍
Spring AI MCP(Model Context Protocol,模型上下文协议)是一个旨在标准化大型语言模型(LLM)与外部数据源和工具交互方式的开放协议。它可以被形象地比喻为AI领域的“USB-C接口”,为AI应用与各种外部能力之间搭建了一座标准化的桥梁。通过MCP,Spring AI应用程序能够以统一的接口与不同的数据源和工具进行交互,支持同步和异步通信模式,极大地简化了AI应用与外部服务集成的复杂性,提升了开发效率和系统的可扩展性。
2. MCP 架构与交互流程
Spring AI MCP 的核心在于其 Client-Server 架构,它使得大型语言模型(LLM)能够通过标准化的协议与外部工具和数据源进行交互。整个交互流程可以概括为以下几个关键参与者及其职责:
大型语言模型 (LLM):作为AI应用的核心,LLM负责理解用户意图、生成响应。它通过MCP Client与外部世界进行交互,获取所需上下文信息或调用外部工具。MCP Client:作为LLM与MCP Server之间的桥梁,MCP Client负责处理LLM发出的请求,将其转换为MCP协议规定的格式,并通过各种传输机制(如Stdio、HTTP SSE)发送给MCP Server。它还负责接收MCP Server的响应,并将其转换回LLM可理解的格式。MCP Client还负责协议版本协商、能力协商、工具发现与执行、资源访问与管理等。MCP Server:MCP Server是提供工具、资源和能力的实体。它可以是一个独立的应用程序,也可以是现有服务的一部分。它接收来自MCP Client的请求,执行相应的操作(例如,调用外部API、访问数据库、执行特定业务逻辑),并将结果通过MCP协议返回给MCP Client。MCP Server负责工具暴露与发现、资源管理、Prompt模板处理、能力协商等。
2.1 交互流程概述
图1:Spring AI MCP 交互时序图
时序图分析:
该时序图详细描绘了Spring AI MCP中大模型(LLM)、客户端(Client)和服务器(Server)之间的交互流程。核心流程如下:
客户端发起请求 (User Client -> LLM): 用户首先向大模型发送一个包含用户请求和可能工具定义(Tool Definitions)的提示(Prompt)。这些工具定义告诉大模型它可以使用哪些外部功能。大模型决策与工具调用 (LLM -> Client): 大模型接收到请求后,会根据其内部逻辑判断是否需要调用外部工具来完成任务。如果需要,它会生成一个工具调用请求(Tool Call Request),其中包含要调用的工具名称和参数。这个请求会返回给客户端。客户端执行工具 (Client -> Server): 客户端接收到大模型的工具调用请求后,会解析该请求,并根据请求中的工具名称和参数,向相应的MCP服务器发起工具执行请求(Tool Execution Request)。服务器执行工具并返回结果 : MCP服务器接收到工具执行请求后,会执行实际的业务逻辑(例如,调用外部API、查询数据库等),并将执行结果(Tool Execution Result)返回给客户端。客户端将结果传递给大模型 (Client -> LLM): 客户端收到工具执行结果后,会将这个结果作为新的上下文信息,连同原始请求一起,再次发送给大模型。这使得大模型能够基于工具的执行结果继续生成最终响应。大模型生成最终响应 : 大模型接收到工具执行结果后,会结合这些信息生成最终的用户响应(Final Response),并将其返回给用户。
关键点:
职责分离: 大模型专注于理解意图和生成响应,而具体的功能实现则由MCP服务器负责。客户端作为中间协调者,负责在大模型和MCP服务器之间传递信息。可扩展性: 通过MCP,可以轻松地为大模型添加新的工具和功能,而无需修改大模型本身。只需部署新的MCP服务器或在现有服务器上注册新工具即可。协议标准化: MCP提供了一个标准化的协议,使得不同的大模型和工具服务能够互操作,降低了集成复杂性。
这个时序图清晰地展示了Spring AI MCP如何通过引入一个中间协议层,有效地将大模型的能力与外部世界连接起来,实现了大模型的功能扩展和应用落地。
4. 源码分析
Spring AI MCP 的源码主要围绕 McpClient 和 McpServer 两个核心组件展开,它们分别负责客户端和服务端的逻辑。通过对 spring-ai-mcp 仓库的分析,我们可以深入理解其内部机制。
首先我们先看一下MCP 对象的封装,Spring 他没有做底层的处理,他只是做了上层的封装。这个很重要,核心能力还是要看官网。
此处的代码会很少,因为我觉得在这里看代码不如回到 Idea 中看舒服,此处会标注一些切入点。如果有不对的也希望大家指正。
Spring AI MCP 模块组成:
├── 服务端 (spring-ai-autoconfigure-mcp-server)
│ ├── McpServerAutoConfiguration.java [核心服务配置]
│ ├── McpWebMvcServerAutoConfiguration.java [WebMVC传输]
│ ├── McpWebFluxServerAutoConfiguration.java[WebFlux传输]
│ └── McpServerProperties.java [配置属性]
├── 客户端 (spring-ai-autoconfigure-mcp-client)
│ ├── McpClientAutoConfiguration.java [客户端核心配置]
│ ├── SseHttpClientTransportAutoConfiguration.java [HTTP+SSE传输]
│ └── SseWebFluxTransportAutoConfiguration.java [WebFlux+SSE传输]
└── Starter 模块
├── spring-ai-starter-mcp-server-webmvc
├── spring-ai-starter-mcp-server-webflux
└── spring-ai-starter-mcp-client
4.1 核心类图展示
4.2 核心交互流程
4.3 服务端核心配置类
// McpServerAutoConfiguration.java - 核心自动配置
// @AutoConfiguration 确保你的配置类在指定类after 之后 before之前生效,以避免依赖项还没加载就提前执行的问题。
@AutoConfiguration(after = { McpWebMvcServerAutoConfiguration.class, McpWebFluxServerAutoConfiguration.class })
@ConditionalOnClass({ McpSchema.class, McpSyncServer.class })
@EnableConfigurationProperties(McpServerProperties.class)
public class McpServerAutoConfiguration {
// 关键配置方法
@Bean
@ConditionalOnProperty(name = "type", havingValue = "SYNC", matchIfMissing = true)
public McpSyncServer mcpSyncServer(
McpServerTransportProvider transportProvider,
McpSchema.ServerCapabilities.Builder capabilitiesBuilder,
McpServerProperties serverProperties,
ObjectProvider<List<SyncToolSpecification>> tools) {
// 构建服务器信息
McpSchema.Implementation serverInfo = new Implementation(
serverProperties.getName(),
serverProperties.getVersion()
);
// 创建同步服务器规范
SyncSpecification serverBuilder = McpServer.sync(transportProvider)
.serverInfo(serverInfo);
// 注册工具能力
if (serverProperties.getCapabilities().isTool()) {
List<SyncToolSpecification> toolSpecs = tools.stream()
.flatMap(List::stream).toList();
serverBuilder.tools(toolSpecs);
}
return serverBuilder.build();
}
}// McpWebMvcServerAutoConfiguration.java
@AutoConfiguration
@ConditionalOnClass({ WebMvcSseServerTransportProvider.class })
@ConditionalOnMissingBean(McpServerTransportProvider.class)
public class McpWebMvcServerAutoConfiguration {
@Bean
public WebMvcSseServerTransportProvider webMvcSseServerTransportProvider(
ObjectProvider<ObjectMapper> objectMapperProvider,
McpServerProperties serverProperties) {
return new WebMvcSseServerTransportProvider(
objectMapper,
serverProperties.getBaseUrl(),
serverProperties.getSseMessageEndpoint(), // "/mcp/message"
serverProperties.getSseEndpoint() // "/sse"
);
}
@Bean
public RouterFunction<ServerResponse> mvcMcpRouterFunction(
WebMvcSseServerTransportProvider transportProvider) {
// 这里返回的RouterFunction会注册两个端点:
// GET /sse - 处理SSE连接建立
// POST /mcp/message - 处理客户端消息
return transportProvider.getRouterFunction();
}
}// McpToolUtils.java - 关键的工具转换工具类
public final class McpToolUtils {
public static final String TOOL_CONTEXT_MCP_EXCHANGE_KEY = "exchange";
// 核心转换方法:将Spring AI的ToolCallback转换为MCP工具规范
public static SyncToolSpecification toSyncToolSpecification(
ToolCallback toolCallback, MimeType mimeType) {
// 1. 创建MCP工具定义
var tool = new McpSchema.Tool(
toolCallback.getToolDefinition().name(),
toolCallback.getToolDefinition().description(),
toolCallback.getToolDefinition().inputSchema()
);
// 2. 创建工具执行规范
return new SyncToolSpecification(tool, (exchange, request) -> {
try {
// 3. 调用Spring AI工具回调
String callResult = toolCallback.call(
ModelOptionsUtils.toJsonString(request),
new ToolContext(Map.of(TOOL_CONTEXT_MCP_EXCHANGE_KEY, exchange))
);
// 4. 根据MIME类型包装结果
if (mimeType != null && mimeType.toString().startsWith("image")) {
return new CallToolResult(List.of(
new ImageContent(List.of(Role.ASSISTANT), null, callResult, mimeType.toString())
), false);
}
return new CallToolResult(List.of(new TextContent(callResult)), false);
} catch (Exception e) {
// 5. 错误处理
return new CallToolResult(List.of(new TextContent(e.getMessage())), true);
}
});
}
}
当Spring Boot应用启动时:
启动阶段:Spring Boot扫描到MCP相关的@AutoConfiguration类
条件检查:验证classpath和配置属性
传输层配置:根据依赖选择WebMVC、WebFlux或STDIO传输
服务器构建:收集所有ToolCallback Bean,转换为MCP工具规范
路由注册:注册/sse和/mcp/message端点
服务就绪:MCP服务器启动,等待客户端连接
溜了溜了 |
|