2026-09-14 12:21:26 +08:00
|
|
|
|
# CRM 接入小趣 MCP 手册
|
|
|
|
|
|
|
|
|
|
|
|
> 适用版本:REQ-20260911-0013(增量同步框架)交付后
|
|
|
|
|
|
> 端点:`https://agent.ququclean.com/mcp`(生产)/ `http://192.168.4.236:8088/mcp`(内网)
|
|
|
|
|
|
> 协议:MCP Streamable HTTP(JSON-RPC),所有响应为 SSE,取 `data:` 行
|
2026-09-15 18:24:13 +09:30
|
|
|
|
>
|
|
|
|
|
|
> 当前生产可用性、阻塞项和下一步以[对接进度](crm-sync-integration-progress.md)为准;本手册描述目标调用方式,不代表发布门禁已经通过。
|
2026-09-14 12:21:26 +08:00
|
|
|
|
|
|
|
|
|
|
## 0. 边界(先读这段)
|
|
|
|
|
|
|
|
|
|
|
|
小趣 MCP 只做三件事:**供数据、供身份、守权限**。
|
|
|
|
|
|
到期规则计算、AI 决策、推送、通知负责人、经营事项流转——全部是 CRM / 小趣 AI 系统的职责,MCP 不提供也不预留任何相关字段。
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 一次性开通
|
|
|
|
|
|
|
|
|
|
|
|
| 步骤 | 操作方 | 说明 |
|
|
|
|
|
|
|---|---|---|
|
2026-09-15 12:05:26 +09:30
|
|
|
|
| 1 | 小趣管理员 | 登录 `https://agent.ququclean.com/`,进入「服务密钥」→「创建服务密钥」 |
|
|
|
|
|
|
| 2 | 小趣管理员 | 调用方名称填 `crm`,勾选 `sync` 作用域,保存并立即复制只展示一次的 `X-Open-Key` |
|
|
|
|
|
|
| 3 | CRM 后端 | 用下面的请求换取**长期服务 Token**(`xqak-...`),安全保管 |
|
2026-09-14 12:21:26 +08:00
|
|
|
|
|
2026-09-15 12:05:26 +09:30
|
|
|
|
```bash
|
|
|
|
|
|
curl -X POST 'https://agent.ququclean.com/api/open/token/ensure' \
|
|
|
|
|
|
-H 'X-Open-Key: <管理后台创建后显示的服务密钥>' \
|
|
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
|
-d '{"scopeCode":"sync","principalType":"service","serviceName":"crm"}'
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
响应的 `token` 就是后续放进 MCP `Authorization: Bearer <token>` 的服务 Token。`X-Open-Key` 不是 MCP Token,不能直接放进 Authorization 头。
|
|
|
|
|
|
|
|
|
|
|
|
完成后 CRM 持有两样东西:**服务 Token**(后台扫描用)、**服务密钥**(重新 ensure 获取 Token 或给销售换个人 Token 用)。若还需要给销售换 QUERY 个人 Token,创建/编辑服务密钥时还要勾选对应 QUERY 作用域;只绑定 `sync` 的密钥不能跨域签发个人 Token。
|
|
|
|
|
|
|
|
|
|
|
|
密钥泄露时,管理员在同一页面点「轮换」(旧密钥立即失效)或「吊销」。数据库只保存密钥哈希,关闭创建/轮换结果弹窗后无法找回明文。
|
2026-09-14 12:21:26 +08:00
|
|
|
|
|
|
|
|
|
|
## 2. 每次调用前的身份自检
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
tools/call integration.context.get
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
返回 `principal_type` / `scopes` / `capability_levels` / `data_scope_version`。
|
|
|
|
|
|
|
|
|
|
|
|
- 后台扫描任务启动时必须确认 `principal_type=tenant_service` 且 capability 含 SYNC;拿错 Token(user_delegated)时**拒绝执行扫描**,防止串权。
|
|
|
|
|
|
- `data_scope_version` 变化说明管理员改了授权范围,建议触发一次全量重建。
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 后台通道:每日定时扫描(增量同步)
|
|
|
|
|
|
|
2026-09-15 19:23:08 +09:30
|
|
|
|
三个变化流工具:`users.changes.list` / `properties.changes.list` / `contracts.changes.list`。
|
2026-09-14 12:21:26 +08:00
|
|
|
|
|
|
|
|
|
|
入参只有三个(**禁止传 tenant_id/scope**,传了直接 PERMISSION_DENIED):
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{ "syncToken": null, "cursor": null, "limit": 200 }
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 协议语义
|
|
|
|
|
|
|
|
|
|
|
|
- **快照**:每轮同步签发 `snapshot_id` + `data_cutoff_at`,同一快照内翻页结果稳定,页间不会有数据漂移。
|
|
|
|
|
|
- **游标**:页内按 `(modify_time, id)` 复合游标推进;`has_more=true` 时用 `next_cursor` 翻下一页。
|
|
|
|
|
|
- **续传**:只有最后一页(`has_more=false`)才签发 `next_sync_token`。中断/宕机后从本地保存的 `sync_token + cursor` 继续,**不重不漏**。
|
|
|
|
|
|
- **tombstone**:`deleted_at` 非空的条目是被删除的数据,CRM 本地镜像应标记删除,不进 AI。
|
|
|
|
|
|
- **limit**:上限 200,传更大会被截断到 200 并带 notice。
|
|
|
|
|
|
|
|
|
|
|
|
### CRM 侧定时任务伪代码
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
token, cursor = load_local() # 首次均为 null → 全量
|
|
|
|
|
|
loop:
|
|
|
|
|
|
resp = call("contracts.changes.list", {syncToken: token, cursor: cursor, limit: 200})
|
|
|
|
|
|
for item in resp.items:
|
|
|
|
|
|
if item.deleted_at: 本地镜像标记删除(item.contract_id)
|
|
|
|
|
|
else: 本地镜像 upsert(item)
|
|
|
|
|
|
save_local(token, resp.next_cursor) # 每页都存,断点恢复
|
|
|
|
|
|
if resp.has_more: cursor = resp.next_cursor; continue
|
|
|
|
|
|
save_local(resp.next_sync_token, null) # 本轮结束,钉死新游标
|
|
|
|
|
|
break
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 错误分支(必须实现)
|
|
|
|
|
|
|
|
|
|
|
|
| 错误码 | 含义 | CRM 动作 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| `SYNC_CURSOR_EXPIRED` | 快照/游标过期或被篡改 | 清空本地镜像,syncToken=null 全量重建 |
|
|
|
|
|
|
| `RATE_LIMITED` | 触发 SYNC 限流档 | 指数退避重试(建议 1s/2s/4s…上限 60s) |
|
|
|
|
|
|
| `UNAUTHENTICATED` | Token 被吊销/人员停用 | 重新 ensure 取 Token,仍失败则告警人工介入 |
|
|
|
|
|
|
|
|
|
|
|
|
### 两个错误用法
|
|
|
|
|
|
|
|
|
|
|
|
- 不要拿 `version` 字段做并发控制——它由 `modify_time` 派生,只用于调试核对。
|
|
|
|
|
|
- 不要把扫描任务和销售在线查询混用同一个 Token——服务 Token 调 QUERY 工具会被拒(scope 白名单),这是设计如此。
|
|
|
|
|
|
|
2026-09-15 19:23:08 +09:30
|
|
|
|
### 发送前复核(不能省略)
|
|
|
|
|
|
|
|
|
|
|
|
日同步只负责发现候选。CRM 在晨报、午报或日结真正入推送队列前,必须使用同一个服务 Token 批量调用:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
tools/call contracts.current.batch_get
|
|
|
|
|
|
arguments: {"contractIds":["1001","1002"]}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- 每批 1—200 个稳定合同 ID,返回 `checked_at/count/items/not_found_ids`。
|
|
|
|
|
|
- `items` 使用与合同变化流相同的公开字段;软删合同返回删除标记,查无记录进入 `not_found_ids`。
|
|
|
|
|
|
- CRM 必须逐项复核状态、到期日、负责人、客户归属、提醒配置和续约结果。任一变化、缺失、删除、响应不完整、证据时间异常或服务不可用,对应合同本次都不得发送。
|
|
|
|
|
|
- 该工具属于 SYNC 能力和限流档,调用方传 `tenant_id/tenantId/scope` 会被拒绝;数据域只能来自服务 Token。
|
|
|
|
|
|
|
2026-09-14 12:21:26 +08:00
|
|
|
|
## 4. 前台通道:销售在线查询(实时 ACL)
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
1. 销售登录 CRM → CRM 后端调 /api/open/token/ensure {mobile: 销售手机号}
|
|
|
|
|
|
幂等,同一人永远拿到同一个个人 Token;缓存 "CRM用户 ↔ xqak ↔ userId" 映射。
|
|
|
|
|
|
2. 销售查合同时,带他的个人 Token 调:
|
|
|
|
|
|
- contract.list.query (列表,12 字段,自动按实时 ACL 行过滤)
|
|
|
|
|
|
- contract.detail.query (详情,含 version、files、processes)
|
|
|
|
|
|
3. 个人 Token 调 SYNC 工具直接被 scope 白名单拦截——销售永远扫不到全量数据。
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
个人 Token 缓存在 CRM 侧即可;收到 `UNAUTHENTICATED`(如人员被停用,60 秒内生效)时清缓存重取。
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 两条通道速查
|
|
|
|
|
|
|
|
|
|
|
|
| | 前台(销售点查) | 后台(定时扫描) |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| Token 类型 | user_delegated | tenant_service |
|
2026-09-15 19:23:08 +09:30
|
|
|
|
| 可用工具 | contract.list/detail.query 等 QUERY | *.changes.list + contracts.current.batch_get + context.get |
|
2026-09-14 12:21:26 +08:00
|
|
|
|
| 数据范围 | 实时 ACL 行过滤 | 管理员授权的 sync scope |
|
|
|
|
|
|
| 限流 | 常规档 | SYNC 独立档,互不占配额 |
|
|
|
|
|
|
| tenant_id 入参 | 不允许 | 不允许,从 Token 推导 |
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 通用输出规范
|
|
|
|
|
|
|
|
|
|
|
|
所有工具返回统一信封 `structuredContent`:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{ "schema_version": 2, "request_id": "...", "data": { ... } }
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- 请求头 `X-Mcp-Schema-Version: 2` 启用新信封;不带则返回老结构(v1,兼容期内有效)。
|
|
|
|
|
|
- 所有请求把 `request_id` 记入 CRM 日志,排查时两边对得上。
|
|
|
|
|
|
- **Token 和手机号明文不要落日志**(MCP 侧已对手机号打码,CRM 侧请同样处理)。
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 后续扩展
|
|
|
|
|
|
|
|
|
|
|
|
同步协议是通用框架:以后新增设备/订单/工单同步,CRM 侧代码不变,只是多调一个 `xxx.changes.list`、多存一对 `sync_token/cursor`。输出信封与错误码也不变。
|