MCP详解
## MCP 通俗解释
让我用一个更生活化的例子来解释 MCP。
---
## 一、最直白的类比:充电器接口
### 没有 MCP 的时代
想象一下,如果每个电子设备都有自己独特的充电接口:
- 手机用 A 接口
- 电脑用 B 接口
- 耳机用 C 接口
- 平板用 D 接口
你出差要带**4个不同的充电器**,因为每个设备都不通用。这就是早期 AI 工具集成的问题——每个工具都要单独写代码对接,换一个 AI 应用就得重新写一遍。
### 有 MCP 之后
就像 USB-C 接口统一了充电标准:
- 一个充电器可以充手机、电脑、耳机、平板
- 因为大家都遵守同一个协议
**MCP 就是 AI 世界的 USB-C**。它定义了一套标准协议,让 AI 应用可以通过统一的方式连接任何外部工具和数据源。
---
## 二、餐厅点餐的类比
### 传统方式
```
你(AI)想点餐 → 需要自己打电话给厨房 → 需要知道厨房的电话号码 →
需要知道厨师说的是哪种语言 → 需要自己把菜名翻译成厨师能听懂的话
```
每换一家餐厅,你都要重新学习这套流程。这就是为什么以前每个 AI 应用接入新工具都很麻烦。
### 使用 MCP 的方式
```
你(AI) → 服务员(MCP Server) → 厨房(工具/数据源)
```
MCP 相当于一个**万能服务员**:
- 你只要用自然语言说“我要一份牛排”
- 服务员(MCP)负责:通知厨房、翻译需求、把做好的菜端给你
- 你不需要知道厨房在哪、厨师是谁、用什么语言沟通
---
## 三、技术翻译:MCP 到底干了什么?
### MCP 的核心工作
| 角色 | 做什么 | 类比 |
|------|--------|------|
| **AI 应用** | 发出指令 | 你说“我要查一下今天的天气” |
| **MCP 协议** | 标准化的沟通语言 | 你说话,翻译机帮你翻译成对方能听懂的语言 |
| **MCP Server** | 翻译官 + 执行者 | 翻译官把需求转达给具体的人,然后把结果带回来 |
| **工具/数据源** | 实际干活的 | 气象局的数据库、GitHub 的服务器、本地文件 |
### 一个具体例子:让 AI 查询你的数据库
**没有 MCP**:
1. 开发者要写代码连接数据库
2. 要处理数据库认证、SQL 语法、错误处理
3. 每个 AI 应用都得重复做一遍
4. 换一个数据库(比如从 MySQL 换成 PostgreSQL),代码又要重写
**有 MCP**:
1. 开发者写一个 MCP Server(只写一次)
2. MCP Server 封装了所有数据库操作细节
3. 任何支持 MCP 的 AI 应用都可以直接说:“帮我查一下上个月的销售额”
4. MCP Server 自动把自然语言转成 SQL,执行查询,返回结果
---
## 四、MCP 的三大价值
### 1. 一次开发,处处使用
```
开发者:写一个 GitHub MCP Server
效果:任何支持 MCP 的 AI(Dify、Claude、Cursor 等)都能操作你的 GitHub
```
不需要为每个 AI 应用单独写 GitHub 集成代码。
### 2. 标准化沟通
```
所有 AI 应用 → MCP 协议 → 所有工具
```
就像所有 USB-C 设备都可以插到同一个充电器上。
### 3. 安全性
MCP 协议内置了权限控制:
- AI 不能随便删除你的文件(除非你授权)
- 可以控制 AI 能访问哪些数据
- 所有操作都有记录
---
## 五、MCP 和 Dify 的关系
在 Dify 中,MCP 体现在**外部知识库**和**插件**功能上:
| Dify 功能 | MCP 的作用 |
|-----------|-----------|
| **外部知识库 API** | 通过 MCP 协议连接 RAGFlow、VikingDB 等知识库 |
| **插件市场** | 插件本质上是预先封装好的 MCP Server |
| **工具调用** | Agent 可以通过 MCP 调用外部 API |
### Dify 中使用 MCP 的体验
你在 Dify 界面里点击“添加外部知识库”,填个 API 地址和 Key,就完成了连接。背后是 MCP 协议在工作,但你不需要关心细节——就像你用 USB-C 充电,不需要知道背后的电路原理。
---
## 六、一句话总结
> **MCP 是让 AI 能够“即插即用”地连接任何外部工具和数据源的统一标准。**
就像 USB-C 让所有电子设备用一个充电器,MCP 让所有 AI 应用用一种方式连接数据库、文件系统、GitHub、浏览器等任何工具。
---
## 七、一个对比表格
| 对比维度 | 没有 MCP | 有 MCP |
|---------|---------|--------|
| **连接数据库** | 每个 AI 应用写一遍连接代码 | 写一个 MCP Server,所有 AI 复用 |
| **切换工具** | 代码重写 | 换一个 MCP Server 就行 |
| **开发者工作量** | N 个应用 × M 个工具 | N 个应用 + M 个 MCP Server |
| **普通用户使用** | 需要懂技术 | 填个地址和 Key 就能用 |
| **安全性** | 需要自己实现 | 协议内置 |
---
如果你还是觉得抽象,可以这样理解:**MCP 就是给 AI 装上了一个“万能插头”**,让它可以随时插拔不同的工具,而不用每次都要重新“接线”。
## MCP 如何保持上下文理解
这是一个很好的问题!MCP 保持上下文理解的能力,其实是它区别于普通 API 调用的核心特性之一。
---
## 一、先理解问题:为什么需要“保持上下文”?
### 普通 API 的问题
想象你在和一个客服机器人对话:
```
你:我要订一张去北京的机票
机器人:好的,请问出发日期?
你:下周五
机器人:请问从哪个城市出发?
你:上海
机器人:好的,请问几位乘客?
你:2位
机器人:已为您查询到下周五上海飞北京的航班...
```
这里每次你的回答,机器人需要**记住**之前的对话内容(目的地、日期、出发地)。如果每次都是独立处理,机器人就会问重复的问题。
### 普通 API 调用就像“失忆症患者”
```
API 调用1:查询天气(北京)
返回:北京今天晴天
API 调用2:那上海呢?(问题里没有“上海”这个词)
API 无法理解“那”指代什么,因为上下文丢失了
```
---
## 二、MCP 如何解决这个问题?
MCP 通过**会话管理**和**状态维护**来保持上下文理解。
### 核心机制:会话(Session)
```
┌─────────────────────────────────────────────────┐
│ AI 应用 │
│ (Dify / Claude) │
│ │ │
│ 创建会话 ID: abc123 │
│ │ │
│ ┌───────────────────▼───────────────────────┐ │
│ │ MCP Server │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ Session: abc123 │ │ │
│ │ │ ├─ 历史消息:[...] │ │ │
│ │ │ ├─ 临时变量:{city: "北京"} │ │ │
│ │ │ ├─ 操作状态:等待确认 │ │ │
│ │ │ └─ 用户偏好:经济舱 │ │ │
│ │ └─────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
```
当 AI 应用第一次连接 MCP Server 时,会创建一个**会话(Session)**。这个会话有一个唯一的 ID,后续所有操作都带着这个 ID,MCP Server 就能知道这些请求属于同一个“对话”。
---
## 三、具体怎么实现的?三个层面
### 层面1:会话级别的状态存储
MCP Server 会为每个会话维护一个**状态容器**:
```json
{
"session_id": "abc123",
"context": {
"history": [
{"role": "user", "content": "帮我查一下北京的天气"},
{"role": "assistant", "content": "北京今天晴天,25度"}
],
"variables": {
"current_city": "北京",
"last_query_type": "weather"
},
"pending_action": null,
"user_preferences": {
"unit": "celsius",
"language": "zh"
}
}
}
```
### 层面2:协议内置的上下文传递
MCP 协议的消息格式本身就支持上下文传递:
```json
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"city": "上海"
},
"_meta": {
"sessionId": "abc123",
"parentMessageId": "msg_001", // 关联上一条消息
"conversationId": "conv_xyz" // 对话标识
}
}
}
```
### 层面3:工具调用结果的上下文反馈
MCP 不只是单向调用工具,还会把执行结果作为上下文带回来:
```
用户:帮我查一下北京的天气
↓
AI → MCP Server:调用天气工具
↓
MCP Server → AI:返回结果 + 上下文提示
{
"result": "北京晴天,25度",
"context_hint": {
"current_topic": "weather",
"entities": ["北京"],
"next_possible_actions": ["查空气质量", "查未来三天"]
}
}
```
这样 AI 就知道刚才聊的是北京的天气,如果用户说“那上海呢”,AI 能理解“那”指的是“天气查询”。
---
## 四、一个完整的对话示例
让我用一个实际例子展示 MCP 如何保持上下文:
### 第1轮:初始化会话
```
用户:我要订一张机票
AI 应用 → MCP Server(创建会话)
→ 会话 ID: s001
→ 状态:等待用户提供目的地
MCP Server:需要了解目的地、出发地、日期等信息
AI:请问您要飞往哪里?
```
### 第2轮:累积信息
```
用户:去北京
AI 应用 → MCP Server(携带会话 ID: s001)
→ 更新状态:{destination: "北京", status: "等待出发地"}
MCP Server:还需要出发地和日期
AI:请问从哪个城市出发?
```
### 第3轮:继续累积
```
用户:从上海出发
AI 应用 → MCP Server(会话 ID: s001)
→ 更新状态:{destination: "北京", origin: "上海", status: "等待日期"}
MCP Server:还需要日期
AI:请问什么日期出发?
```
### 第4轮:完成信息收集
```
用户:下周五
AI 应用 → MCP Server(会话 ID: s001)
→ 更新状态:所有信息完整,可以查询了
→ 执行实际查询(调用航空公司 API)
→ 返回结果
AI:为您找到以下航班...
```
### 关键点
每一轮对话,MCP Server 都知道:
- 这是同一个会话(通过 session_id)
- 之前已经收集了哪些信息(destination、origin)
- 还缺什么信息(date)
- 用户当前处于哪个阶段(信息收集中 vs 已可查询)
---
## 五、MCP 上下文 VS 传统 API 上下文
| 维度 | 传统 API | MCP |
|------|---------|-----|
| **状态存储** | 由调用方自己维护 | MCP Server 内置会话管理 |
| **上下文传递** | 每次都要手动传所有历史 | 协议自动处理,只需传 session_id |
| **多轮对话** | 需要自己写代码实现 | 内置支持 |
| **状态恢复** | 断线后需要重新建立上下文 | 会话可持久化,断线重连后恢复 |
| **跨工具上下文** | 很难在不同 API 间共享 | MCP Server 内部可以共享会话状态 |
---
## 六、实际例子:Dify + MCP 的上下文保持
在 Dify 中,当你连接一个外部知识库(通过 MCP 协议)时:
```
第1轮:用户问“请假流程是什么?”
→ Dify 通过 MCP 查询知识库
→ MCP Server 记住:当前会话在查“请假”相关
第2轮:用户追问“那需要提前几天?”
→ Dify 发送请求(带 session_id)
→ MCP Server 理解“那”指的是“请假”
→ 精准返回请假提前天数的相关内容
→ 不会返回其他不相关的信息(如考勤、报销)
```
如果没有上下文保持,第2轮查询时,MCP Server 不知道“那”指什么,可能会返回所有包含“提前几天”的内容,包括“报销需提前几天提交”“会议需提前几天预约”等无关信息。
---
## 七、总结
MCP 保持上下文理解的本质是:
> **把“对话记忆”从 AI 应用层下沉到了协议层**
具体来说:
1. **会话机制**:每个对话有唯一 ID,所有操作都带这个 ID
2. **状态维护**:MCP Server 为每个会话维护独立的上下文状态
3. **协议支持**:MCP 协议本身就设计了对多轮对话的支持
4. **状态共享**:同一会话内调用多个工具时,它们可以共享上下文信息
这样做的好处是:
- **AI 应用更轻**:不需要自己维护对话历史
- **工具更智能**:工具可以根据上下文理解用户意图
- **体验更自然**:用户可以像和人聊天一样与 AI 交互
简单说,**MCP 让每个工具都拥有了“短期记忆”**,能够记住你刚才说了什么,从而理解“那”“这个”“它”这些指代关系。
## MCP 的会话内容存在哪里?
这是一个非常核心的问题!让我详细解释 MCP 会话存储的机制。
---
## 一、核心答案:存在多个地方
MCP 的会话内容**不是存在一个地方**,而是根据架构和场景,分布在不同的位置:
```
┌─────────────────────────────────────────────────────┐
│ 会话内容的存储层级 │
├─────────────────────────────────────────────────────┤
│ │
│ 层级1:AI 应用端(Dify/Claude) │
│ └─ 存储:会话 ID、对话历史(可选) │
│ │
│ 层级2:MCP Server 端(关键!) │
│ └─ 存储:会话状态、上下文变量、操作历史 │
│ │
│ 层级3:外部持久化存储(可选) │
│ └─ 存储:Redis、数据库、文件系统 │
│ │
└─────────────────────────────────────────────────────┘
```
---
## 二、详细拆解:每一层存什么、怎么存
### 层级1:AI 应用端(如 Dify)
**存储位置**:应用的内存或数据库
**存储内容**:
```
{
"conversation_id": "conv_12345",
"session_id": "mcp_session_abc", // 关联到 MCP 会话
"messages": [
{"role": "user", "content": "帮我查一下北京天气"},
{"role": "assistant", "content": "北京今天晴天"}
],
"current_mcp_session": "abc123"
}
```
**特点**:
- AI 应用主要负责**管理对话的展示层面**
- 存储用户和 AI 的完整对话历史
- 只需要记住 MCP 会话 ID,不需要存储 MCP 内部的复杂状态
---
### 层级2:MCP Server 端(核心存储)
这是**会话内容存储最核心的地方**。MCP Server 运行时会维护一个**内存中的会话管理器**:
```python
# 伪代码:MCP Server 内部的内存存储
class SessionManager:
def __init__(self):
# 所有活跃会话都存在这里
self.sessions = {} # 内存字典
def create_session(self, session_id):
self.sessions[session_id] = {
"id": session_id,
"created_at": "2024-01-15 10:00:00",
"last_activity": "2024-01-15 10:05:00",
"context": {
"history": [], # 历史交互记录
"variables": {}, # 上下文变量
"pending_actions": [], # 待处理的操作
"tool_states": {} # 各个工具的状态
}
}
```
**实际存储示例**:
```json
{
"session_abc123": {
"id": "session_abc123",
"created_at": "2024-01-15T10:00:00Z",
"last_activity": "2024-01-15T10:15:30Z",
"context": {
"history": [
{
"timestamp": "2024-01-15T10:00:05Z",
"role": "user",
"content": "帮我查一下北京的天气",
"tool_calls": null
},
{
"timestamp": "2024-01-15T10:00:08Z",
"role": "assistant",
"content": null,
"tool_calls": [{
"name": "weather_query",
"args": {"city": "北京"}
}]
},
{
"timestamp": "2024-01-15T10:00:12Z",
"role": "tool",
"content": "北京晴天,25度"
}
],
"variables": {
"current_city": "北京",
"last_query_type": "weather",
"user_preferences": {
"unit": "celsius",
"language": "zh"
}
},
"pending_actions": [],
"tool_states": {
"weather_tool": {
"last_query": "北京",
"query_count": 3
}
}
}
}
}
```
**关键点**:
- 这些数据默认存储在 **MCP Server 进程的内存**中
- 如果 MCP Server 重启,内存中的会话会丢失
- 这就是为什么需要层级3
---
### 层级3:外部持久化存储(可选但推荐)
为了让会话在服务重启后不丢失,MCP Server 可以配置**持久化存储**:
#### 选项A:Redis(最常用)
```yaml
# MCP Server 配置
storage:
type: redis
redis:
host: localhost
port: 6379
key_prefix: "mcp:session:"
ttl: 3600 # 会话过期时间1小时
```
存储结构:
```
Redis Key: mcp:session:abc123
Redis Value: {JSON 格式的会话数据}
TTL: 3600秒(1小时后自动删除)
```
#### 选项B:数据库
```sql
-- PostgreSQL 存储会话
CREATE TABLE mcp_sessions (
session_id VARCHAR(64) PRIMARY KEY,
context_data JSONB, -- 会话上下文(JSON格式)
created_at TIMESTAMP,
last_activity TIMESTAMP,
status VARCHAR(20) -- active/expired/completed
);
CREATE TABLE mcp_session_history (
id BIGSERIAL PRIMARY KEY,
session_id VARCHAR(64) REFERENCES mcp_sessions(session_id),
timestamp TIMESTAMP,
role VARCHAR(20), -- user/assistant/tool
content TEXT,
metadata JSONB
);
```
#### 选项C:文件系统
```
/mcp_sessions/
├── session_abc123.json
├── session_def456.json
└── session_ghi789.json
```
每个文件内容就是完整的会话 JSON 数据。
---
## 三、完整的存储架构图
```
┌─────────────────────────────────────────────────────────────┐
│ 用户浏览器/客户端 │
└─────────────────────────┬───────────────────────────────────┘
│ HTTPS
┌─────────────────────────▼───────────────────────────────────┐
│ Dify 应用服务器 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 数据库(PostgreSQL) │ │
│ │ ├─ conversations 表:存储对话元数据 │ │
│ │ │ {id, user_id, title, created_at} │ │
│ │ └─ messages 表:存储用户和AI的完整对话 │ │
│ │ {id, conversation_id, role, content, ...} │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ 记住 session_id │
│ ▼ │
└─────────────────────────────┬───────────────────────────────┘
│ MCP 协议
┌─────────────────────────────▼───────────────────────────────┐
│ MCP Server 服务器 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 内存(RAM) │ │
│ │ ├─ SessionManager.sessions = {} # 活跃会话缓存 │ │
│ │ │ session_abc: {context: {...}} │ │
│ │ │ session_def: {context: {...}} │ │
│ │ └─ 访问速度:极快(微秒级) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ 可选:定期持久化 │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 持久化存储(Redis/PostgreSQL/文件) │ │
│ │ ├─ Redis:会话过期自动清理,适合短期会话 │ │
│ │ ├─ PostgreSQL:永久存储,适合长期会话 │ │
│ │ └─ 文件系统:简单场景 │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
---
## 四、数据流向:一次完整对话的存储过程
```
1. 用户:帮我查一下北京天气
↓
2. Dify 收到请求
├─ 检查是否有 existing session
├─ 没有 → 创建新会话
└─ 存储:Dify 数据库记录这条消息
↓
3. Dify 调用 MCP Server(带着新 session_id)
↓
4. MCP Server 创建会话
├─ 在内存中创建 Session 对象
├─ 可选:持久化到 Redis/DB
└─ 存储:{session_id: abc123, context: {...}}
↓
5. MCP Server 执行天气查询
├─ 更新会话历史:添加 tool call 记录
└─ 更新变量:{current_city: "北京"}
↓
6. 返回结果给 Dify
↓
7. 用户追问:那上海呢?
↓
8. Dify 调用 MCP Server(带着同一个 session_id)
↓
9. MCP Server 根据 session_id 找到之前的会话
├─ 从内存中读取:current_city = "北京"
├─ 理解"那"指的是天气查询
└─ 执行新查询:上海天气
↓
10. 更新会话上下文
└─ current_city = "上海"
```
---
## 五、关键问题解答
### Q1:MCP Server 重启了,会话还在吗?
**默认情况**:不在。内存中的会话全部丢失。
**解决方案**:启用持久化存储
```yaml
# MCP Server 配置持久化
persistence:
enabled: true
backend: redis
redis_url: redis://localhost:6379/0
session_ttl: 86400 # 24小时
```
重启后,MCP Server 会从 Redis 恢复活跃会话。
### Q2:如果有很多用户同时使用,会话不会撑爆内存吗?
**会**,所以有管理机制:
1. **TTL(过期时间)**:每个会话设置存活时间
2. **LRU 淘汰**:内存满时淘汰最久未使用的会话
3. **分层存储**:
- 热会话:在内存中(最近活跃)
- 冷会话:在 Redis/DB 中(长期未活跃)
- 会话恢复时从 DB 加载到内存
### Q3:Dify 自己存了一份对话,MCP 又存一份,是不是重复了?
不重复,它们存的**层次不同**:
| 存储位置 | 存储内容 | 用途 |
|---------|---------|------|
| Dify 数据库 | 完整的用户-AI对话 | 展示给用户、导出、分析 |
| MCP Server | 工具调用状态、上下文变量 | 让工具理解上下文、保持状态 |
举例:
```
Dify 存的是:
用户:帮我查北京天气
AI:北京今天晴天
MCP 存的是:
session: {
current_city: "北京",
last_query_time: "10:00",
query_history: ["北京", "上海"],
user_preferences: {unit: "celsius"}
}
```
---
## 六、总结
**会话内容存在哪里?**
| 层级 | 存储位置 | 存储内容 | 持久化 |
|------|---------|---------|--------|
| **应用层** | Dify 数据库 | 对话历史、会话 ID | ✅ 永久 |
| **MCP 内存** | RAM | 当前活跃会话的完整状态 | ❌ 重启丢失 |
| **MCP 持久化** | Redis/DB/文件 | 会话的备份 | ✅ 可选 |
**核心要点**:
1. **默认存内存**:MCP Server 把会话存在自己的内存里,速度最快
2. **可配置持久化**:重要会话可以存到 Redis 或数据库
3. **会话 ID 是桥梁**:Dify 只记住 session_id,具体状态由 MCP Server 管理
4. **分层存储**:热数据在内存,冷数据在磁盘
简单说就是:**MCP Server 就像你的手机通话记录,通话中记录存在手机内存里,挂断后可以选择存到云端(持久化),下次通话时再从云端加载回来。**
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)