MCP协议入门与实践
skills跟mcp解决的问题不一样。
mcp很早这个概念就出来了,是一种协议、模型间调用三方能力的一个类似接口定义。比如你想购票、那你可以用携程基于MCP实现的MCP服务,接入到你的模型里来直接调用。他们负责MCP Server的实现。别的能力也这样。其实就是定义了一套规范,送你一句话,刚看到的:MCP(Model Context Protocol)是一个开放协议,旨在标准化应用程序向大语言模型(LLMs)提供上下文的方式。可以将 MCP 想象成 AI 应用的 USB-C 接口——正如 USB-C 为设备连接各类外设提供了统一标准,MCP 也为 AI 模型连接不同数据源和工具建立了标准化桥梁。
skills其实不是什么新的东西,本质是一系列文件。把某些能力包装在一个个的skills目录下,比如有个pdf处理文件的能力,这个能力可以封装成一个skills。如果你用claude的时候 跟他说 帮我处理xx pdf文件,claude就会识别到我可以用这个skills(前提是这个skills在你的当前目录下)。这样就可以把一些能力复用。。别人也可以用
Function Call 很好用,工具一多就管不过来了。
假设你在一家公司做企业知识库助手,一开始只有两个工具:查年假、查订单。你手写两份 JSON Schema,代码里写两个 if-else 路由,没什么问题。但半年过去了,产品经理不断加需求:查考勤、查销售数据、查会议室、查报销进度、查项目排期、查库存、查物流、查合同……工具从 2 个变成了 20 个。
这时候你会发现:
- 20 个工具 × 每个工具 5~10 个参数 = 几百行 JSON Schema 要手写和维护
- Python 团队写了一个数据分析工具,你的 Java 系统调不了
- 某个工具的参数改了,JSON Schema 忘了同步更新,模型传了错误的参数,线上出了 bug
你需要的不是更多的 if-else,而是一个标准化的工具管理协议。这就是今天要讲的 MCP。
2. 工具规模化之后的四大痛点
2.1 工具定义的维护噩梦
上一篇的代码你应该还有印象,定义一个工具要写很多很多的JSON Schema:

这只是一个工具、一个参数。如果一个工具有 5 个参数,代码量翻 5 倍。20 个工具就是几百行纯粹的 JSON Schema 构建代码。
更要命的是维护问题:
- 工具的参数改了(比如
getUserAnnualLeave新增了一个year参数),你要同步修改 JSON Schema,忘了改就会出 bug - 没有工具文档,新同事不知道系统里有哪些工具可用,只能翻代码
- 工具定义散落在代码各处,没有统一的注册中心
2.2 跨语言跨系统的集成困境
你的企业知识库助手需要调用的工具来自不同团队:
- Java 团队写的 HR 工具(查年假、查考勤)
- Python 团队写的数据分析工具(销售报表、用户画像)
- 第三方 HTTP API(物流查询、天气查询)
三种不同的调用方式,你的代码里要写三套集成逻辑,接入一个新系统,就要写一套适配代码。而且每个系统的认证方式不同(有的用 Token,有的用 API Key,有的用 OAuth),错误处理方式也不同。
2.3 权限和安全的黑洞
Function Call 协议本身没有任何权限机制。所有的权限校验都要你自己写:
- 用户 A 能不能查用户 B 的年假?
- 某个工具只允许管理员使用,怎么控制?
工具越多,权限逻辑越复杂。而且权限代码和业务代码混在一起,容易出漏洞。
2.4 可观测性的缺失
20 个工具在线上跑,你需要知道:
- 每个工具被调用了多少次?
- 平均耗时多少?哪个工具最慢?
- 调用失败率是多少?失败的原因是什么?
- 某次调用的完整链路:用户问了什么 → 模型选了哪个工具 → 传了什么参数 → 返回了什么结果 → 最终答案是什么?
Function Call 协议不管这些,全靠你自己埋点、写日志、搭监控。工具调用链路一长(调用工具 A → 工具 A 内部调用工具 B → 工具 B 查数据库),排查问题就像大海捞针。
我们需要的是在 Function Call 之上,加一层标准化的工具管理框架——统一工具的定义、注册、发现、调用、权限控制。
| 维度 | Function Call 解决了吗 |
|---|---|
| 模型判断是否调用工具 | 解决了 |
| 标准化的调用意图输出 | 解决了 |
| 工具定义的自动化管理 | 没有,手写 JSON Schema |
| 工具的动态发现和注册 | 没有,硬编码在代码里 |
| 跨语言跨系统的统一调用 | 没有,每个系统写一套适配 |
| 权限和安全控制 | 没有,自己实现 |
| 调用链路的可观测性 | 没有,自己埋点 |
这就是 MCP 要做的事。
MCP,全称 Model Context Protocol(模型上下文协议),由 Anthropic(Claude 的母公司)于 2024 年 11 月开源发布。它不是一个具体的产品或框架,而是一个开放的协议规范。核心思想用一句话概括:任何工具只要实现了 MCP 协议,就能被任何支持 MCP 的客户端调用,不用关心对方是什么语言、什么平台。
2. MCP 的三层架构:Host、Client、Server
MCP 的架构设计分三层:Host(宿主应用)、Client(MCP 客户端)、Server(MCP 服务端)。这三层的关系用一张图说明:


