# MCP 实时 API 服务器架构（2026-07-26 上线）

## 概述

将销售工作台数据从"定时管道写 JSON → 前端 fetch 静态文件"升级为"前端 fetch 后端 API → 后端按需拉 MCP + 内存缓存 → 返回实时数据"。

## 架构图

```
飞书项目 MCP (search_by_mql)
    ↓ HTTP POST JSON-RPC (token auth)
Python 后端 (销售工作台服务.py :8765)
    ├── mcp_pull_all()  → 翻页拉取 + moql_field_list 展平
    ├── MCP_CACHE dict  → 内存缓存（可配 TTL）
    └── GET /api/mcp/{type} → 返回 JSON
    ↓
Cloudflare Tunnel (board-celebrate-nylon-address.trycloudflare.com)
    ↓
CloudBase 前端 (index.html) → fetch API 端点
```

## 核心函数

### mcp_pull_all(mql_query, max_pages=50)

拉取全量 MCP 数据，自动翻页，展平 `moql_field_list` 为扁平 JSON。

关键细节：
- 每页 50 条，用 `session_id` 续拉后续页
- `data` 是 dict（key=group_id），不是 list
- `list[0].count` 是总行数，用于判断结束
- `moql_field_list` 需展平：`key_label_value` 取 `.label`

### 缓存层

```python
MCP_CACHE = {}  # {cache_key: {time: timestamp, data: [...]}}
MCP_CACHE_TTL = {
    'customers': 1800,   # 30分钟
    'orders': 300,       # 5分钟
    'complaints': 900,   # 15分钟
    'activities': 300,   # 5分钟
    'opportunities': 300 # 5分钟
}
```

缓存同时写 JSON 备份文件（`数据/mcp_{type}.json`），后端重启时恢复。

## API 端点

| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/mcp/customers` | GET | 客户数据，支持 `?refresh=1` 强制刷新 |
| `/api/mcp/orders` | GET | 销售订单 |
| `/api/mcp/activities` | GET | 活动数据 |
| `/api/mcp/complaints` | GET | 客诉数据 |
| `/api/mcp/opportunities` | GET | 商机数据 |
| `/api/mcp/refresh` | POST | `{"type":"all"}` 批量刷新 |

## MQL 表名对照

| 数据 | type_key | MQL 表名 |
|------|----------|----------|
| 客户 | `65ae1e403c87b152f3365ca6` | `销售管理.65ae1e403c87b152f3365ca6` |
| 活动 | `65ae1e5d44338dbe7c39a29a` | `销售管理.65ae1e5d44338dbe7c39a29a` |
| 订单 | `662612aea6bb7089fea044ef` | `销售管理.662612aea6bb7089fea044ef` |
| 商机 | `story` | `销售管理.story` |
| 客诉 | `issue` | `销售管理.issue` |

⚠️ 必须用完整 type_key，不能用 api_name 别名（`kh`/`xsdd`/`sj` 报 "not found"）。

## 已知问题

- 客户字段 `field_ec1e8b`（行业）、`field_e769ee`（国家）当前 MCP token 无读权限
- 大批量（1678 客户）首次拉取 ~100 秒，缓存后命中 <50ms
- Tunnel URL 重启变化，前端 `AUTH_URLS` 需同步更新
- `SELECT *` 不支持，必须显式列出所有字段
