## 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 就像你的手机通话记录,通话中记录存在手机内存里,挂断后可以选择存到云端(持久化),下次通话时再从云端加载回来。**

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