2.1 Host(宿主应用)
Host 是用户直接交互的应用,比如:
- Claude Desktop(Anthropic 的桌面客户端)
- Cursor(AI 编程 IDE)
- 你自己开发的企业知识库助手(比如咱们的 Ragent)
Host 的职责是:接收用户输入 → 调用大模型 → 根据模型的指令通过 MCP Client 调用工具 → 把结果返回给模型 → 展示最终答案给用户。
Host 内部包含一个或多个 MCP Client,每个 Client 负责和一个 MCP Server 通信。
2.2 Client(MCP 客户端)
Client 是 Host 内部的通信组件,负责和 MCP Server 建立连接、发送请求、接收响应。
关键点:一个Client只连接一个Server ,但一个 Host 可以有多个 Client,连接多个 Server。就像你的电脑有多个 USB 接口,每个接口插一个设备。
Client 的职责包括:
- 和 Server 建立连接(通过 Stdio 或 HTTP)
- 发现 Server 提供的工具列表
- 调用 Server 的工具并获取结果
- 管理连接的生命周期
2.3 Server(MCP 服务端)
Server 是提供工具的一方。每个 Server 暴露一组工具,Client 通过 MCP 协议调用这些工具。
Server 可以是:
- 本地进程(通过 Stdio 通信,比如一个本地的文件操作工具)
- 远程 HTTP 服务(通过 Streamable HTTP 通信,比如部署在服务器上的 HR 系统工具)
Server 的职责包括:
- 声明自己提供哪些工具(工具名、描述、参数定义)
- 接收 Client 的调用请求
- 执行工具逻辑并返回结果
3. MCP 的三大核心能力
MCP 协议定义了三大核心能力:Tools(工具调用)、Resources(资源访问)、Prompts(提示词模板)。
3.1 Tools(工具调用)
这是 MCP 最核心的能力,也是和 Function Call 直接对应的部分。
Server 定义工具,Client 发现并调用工具。和 Function Call 的区别在于:
- FunctionCall :工具定义在客户端代码里(手写 JSON Schema),和模型一起发送
- MCP :工具定义在 Server 端,Client 通过协议动态获取
注意:MCP 协议本身只规定工具定义在 Server 端,Client 通过协议动态获取工具列表和元数据。至于 Server 端用什么方式定义工具(注解、手写 JSON、配置文件),那是实现框架的选择。下面展示的
@Tool注解是 Spring AI 框架提供的便利性封装。
举个例子,Function Call 里你要这样定义工具:
{"type":"function","function":{"name":"getUserAnnualLeave","description":"查询用户的年假余额","parameters":{"type":"object","properties":{"userId":{"type":"string","description":"用户 ID"}},"required":["userId"]}}}
在 Spring AI 框架中,你可以用 @Tool 注解定义工具(框架会自动生成符合 MCP 协议的工具元数据):
@Tool(description ="查询用户的年假余额,包括总天数、已使用天数、剩余天数")publicStringgetUserAnnualLeave(@ToolParam(description ="用户 ID")String userId){// 查询 HR 系统return"{\"remainingDays\": 5, \"totalDays\": 10, \"usedDays\": 5}";}
Spring AI 框架会扫描 @Tool 注解,自动提取方法名作为工具名、description 作为工具描述、方法参数和 @ToolParam 注解作为参数定义,生成符合 MCP 协议的工具元数据(JSON Schema 格式)。Client 启动时通过 MCP 协议从 Server 获取这些元数据,不用在 Client 端手写 JSON Schema,也不用担心定义和实现不同步。
3.2 Resources(资源访问)
Server 可以暴露资源供 Client 读取,比如:
- 文件内容(配置文件、日志文件)
- 数据库记录
- API 返回的数据
Resources 和 Tools 的区别是:Tools 是执行操作(查年假、下订单),Resources 是提供数据(读取一个文件的内容)。Resources 更像是给模型提供额外的上下文信息。
3.3 Prompts(提示词模板)
Server 可以提供预定义的提示词模板,Client 可以使用这些模板来构建和模型的交互。适合标准化的交互场景,比如“代码审查模板"”、“文档总结模板”。
本篇重点讲 Tools,Resources 和 Prompts 在实际项目中用得相对少一些,了解即可。
4. MCP vs Function Call:不是替代,是增强
答案是:不是。MCP 底层仍然依赖模型的 Function Call 能力。模型判断是否调用工具、输出 tool_calls JSON——这个能力是 Function Call 提供的,MCP 不会重新发明这个轮子。
MCP 做的是在 Function Call 之上,提供一层标准化的管理框架。用一个类比:Function Call 是"发动机",MCP 是"整车"。发动机提供动力,但你还需要方向盘、刹车、仪表盘才能上路。
MCP提供:工具的标准化管理;跨语言/跨平台支持;统一的安全控制
FunctionCall 提供:意图理解能力;结构化输出能力;对话上下文管理
| 对比维度 | Function Call | MCP |
|---|---|---|
| 本质 | 模型的原生能力(输出调用意图) | 标准化的工具管理协议 |
| 工具定义 | 手写 JSON Schema,和代码分离 | 代码注解自动生成,定义和实现一体 |
| 工具发现 | 没有,硬编码在请求里 | Client 启动时自动从 Server 获取 |
| 跨语言支持 | 不支持,每个语言自己实现 | 协议统一,Java / Python / TS 都能互通 |
| 传输方式 | 依赖具体的 HTTP API | 标准化传输(Stdio / Streamable HTTP) |
| 权限控制 | 没有,自己实现 | 协议层面支持(还在完善中) |
| 可观测性 | 没有,自己埋点 | 协议层面支持日志和追踪 |
| 生态 | 各家模型厂商各自实现 | 开放协议,社区共建 MCP Server |
MCP协议层面 (标准制定者):
- 定义了工具元数据的标准格式(name、description、parameters 的 JSON Schema)
- 定义了 Client 和 Server 的通信协议(JSON-RPC over Stdio/HTTP)
- 定义了工具发现机制(Client 启动时从 Server 获取工具列表)
- 解决的核心问题:工具定义从Client端转移到Server端,实现跨语言跨系统互通
SpringAI框架层面 (协议实现者):
- 提供
@Tool注解,让你用注解方式定义工具(而不是手写 JSON) - 提供自动扫描注解并生成符合 MCP 协议的工具元数据
- 处理 MCP 协议的通信细节(JSON-RPC 请求解析、响应构建等)
- 解决的核心问题:让Java开发者更方便地实现MCP协议
打个比方:MCP 协议就像 HTTP 协议,Spring AI 就像 Spring MVC 框架。HTTP 定义了请求响应格式,但你可以用任何语言、任何框架实现 HTTP 服务器。Spring MVC 提供了 @RestController 注解让你更方便地写 HTTP 接口,但这不是 HTTP 协议本身的能力。
即使不用 Spring AI,你也可以用纯 Java 手写 JSON 来实现 MCP Server,只是更麻烦。MCP 协议的价值在于:一旦你的Server实现了MCP协议,任何支持MCP的Client(ClaudeDesktop、Cursor、Python客户端等)都能调用你的工具,不需要为每个Client写适配代码
MCP 的传输机制
MCP Client 和 Server 之间怎么通信?MCP 协议定义了两种传输方式:Stdio(标准输入输出)和 Streamable HTTP(可流式 HTTP)。
1. Stdio(标准输入输出)
Stdio 是最简单的传输方式。MCP Server 作为本地子进程运行,Client 通过操作系统的标准输入(stdin)和标准输出(stdout)和 Server 通信。
打个比方:你在终端里运行 grep "error" log.txt,你敲的命令是输入(stdin),grep 打印出来的结果是输出(stdout)。MCP 的 Stdio 传输就是这个原理:Client 启动 Server 进程,往 Server 的 stdin 写请求(JSON 格式),Server 从 stdout 返回结果(也是 JSON 格式)。整个过程就像你在和一个命令行程序对话,只不过对话内容是结构化的 JSON 数据。
通信过程:
- 1.Client 启动 Server 进程(比如
java -jar mcp-server.jar) - 2.Client 往 Server 的 stdin 写入 JSON-RPC 请求
- 3.Server 从 stdin 读取请求,执行工具,把结果以 JSON-RPC 格式写入 stdout
- 4.Client 从 Server 的 stdout 读取响应
JSON-RPC 是一种轻量级的远程过程调用协议,用 JSON 格式传输请求和响应。你可以把它理解为用 JSON 格式约定好请求和响应的结构,和 RESTful API 类似,但更简单。
Stdio 的优点:
- 简单,不需要网络配置,不暴露端口
- 安全,通信只在本地进程之间,不经过网络
- 适合本地工具(文件操作、本地数据库查询、命令行工具)
Stdio 的缺点:
- 只能本地调用,不支持远程访问
- Server 和 Client 必须在同一台机器上
2. Streamable HTTP(可流式 HTTP)
Streamable HTTP 是 MCP 协议在 2025 年 3 月引入的传输方式(替代了早期的 HTTP+SSE 方案)。MCP Server 作为 HTTP 服务运行,Client 通过 HTTP 请求调用。
通信过程:
- 1.Server 启动 HTTP 服务,监听某个端口(比如
http://localhost:8080) - 2.Client 向 Server 发送 HTTP POST 请求(JSON-RPC 格式)
- 3.Server 处理请求,返回 HTTP 响应
- 4.如果需要流式返回(比如长时间运行的工具),Server 通过 SSE(Server-Sent Events)推送增量结果
Streamable HTTP 的优点:
- 支持远程访问,Server 可以部署在任何地方
- 支持团队共享,多个 Client 可以连接同一个 Server
- 支持流式响应(SSE),适合长时间运行的工具
- 可以利用 HTTP 生态的认证、负载均衡、监控等基础设施
Streamable HTTP 的缺点:
- 需要网络配置(端口、防火墙、HTTPS)
- 相比 Stdio 多了网络开销
本地开发和个人工具用 Stdio,团队共享和生产环境用 Streamable HTTP。企业级项目基本上都是后者。
Java 实战:搭建一个 MCP Server
延续前几篇的企业知识库助手场景,我们用 Spring AI MCP Server 框架搭建一个 MCP Server,提供两个工具:
getUserAnnualLeave:查询用户年假余额getOrderStatus:查询订单状态
搭建完成后,这个 MCP Server 可以被 Claude Desktop、Cursor 等任何支持 MCP 的客户端直接调用。
Spring AI 从 1.0 版本开始提供了 MCP Server 的 Boot Starter,开箱即用。选 Spring AI 的理由很简单:
- Java 生态,和现有的 Spring Boot 项目无缝集成
- 用
@Tool注解定义工具,不用手写 JSON Schema - 同时支持 Stdio 和 Streamable HTTP 两种传输方式
- 社区活跃,文档完善
Spring AI MCP Server 提供了三个 Starter,根据传输方式选择:
| Starter | 传输方式 | 适用场景 |
|---|---|---|
spring-ai-starter-mcp-server | Stdio | 本地工具,被 Claude Desktop / Cursor 调用 |
spring-ai-starter-mcp-server-webmvc | Streamable HTTP(基于 Spring MVC) | 远程工具,团队共享 |
spring-ai-starter-mcp-server-webflux | Streamable HTTP(基于 WebFlux) | 远程工具,响应式编程 |
本篇先用 Stdio 方式演示(最简单,能直接被 Claude Desktop 调用),后面再介绍 HTTP 方式。
Maven 依赖
注意:
spring-ai-starter-mcp-server是 Stdio 传输方式的 Starter。如果你需要 HTTP 传输,换成spring-ai-starter-mcp-server-webmvc。
4. 定义工具
这是 MCP 相比 Function Call 最爽的地方——用 @Tool 注解定义工具,参数用 @ToolParam 注解描述,框架自动生成工具的 JSON Schema。
创建一个工具类 EnterpriseTools.java:
packagecom.nageoffer.ai.mcp.tools;importorg.springframework.ai.tool.annotation.Tool;importorg.springframework.ai.tool.annotation.ToolParam;importorg.springframework.stereotype.Service;/**
* 企业知识库助手工具集
* 每个 @Tool 方法会自动注册为一个 MCP 工具
*/@ServicepublicclassEnterpriseTools{/**
* 查询用户年假余额
*/@Tool(description ="查询用户的年假余额,包括总天数、已使用天数、剩余天数。当用户询问年假、假期余额、还有多少天假等问题时使用此工具。")publicStringgetUserAnnualLeave(@ToolParam(description ="用户 ID,例如 user_12345")String userId){// 实际项目中这里调用 HR 系统 API// 这里用 mock 数据演示returnString.format("""
{
"userId": "%s",
"remainingDays": 5,
"totalDays": 10,
"usedDays": 5,
"year": 2026
}
""", userId);}/**
* 查询订单状态
*/@Tool(description ="查询订单的物流状态和详细信息。当用户询问订单状态、物流进度、快递到哪了等问题时使用此工具。")publicStringgetOrderStatus(@ToolParam(description ="订单号,例如 ORD-12345")String orderId){// 实际项目中这里调用订单系统 APIreturnString.format("""
{
"orderId": "%s",
"status": "运输中",
"location": "北京市朝阳区分拨中心",
"estimatedDelivery": "2026-03-01",
"carrier": "顺丰速运",
"trackingNumber": "SF1234567890"
}
""", orderId);}}
对比一下 Function Call 里定义同样两个工具需要多少代码——上一篇的 callModelWithTools 方法里,光构建 JSON Schema 就写了 40 多行。MCP 里只需要两个方法加注解,清爽多了。
5. 注册工具到 MCP Server
创建配置类,把工具注册到 MCP Server:
packagecom.nageoffer.ai.mcp.config;importcom.nageoffer.ai.mcp.tools.EnterpriseTools;importorg.springframework.ai.tool.ToolCallbackProvider;importorg.springframework.ai.tool.method.MethodToolCallbackProvider;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassMcpServerConfig{/**
* 注册工具提供者
* MethodToolCallbackProvider 会扫描 EnterpriseTools 中所有 @Tool 注解的方法,
* 自动注册为 MCP 工具
*/@BeanpublicToolCallbackProviderenterpriseToolProvider(EnterpriseTools enterpriseTools){returnMethodToolCallbackProvider.builder().toolObjects(enterpriseTools).build();}}
MethodToolCallbackProvider 会自动扫描 EnterpriseTools 类中所有带 @Tool 注解的方法,提取方法名作为工具名、description 作为工具描述、方法参数和 @ToolParam 注解作为参数定义,自动生成完整的工具元数据。
6. 配置 MCP Server
application.yml 配置:
spring:ai:mcp:server:name: enterprise-assistant
version: 1.0.0
type: SYNC
main:web-application-type: none
banner-mode: off
logging:file:name: ./logs/mcp-server.log
level:root: OFF
几个关键配置说明:
spring.ai.mcp.server.name:Server 名称,Client 连接时会看到这个名字spring.ai.mcp.server.version:Server 版本号spring.ai.mcp.server.type:工具执行模式,SYNC(同步)或ASYNC(异步)spring.main.web-application-type: none:Stdio 模式不需要 Web 容器spring.main.banner-mode: off:关闭 Spring Boot 启动 banner,避免 banner 输出到 stdout 干扰 MCP 通信
Stdio 模式下,stdout 是 MCP 协议的通信通道,任何非协议内容(banner、日志)输出到 stdout 都会导致通信失败。这是一个常见的坑。
7. 启动类
packagecom.nageoffer.ai.mcp;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublicclassMcpServerApplication{publicstaticvoidmain(String[] args){SpringApplication.run(McpServerApplication.class, args);}}
项目结构:
mcp-server-demo/
├── pom.xml
└── src/main/
├── java/com/nageoffer/ai/mcp/
│ ├── McpServerApplication.java
│ ├── config/
│ │ └── McpServerConfig.java
│ └── tools/
│ └── EnterpriseTools.java
└── resources/
└── application.yml
先用 Maven 打包:
mvn clean package -DskipTests
打包完成后,在 target 目录下会生成 mcp-server-demo-1.0.0.jar。
8. 测试:用 MCP 客户端调用
8.1 在 Cursor 中配置
打开 Cursor 的 MCP 配置(Settings → Tools & MCP),如下图所示:

若果是SpringAI1.1+版本就可以使用/mcp,项目中马哥的SpringAI版本比较早,而且支持MCP的springAI版本是在1.1.0-M1版本。配置cusor的mcp server信息时得用: "url": "http://localhost:8080/sse"
添加:
{"mcpServers":{"enterprise-assistant":{"command":"java","args":["-jar","/path/to/mcp-server-demo-1.0.0.jar"]}}}
把 /path/to/ 替换成你的 jar 包实际路径。
咱们 MCP Demo 项目用的 JDK17,如果你的电脑默认不是 JDK17,需要将 command 设置为 Java 的绝对路径。我的默认 JDK 就不是 17,所以需要调整下,比如:
{"mcpServers":{"enterprise-assistant":{"command":"/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin/java","args":["-jar","/path/to/mcp-server-demo-1.0.0.jar"],"env":{"JAVA_HOME":"/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home"}}}}
在对话框里进行问答,Cursor 会自动调用你的 MCP Server 查询年假余额和订单状态。

因为是个 Demo 的 MCP 示例,所以问题有点呆,需要用户提示词自己把账号和订单号带进去。常规上肯定是程序里自动带入,大家忽略即可。
8.2 使用 Streamable HTTP 方式
如果你想让 MCP Server 以 HTTP 服务的方式运行(支持远程访问、多客户端共用),只需要做两个改动:
第一步,把 Maven 依赖换成 WebMVC 版本:
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-webmvc</artifactId><version>${spring-ai.version}</version></dependency>
第二步,修改 application.yml:
spring:ai:mcp:server:name: enterprise-assistant
version: 1.0.0
type: SYNC
server:port:8080
启动后,MCP Server 会在 http://localhost:8080 上监听。Client 配置改为:
{"mcpServers":{"enterprise-assistant":{"url":"http://localhost:8080/mcp"}}}
工具代码和配置类完全不用改,只是传输方式从 Stdio 变成了 HTTP。
9. 对比:Function Call vs MCP + Spring AI 的代码量
同样实现查年假和查订单两个工具,对比一下两种方式的代码量:
| 对比项 | Function Call(上一篇) | MCP + Spring AI(本篇) |
|---|---|---|
| 工具定义 | 40+ 行 JSON Schema 构建代码 | 2 个 @Tool 注解方法 |
| 工具路由 | 手写 if-else 或策略模式 | 框架自动路由 |
| 协议处理 | 手写 HTTP 请求、解析 tool_calls、构建第二轮消息 | 框架自动处理 |
| 新增工具 | 加 JSON Schema + 加路由 + 改代码 + 重新部署 | 加一个 @Tool 方法 + 重新部署 |
| 客户端适配 | 只能被你自己的代码调用 | 任何 MCP 客户端都能调用 |
| 总代码量 | ~200 行(含 JSON Schema 构建) | ~60 行(含工具实现) |
代码量减少了 70%,而且新增工具只需要加一个方法,不用改任何框架代码。
说明:这里对比的是纯 Function Call 实现 vs MCP 协议 + Spring AI 框架实现。代码量的减少主要来自 Spring AI 框架的便利性封装(注解、自动路由等)。MCP 协议本身带来的核心价值是最后一行客户端适配——一旦你的工具实现了 MCP 协议,任何支持 MCP 的客户端都能调用,不需要为每个客户端写适配代码。
MCP 在 RAG 系统中的应用
讲完了 MCP 的原理和实战,回到我们的主线——RAG 系统。MCP 在 RAG 系统中能发挥什么作用?
1. 知识检索作为 MCP 工具
上一篇讲 Function Call 在 RAG 中的应用时,我们定义了一个 searchKnowledgeBase 工具,让模型自动判断是查知识库还是调业务工具。用 MCP 实现同样的能力,只需要把知识检索封装成一个 MCP 工具:
@Tool(description ="在企业知识库中搜索相关文档。当用户询问公司制度、产品文档、操作指南等静态知识时使用此工具。")publicStringsearchKnowledgeBase(@ToolParam(description ="搜索关键词,用自然语言描述")String query,@ToolParam(description ="返回结果数量,默认 5")int topK){// 调用向量数据库检索// 实际项目中这里执行 Embedding → Milvus 检索 → RerankingList<Document> results = ragService.search(query, topK);returnformatResults(results);}
这样做的好处是:你的知识检索能力不再局限于自己的系统,任何支持 MCP 的客户端都能调用你的知识库。比如团队成员在 Cursor 里写代码时,可以直接问公司的代码规范是什么,Cursor 通过 MCP 调用你的知识库检索工具,返回相关文档。
2. 多工具编排:知识检索 + 业务工具
MCP 的真正威力在于多个 Server 协同工作。假设用户问我的订单 #12345 能退货吗,这个问题需要两部分信息:
- 1.订单的当前状态(需要调用订单系统)
- 2.退货政策(需要检索知识库)
在 MCP 架构下,这两个能力可以由不同的 MCP Server 提供:

每个 MCP Server 专注做一件事(订单查询、知识检索、HR 查询……),Host 根据模型的判断,并行调用多个 Server,综合结果生成答案。这种架构的好处是:
- 职责清晰 :每个 Server 独立开发、独立部署、独立维护
- 灵活组合 :新增一个能力只需要部署一个新的 MCP Server,不用改现有代码
- 团队协作 :不同团队各自维护自己的 MCP Server,通过协议互通
3. 企业级场景:Ragent 中的 MCP 实践
在我们的 Ragent 项目(企业级 RAG 智能体平台)中,MCP 被用来管理所有的外部工具调用。简要介绍一下架构思路:
- MCPToolRegistry :工具注册表,管理所有已注册的 MCP Server 和工具
- MCPToolExecutor :工具执行器,负责根据模型的
tool_calls路由到对应的 MCP Server 并执行 - 自动发现机制 :系统启动时自动连接配置的 MCP Server,获取工具列表,注册到工具注册表
这种架构让 Ragent 可以灵活接入各种外部工具,而不需要为每个工具写适配代码。具体的代码实现会在后续的 Ragent 项目实战文章中详细展开。
MCP 的生态现状
1. 支持 MCP 的客户端
MCP 协议发布一年多以来,已经有不少客户端支持:
| 客户端 | 类型 | MCP 支持情况 |
|---|---|---|
| Claude Desktop | AI 对话客户端 | 完整支持,Anthropic 官方出品 |
| Cursor | AI 编程 IDE | 完整支持,MCP 工具可在编程中使用 |
| Windsurf | AI 编程 IDE | 支持 MCP |
| Continue | VS Code AI 插件 | 支持 MCP |
| Cline | VS Code AI 插件 | 支持 MCP |
| Claude Code | CLI 工具 | 完整支持 |
| Spring AI | Java AI 框架 | 提供 MCP Client 和 Server Starter |
| Kiro | AI IDE | 支持 MCP |
这意味着你开发一个 MCP Server,上面这些客户端都能直接调用,不需要为每个客户端写适配代码。
2. 社区 MCP Server
GitHub 上已经有大量社区开发的 MCP Server,覆盖常见场景:
- 文件系统 :读写本地文件、目录操作
- 数据库 :MySQL、PostgreSQL、SQLite 查询
- Web搜索 :Brave Search、Google Search
- 代码仓库 :GitHub 操作(创建 Issue、提交 PR、查看代码)
- 知识管理 :Notion、Obsidian 集成
- 通信工具 :Slack、Discord 消息发送
- 云服务 :AWS、GCP 资源管理
你可以在 MCP Servers 目录 找到这些社区 Server,直接配置使用,不需要自己开发。
3. MCP 的局限性和未来
MCP 的方向是对的,但目前还有一些局限:
- 协议还在快速演进 :从 2024 年 11 月发布到现在,传输层已经从 HTTP+SSE 改为 Streamable HTTP,API 也在不断调整。早期开发的 MCP Server 可能需要适配新版本
- 部分客户端支持不完整 :有些客户端只支持 Stdio,不支持 HTTP;有些只支持 Tools,不支持 Resources 和 Prompts
- 生产环境的稳定性 :MCP 在本地开发场景下表现很好,但在高并发的生产环境中,稳定性和性能还需要更多验证
- 权限模型还在完善 :MCP 协议层面的权限控制还比较基础,企业级的细粒度权限(比如基于角色的工具访问控制)仍然需要自己实现
- 认证标准化 :远程 MCP Server 的认证方式(OAuth、API Key 等)还没有统一标准
不过,标准化是大趋势。就像 HTTP 协议从 0.9 到 1.0 到 1.1 到 2.0 到 3.0,MCP 也会不断完善。现在学习和使用 MCP,是一个好的时机。

Comments NOTHING