MCP(Model Context Protocol)本质是标准化的 LLM 工具调用交互规范,核心目标是让 AI 工具(如 Claude Desktop、IDE 插件)安全、高效地调用封装了本地 / 远程资源的 “能力服务”,其实现逻辑与 Function Call 一致,但更强调 “通信协议标准化” 和 “多场景适配(本地 / 远程)”。
MCP 是一个开放协议,它标准化了应用程序如何向大语言模型(LLMs)提供上下文。
MCP 核心角色
MCP 的实现依赖 5 个核心角色,各角色分工明确,共同完成 “工具调用” 闭环:
角色 | 核心职责 | 示例 |
MCP 主机(Host) | 发起工具调用需求的 “业务方”,即 MCP 能力的使用者 | Trae、Claude Desktop、IDE 插件、AI 问答工具 |
MCP 客户端(Client) | 遵循 MCP 协议的 “通信代理”,负责与 MCP 服务器建立连接、传递调用请求、接收结果 | 基于 stdio/SSE 的 Spring AI 客户端 |
MCP 服务器(Server) | 封装 “工具能力” 的 “服务提供方”,暴露可调用的工具(如天气查询、数据库访问) | 本地嵌入式服务、远程 HTTP 服务 |
本地数据源 | MCP 服务器可安全访问的本地资源(避免 Host 直接操作) | 本地文件、MySQL 数据库、本地 API |
远程服务 | MCP 服务器可调用的外部互联网服务 | 天气 API(OpenMeteo)、支付接口 |
MCP 两种实现方式
- 基于 stdio(标准输入输出)
- 适用场景:嵌入式、单机部署,客户端直接启动服务端子进程。
- 特点:轻量、无网络依赖,适合本地工具(如文件读取、系统命令)。
- 实现关键:
- 服务端需设置
spring.main.web-application-type=none - 启动参数包含
-Dspring.ai.mcp.server.stdio=true - 客户端通过
StdioClientTransport管理子进程 。
- 服务端需设置
- 基于 SSE(Server-Sent Events)
- 适用场景:远程服务、多客户端共享、云原生部署。
- 特点:基于 HTTP/HTTPS,可跨网络调用,支持负载均衡。
- 实现关键:
- 服务端作为 WebFlux 应用运行在指定端口(如 8080)
- 客户端通过
WebFluxSseClientTransport连接
两种方式在业务逻辑层完全一致——都通过@Tool注解暴露方法
MCP 客户端实现
客户端的核心是 “按协议与服务器通信”,分为本地 stdio 模式(同一机器,子进程交互)和远程 SSE 模式(跨机器,HTTP 交互),两者实现差异集中在 “连接方式” 和 “配置”。
本地 stdio 模式(适合嵌入式场景)
核心特点
客户端与服务器在同一台机器,客户端通过 “启动服务器子进程”,用标准输入输出流(stdio)通信,无需网络,延迟低。
实现步骤
- 添加依赖(Spring AI MCP 客户端 starter)
<!-- 本地stdio模式依赖 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId> </dependency>- 配置服务器(application.yml + JSON 配置文件)
- application.yml:指定服务器配置文件路径,或直接配置启动命令
spring: ai: dashscope: # 若调用远程LLM(如通义千问),配置API密钥 api-key: ${DASH_SCOPE_API_KEY} mcp: client: stdio: # 方式1:指定服务器配置文件(推荐,分离配置) servers-configuration: classpath:/mcp-servers-config.json # 方式2:直接配置(适合简单场景) # connections: # server1: # command: java # args: [-jar, /path/to/mcp-server.jar]- mcp-servers-config.json:定义服务器启动参数(如命令、JVM 参数)
{ "mcpServers": { "weather-server": { # 服务器名称(自定义) "command": "java", # 启动命令 "args": [ "-Dspring.ai.mcp.server.stdio=true", # 启用stdio模式 "-Dspring.main.web-application-type=none", # 禁用Web服务(本地子进程) "-jar", "/path/to/weather-mcp-server.jar" # 服务器Jar包路径 ], "env": {} # 可选:环境变量(如数据库密码) } } }- 代码实现:构建 ChatClient,注入 MCP 工具
@SpringBootApplication public class McpStdioClientApplication { public static void main(String[] args) { SpringApplication.run(McpStdioClientApplication.class, args); } // 注入工具和ChatClient,执行查询 @Bean public CommandLineRunner runTool( ChatClient.Builder chatClientBuilder, ToolCallbackProvider tools, // MCP工具自动注入 ConfigurableApplicationContext context) { return args -> { // 1. 构建支持MCP工具的ChatClient ChatClient chatClient = chatClientBuilder .defaultTools(tools) // 注入MCP服务器的工具(如天气查询) .build(); // 2. 调用工具:查询北京天气(触发MCP客户端向服务器发请求) String userQuery = "北京的天气如何?"; System.out.println(">>> 问题:" + userQuery); String result = chatClient.prompt(userQuery).call().content(); System.out.println(">>> 结果:" + result); context.close(); }; } }远程 SSE 模式(适合多客户端共享场景)
核心特点
服务器独立部署(如远程服务器、云服务),客户端通过Server-Sent Events(SSE)协议(HTTP 长连接)与服务器通信,支持多客户端同时调用。
实现步骤
- 添加依赖(支持 SSE 的 MCP 客户端 starter)
<!-- 远程SSE模式依赖 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-client</artifactId> </dependency>- 配置服务器(仅需指定远程 URL)
spring: ai: dashscope: api-key: ${DASH_SCOPE_API_KEY} mcp: client: sse: connections: weather-server: # 服务器名称 url: http://localhost:8080 # 远程MCP服务器地址(SSE服务端口)- 代码实现:与 stdio 模式完全一致(协议透明化)
@SpringBootApplication public class McpSseClientApplication { public static void main(String[] args) { SpringApplication.run(McpSseClientApplication.class, args); } @Bean public CommandLineRunner runTool( ChatClient.Builder chatClientBuilder, ToolCallbackProvider tools, ConfigurableApplicationContext context) { return args -> { // 代码与stdio模式完全相同,Spring AI自动处理SSE通信 ChatClient chatClient = chatClientBuilder.defaultTools(tools).build(); String result = chatClient.prompt("北京天气?").call().content(); System.out.println(">>> SSE模式结果:" + result); context.close(); }; } }MCP 服务器实现
服务器的核心是 “将能力封装为可调用的工具”,通过@Tool注解标记方法,让客户端自动发现并调用,同样支持 stdio 和 SSE 两种部署模式。
本地 stdio 模式(嵌入式服务器)
核心特点
作为客户端的 “子进程” 启动,无独立端口,禁用 Web 服务,适合本地资源访问(如本地文件、数据库)。
实现步骤:
- 添加依赖(stdio 模式服务器 starter)
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server-webflux</artifactId> </dependency>- 配置服务器(禁用 Web,启用 stdio)
spring: main: web-application-type: none # 关键:禁用Web服务(嵌入式子进程) banner-mode: off # 关闭启动日志(减少干扰) ai: mcp: server: stdio: true # 启用stdio模式 name: weather-stdio-server # 服务器名称(客户端需匹配) version: 0.0.1 # 版本号(用于兼容性判断)- 封装工具:用
@Tool标记可调用方法
// 服务类:封装天气查询能力(调用远程天气API) @Service public class WeatherToolService { private final WebClient webClient; // 注入WebClient,用于调用远程天气API public WeatherToolService(WebClient.Builder webClientBuilder) { this.webClient = webClientBuilder.baseUrl("https://api.open-meteo.com/v1").build(); } /** * 工具1:根据经纬度查天气预报 * @Tool:标记为MCP工具,description供客户端识别功能 * @ToolParameter:描述参数,帮助客户端传递正确值 */ @Tool(description = "根据经纬度获取实时天气预报(温度、风速)") public String getWeather( @ToolParameter(description = "纬度,示例:39.9042(北京)") String latitude, @ToolParameter(description = "经度,示例:116.4074(北京)") String longitude) { try { // 调用远程天气API String apiResult = webClient.get() .uri(uri -> uri.path("/forecast") .queryParam("latitude", latitude) .queryParam("longitude", longitude) .queryParam("current", "temperature_2m,wind_speed_10m") .build()) .retrieve() .bodyToMono(String.class) .block(); // 格式化结果(实际项目需解析JSON) return "北京天气:\n" + apiResult; } catch (Exception e) { return "查询失败:" + e.getMessage(); } } /** 工具2:根据经纬度查空气质量(模拟数据) */ @Tool(description = "根据经纬度获取空气质量(PM2.5、AQI)") public String getAirQuality( @ToolParameter(description = "纬度") String latitude, @ToolParameter(description = "经度") String longitude) { return "北京空气质量:\nPM2.5: 15 μg/m³(优)\nAQI: 42"; } }- 注册工具:让服务器识别并暴露工具
@SpringBootApplication public class McpStdioServerApplication { public static void main(String[] args) { SpringApplication.run(McpStdioServerApplication.class, args); } // 注册工具:将WeatherToolService中的@Tool方法暴露给客户端 @Bean public ToolCallbackProvider weatherTools(WeatherToolService weatherToolService) { return MethodToolCallbackProvider.builder() .toolObjects(weatherToolService) // 传入工具类实例 .build(); } }远程 SSE 模式(独立服务器)
核心特点
作为独立 Web 服务启动(有端口),支持多客户端远程调用,适合共享能力(如团队内共用的数据库查询工具)。
实现步骤
- 添加依赖(同 stdio 模式,需 WebFlux 支持 SSE)
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server-webflux</artifactId> </dependency>- 配置服务器(指定端口,启用 SSE)
server: port: 8080 # 独立服务端口(客户端需配置此地址) spring: ai: mcp: server: name: weather-sse-server # 服务器名称 version: 0.0.1 # 无需配置stdio=true(默认启用SSE)- 工具封装与注册:与 stdio 模式完全一致
工具类(WeatherToolService)和注册代码(ToolCallbackProvider)与 stdio 模式相同,Spring AI 自动通过 SSE 协议暴露工具。
- 启动服务器:独立运行
# 打包 mvn clean package -DskipTests # 启动(独立进程) java -jar target/weather-sse-server.jarMCP 客户端与服务器交互流程
两种模式的交互逻辑差异集中在 “连接建立方式”,核心工具调用流程一致(请求→处理→响应)。
stdio 模式交互(本地子进程)
- 客户端启动时,读取
mcp-servers-config.json,执行java -jar命令启动服务器子进程; - 客户端通过 “标准输入流” 向服务器发送工具调用请求(如
getWeather(latitude=39.9042, longitude=116.4074)); - 服务器执行
@Tool方法,通过 “标准输出流” 将结果返回给客户端; - 客户端将结果传递给 Host(如 AI 工具),生成最终回答。
SSE 模式交互(远程 HTTP)
- 客户端启动时,通过配置的
http://localhost:8080建立 SSE 长连接; - 客户端通过 HTTP 请求发送工具调用参数,服务器接收后执行
@Tool方法; - 服务器通过 SSE 流将结果推送给客户端(无需客户端轮询);
- 客户端接收结果,传递给 Host。
MCP 的本质
MCP 与 LLM 的 Function Call 核心目标一致(让 AI 调用外部工具),但 MCP 是更具象的 “交互协议规范”,两者差异如下:
维度 | Function Call(如 OpenAI 函数调用) | MCP(模型上下文协议) |
核心定位 | 工具调用能力(LLM 侧定义) | 工具调用的 “通信 + 封装” 标准化规范 |
通信方式 | 依赖 LLM API(如 OpenAI API) | 支持 stdio(本地)、SSE(远程)两种模式 |
能力封装 | 需手动定义函数 Schema | 用 注解自动封装,无需手动写 Schema |
部署场景 | 多为远程 API 调用 | 支持本地嵌入式、远程共享两种场景 |
安全隔离 | 无明确隔离(Host 直接调用工具) | 服务器隔离 Host 与数据源(Host 不直接操作本地资源) |
结论:MCP 是 Function Call 的 “工业化实现”—— 它将 Function Call 的 “工具调用逻辑”,通过标准化协议(stdio/SSE)、注解式工具封装、多场景部署,变成可落地的工程方案。
Function Calling 是‘模型自己会用的工具’,MCP 是‘让模型安全、标准地连接万物的协议’
MCP 核心价值
- 标准化:终结了各家 Function Calling 的碎片化,提供统一接口。
- 解耦:LLM 应用与工具服务完全分离,便于独立开发、部署、升级。
- 安全可控:通过独立服务进程隔离敏感操作(如数据库访问)。
- 生态友好:任何人可开发 MCP Server,形成“AI 工具市场”。
MCP 落地最佳实践
- 工具设计:
- 每个
@Tool方法仅做一件事(如 “查天气”“查空气质量” 分开),避免参数过多; - 用
@ToolParameter详细描述参数(含示例),帮助 LLM 生成正确参数。
- 每个
- 错误处理:
- 服务器工具方法必须捕获异常,返回 “用户可理解的错误信息”(如 “纬度格式错误,示例:39.9042”)。
- 部署选择:
- 本地资源访问(如本地文件、数据库)→ 选 stdio 模式(低延迟、安全);
- 多客户端共享能力(如团队共用工具)→ 选 SSE 模式(方便部署、可扩展)