306 lines
13 KiB
Markdown
306 lines
13 KiB
Markdown
# NS3:MCP Server 扩展 — mcp-server-ai-extension
|
||
|
||
> 优先级:中(可与 NS1/NS2 并行,批次 A 无前置依赖)
|
||
> 预估工作量:中等
|
||
> 前置条件:批次 A 无依赖;批次 B 依赖 P5-A(biz 表已建);批次 C 依赖批次 B
|
||
> 参考基准:`docs/prd/specs/P5.1-mcp-server-ai-extension.md`
|
||
|
||
---
|
||
|
||
## 一、背景与目标
|
||
|
||
当前 MCP Server(`apps/mcp-server/server.py`)仅连接 `etl_feiqiu` 数据仓库,提供 4 个工具(list_tables、describe_table、describe_schemas、query_sql),schema 白名单为 ods/dwd/dws/core/meta/app。SQL 安全通过正则禁词检测实现只读保护。
|
||
|
||
查库手册(`docs/mcp/AI-DATABASE-QUERY-MANUAL.md`)内容陈旧,DWS 层 34 张表缺少完整字段说明,业务库(zqyy_app)完全未覆盖。
|
||
|
||
本 SPEC 目标:
|
||
1. MCP Server 新增 `zqyy_app` 业务库连接,支持多数据库路由
|
||
2. 实现业务库敏感字段脱敏策略
|
||
3. 重写查库手册(ETL 全字段 + 业务库全字段 + 常用查询模式)
|
||
4. 手册上传百炼平台验证 AI 引用效果
|
||
|
||
### 当前 MCP Server 能力
|
||
|
||
| 工具 | 功能 | 限制 |
|
||
|------|------|------|
|
||
| `list_tables` | 列出指定 schema 下的表 | 仅 etl_feiqiu |
|
||
| `describe_table` | 查看表结构(列名、类型、注释) | 仅 etl_feiqiu |
|
||
| `describe_schemas` | 列出可用 schema 及表数量 | 仅 ods/dwd/dws/core/meta/app |
|
||
| `query_sql` | 执行只读 SQL 查询 | 正则禁词检测,单 schema 限制 |
|
||
|
||
---
|
||
|
||
## 二、技术架构
|
||
|
||
### 2.1 多数据库连接
|
||
|
||
```
|
||
apps/mcp-server/
|
||
├── server.py 🔧 扩展:多连接池 + schema 路由
|
||
├── db_pool.py 🆕 新建:连接池管理(etl_feiqiu + zqyy_app)
|
||
├── security.py 🆕 新建:敏感字段脱敏策略
|
||
└── config.py 🆕 新建:数据库配置(DSN、schema 白名单)
|
||
```
|
||
|
||
### 2.2 连接池设计
|
||
|
||
```python
|
||
# db_pool.py
|
||
class DatabasePool:
|
||
"""管理两个数据库的连接池。"""
|
||
|
||
pools = {
|
||
"etl": {
|
||
"dsn_env": "PG_DSN", # etl_feiqiu / test_etl_feiqiu
|
||
"schemas": ["ods", "dwd", "dws", "core", "meta", "app"],
|
||
"readonly": True,
|
||
},
|
||
"biz": {
|
||
"dsn_env": "APP_DB_DSN", # zqyy_app / test_zqyy_app
|
||
"schemas": ["auth", "biz", "public"],
|
||
"readonly": True, # MCP 只读,写操作走后端 API
|
||
},
|
||
}
|
||
```
|
||
|
||
### 2.3 Schema 自动路由
|
||
|
||
工具参数中不再需要显式指定 `database`,而是根据 schema 名称自动路由:
|
||
|
||
| Schema | 路由目标 | 说明 |
|
||
|--------|---------|------|
|
||
| `ods` / `dwd` / `dws` / `core` / `meta` / `app` | etl_feiqiu | ETL 数据仓库 |
|
||
| `auth` / `biz` / `public` | zqyy_app | 业务库 |
|
||
|
||
路由逻辑:
|
||
```python
|
||
def resolve_database(schema: str) -> str:
|
||
ETL_SCHEMAS = {"ods", "dwd", "dws", "core", "meta", "app"}
|
||
BIZ_SCHEMAS = {"auth", "biz", "public"}
|
||
if schema in ETL_SCHEMAS:
|
||
return "etl"
|
||
elif schema in BIZ_SCHEMAS:
|
||
return "biz"
|
||
else:
|
||
raise ValueError(f"未知 schema: {schema}")
|
||
```
|
||
|
||
### 2.4 工具扩展
|
||
|
||
4 个现有工具的参数不变,内部根据 schema 参数自动选择连接池:
|
||
|
||
| 工具 | 变更 |
|
||
|------|------|
|
||
| `list_tables(schema)` | schema 参数扩展接受 auth/biz/public |
|
||
| `describe_table(table, schema)` | 同上 |
|
||
| `describe_schemas()` | 返回结果增加 auth/biz/public 三个 schema |
|
||
| `query_sql(schema, sql)` | 根据 schema 路由到对应连接池 |
|
||
|
||
### 2.5 跨库查询限制
|
||
|
||
- 单次 `query_sql` 调用只能查询单个数据库(由 schema 参数决定)
|
||
- 禁止在 SQL 中引用其他数据库的 schema(现有 `_reject_cross_schema` 逻辑扩展)
|
||
- 如需跨库关联,AI 应分两次查询后在应用层组合
|
||
|
||
---
|
||
|
||
## 三、敏感字段脱敏策略
|
||
|
||
### 3.1 脱敏规则
|
||
|
||
| Schema | 表 | 敏感字段 | 脱敏方式 |
|
||
|--------|-----|---------|---------|
|
||
| `auth` | `users` | `wx_openid` | 前 4 后 4 保留,中间 `***` |
|
||
| `auth` | `users` | `phone` | 前 3 后 4 保留,中间 `****` |
|
||
| `auth` | `users` | `wx_session_key` | 完全隐藏,返回 `[REDACTED]` |
|
||
| `biz` | `ai_messages` | `content`(role=user) | 不脱敏(AI 需要理解对话内容) |
|
||
| `biz` | `ai_conversations` | — | 无敏感字段 |
|
||
| `public` | `member_retention_clue` | `recorded_by_assistant_id` | 不脱敏(非 PII) |
|
||
|
||
### 3.2 实现方式
|
||
|
||
在 `query_sql` 返回结果时,对命中脱敏规则的列进行后处理:
|
||
|
||
```python
|
||
# security.py
|
||
MASKING_RULES = {
|
||
"auth.users": {
|
||
"wx_openid": lambda v: f"{v[:4]}***{v[-4:]}" if v and len(v) > 8 else "[REDACTED]",
|
||
"phone": lambda v: f"{v[:3]}****{v[-4:]}" if v and len(v) >= 11 else "[REDACTED]",
|
||
"wx_session_key": lambda v: "[REDACTED]",
|
||
},
|
||
}
|
||
|
||
def mask_row(schema: str, table: str, columns: list[str], row: tuple) -> tuple:
|
||
"""对查询结果行应用脱敏规则。"""
|
||
```
|
||
|
||
### 3.3 脱敏绕过防护
|
||
|
||
- `SELECT *` 查询 auth.users 时自动应用脱敏
|
||
- 禁止通过 `CAST`、`CONCAT`、子查询等方式绕过脱敏(在 SQL 解析阶段检测)
|
||
- 对 auth.users 的查询结果始终应用列级脱敏,无论 SQL 写法
|
||
|
||
---
|
||
|
||
## 四、查库手册重写
|
||
|
||
### 4.1 手册结构
|
||
|
||
重写后的手册分为两个文件,便于维护和上传:
|
||
|
||
```
|
||
docs/mcp/
|
||
├── AI-DATABASE-QUERY-MANUAL.md 🔧 重写(总览 + ETL 库)
|
||
└── AI-DATABASE-QUERY-MANUAL-BIZ.md 🆕 新建(业务库)
|
||
```
|
||
|
||
### 4.2 ETL 库手册内容(重写)
|
||
|
||
保留现有架构流程和工具说明,重点补充:
|
||
|
||
1. **DWS 层完整表清单**(34 张表按业务域分组)
|
||
- 每张表列出全部字段(字段名、类型、中文说明)
|
||
- 标注关键字段的业务含义和使用注意事项
|
||
- 按业务域分组:会员域、助教域、财务域、配置域
|
||
|
||
2. **金额口径专章**
|
||
- `consume_money` 三种历史口径说明(A/B/C),明确标注"禁止直接使用"
|
||
- `items_sum` 定义和计算公式
|
||
- settle_type 枚举映射表(1=台桌结账 78.6%、3=商城订单 21.4%、5=充值、7=充值退款、6=结算退款)
|
||
- 助教费用拆分规则(assistant_pd_money 陪打 / assistant_cx_money 超休)
|
||
- 支付渠道恒等式(balance_amount = recharge_card_amount + gift_card_amount)
|
||
|
||
3. **会员字段断档说明**
|
||
- DQ-6:member_phone/member_name 自 2025-12 起 NULL,需 JOIN dim_member
|
||
- DQ-7:member_card_type_name 自 2025-07-21 起 NULL,需 JOIN dim_member_card_account
|
||
|
||
4. **常用查询模式**(ETL 侧)
|
||
- 客户消费汇总查询
|
||
- 助教绩效查询
|
||
- 财务日报查询
|
||
- 指数排名查询
|
||
|
||
5. **数据量统计与性能建议**
|
||
- 各表的大致数据量级
|
||
- 推荐的 WHERE 条件(时间范围、site_id)
|
||
- 避免全表扫描的建议
|
||
|
||
### 4.3 业务库手册内容(新建)
|
||
|
||
1. **Schema 概览**
|
||
- `auth`:用户认证(users、user_applications、site_code_mapping、user_assistant_binding)
|
||
- `biz`:业务数据(coach_tasks、notes、ai_conversations、ai_messages、ai_cache、trigger_jobs、salary_adjustments、excel_upload_log)
|
||
- `public`:共享数据(member_retention_clue)
|
||
|
||
2. **每张表完整字段说明**
|
||
- 字段名、类型、是否可空、默认值、中文说明
|
||
- 关键枚举值说明(如 coach_tasks.task_type、notes.type、ai_cache.cache_type)
|
||
- 外键关系和关联查询建议
|
||
|
||
3. **常用查询模式**(业务侧)
|
||
- 维客线索查询(按客户、按来源、按标签)
|
||
- 任务系统查询(按助教、按状态、按类型)
|
||
- 备注查询(按客户、按助教、含星星评分)
|
||
- AI 缓存查询(按应用类型、按 target_id)
|
||
- Excel 上传记录查询
|
||
|
||
4. **跨库关联指南**
|
||
- 业务库 member_id → ETL 库 dim_member 的关联方式
|
||
- 业务库 assistant_id → ETL 库 dim_assistant 的关联方式
|
||
- 注意:MCP 不支持单次跨库 JOIN,需分两次查询
|
||
|
||
### 4.4 数据字段权威参考
|
||
|
||
手册中涉及的 DWD/DWS 层字段来源、金额口径、业务逻辑,以 `docs/reports/DWD-DOC/` 校准文档为准(数据快照 2026-03-06)。
|
||
|
||
---
|
||
|
||
## 五、百炼平台上传与验证
|
||
|
||
### 5.1 上传方式
|
||
|
||
- 将重写后的手册作为知识库文档上传至百炼平台
|
||
- 关联到应用 1(通用对话),使 AI 在回答数据查询问题时可引用手册
|
||
|
||
### 5.2 验证场景
|
||
|
||
| 测试场景 | 预期行为 |
|
||
|---------|---------|
|
||
| "查询本月营业额" | AI 引用手册中的 dws_finance_daily_summary 表,使用 items_sum 口径 |
|
||
| "查看客户王先生的消费记录" | AI 引用 dim_member + dwd_settlement_head,通过 member_id 关联 |
|
||
| "助教张三的本月绩效" | AI 引用 dws_assistant_salary_calc,正确使用 assistant_pd_money 拆分 |
|
||
| "查看维客线索" | AI 引用业务库 member_retention_clue 表 |
|
||
| "查看用户申请列表" | AI 引用 auth.user_applications,对 phone 字段脱敏 |
|
||
|
||
### 5.3 验证标准
|
||
|
||
- AI 不再频繁调用 `describe_table`(手册已提供完整字段信息)
|
||
- AI 生成的 SQL 使用正确的金额口径(items_sum 而非 consume_money)
|
||
- AI 查询 auth.users 时返回结果中敏感字段已脱敏
|
||
- AI 能正确区分 ETL 库和业务库的查询路由
|
||
|
||
---
|
||
|
||
## 六、参考文档
|
||
|
||
| 文档 | 路径 | 用途 |
|
||
|------|------|------|
|
||
| P5.1 原始 spec | `docs/prd/specs/P5.1-mcp-server-ai-extension.md` | 需求定义基准 |
|
||
| 现有 MCP Server | `apps/mcp-server/server.py` | 当前实现参考 |
|
||
| 现有查库手册 | `docs/mcp/AI-DATABASE-QUERY-MANUAL.md` | 重写基础 |
|
||
| DWD-DOC 标杆 | `docs/reports/DWD-DOC/` | 字段语义、金额口径权威参考 |
|
||
| BD 手册-业务表 | `docs/database/BD_Manual_biz_tables.md` | biz schema 表结构 |
|
||
| BD 手册-认证表 | `docs/database/BD_Manual_auth_tables.md` | auth schema 表结构 |
|
||
| ETL BD 手册 | `apps/etl/connectors/feiqiu/docs/database/` | DWD/DWS 表结构 |
|
||
|
||
---
|
||
|
||
## 七、预审查清单(SPEC 启动前确认)
|
||
|
||
### 7.1 多数据库连接
|
||
|
||
1. **连接池大小**:zqyy_app 连接池的 min/max 连接数?与 etl_feiqiu 共享还是独立?MCP Server 的并发查询量预估?
|
||
2. **DSN 环境变量**:MCP Server 运行环境中 `APP_DB_DSN` 是否已配置?测试环境使用 `test_zqyy_app` 还是 `zqyy_app`?
|
||
3. **RLS 隔离**:MCP 查询 zqyy_app 时是否需要 `SET LOCAL app.current_site_id`?如果需要,site_id 从哪里获取(MCP 调用方传入?固定值?)?
|
||
4. **连接超时**:FDW 查询和业务库查询的超时时间是否需要不同设置?
|
||
|
||
### 7.2 安全与脱敏
|
||
|
||
5. **脱敏范围确认**:除 auth.users 外,还有哪些表/字段需要脱敏?biz.notes 的备注内容是否需要脱敏?
|
||
6. **脱敏粒度**:是否需要根据 MCP 调用方身份区分脱敏级别?(如管理员可看完整数据,AI 应用只看脱敏数据)
|
||
7. **SQL 注入防护**:现有正则禁词检测是否足够?是否需要升级为 SQL 解析器(如 sqlparse)?
|
||
8. **审计日志**:MCP 查询是否需要记录审计日志(谁查了什么表、什么时间)?
|
||
|
||
### 7.3 查库手册
|
||
|
||
9. **手册格式**:百炼平台对知识库文档的格式要求?Markdown 是否直接支持?是否需要转换为 PDF/TXT?
|
||
10. **手册拆分**:ETL 库和业务库是否拆分为两个知识库文档?还是合并为一个?
|
||
11. **手册更新机制**:表结构变更后,手册如何同步更新?是否需要自动化脚本从数据库 DDL 生成手册?
|
||
12. **DWD 层覆盖**:手册是否需要覆盖 DWD 层全部表的完整字段?还是只覆盖 DWS + 常用 DWD 表?
|
||
|
||
### 7.4 部署与运维
|
||
|
||
13. **MCP Server 重启**:新增连接池后,MCP Server 是否需要重启?是否支持热加载配置?
|
||
14. **监控指标**:是否需要监控 MCP 查询的响应时间、错误率、查询频次?
|
||
15. **降级策略**:zqyy_app 连接失败时,是否影响 etl_feiqiu 的查询?两个连接池是否需要独立故障隔离?
|
||
|
||
---
|
||
|
||
## 八、任务清单(草案,SPEC 细化后调整)
|
||
|
||
### 批次 A:查库手册 — ETL 库(无前置依赖)
|
||
- [ ] T1:重写 `AI-DATABASE-QUERY-MANUAL.md` — DWS 层 34 张表全字段说明(按业务域分组)
|
||
- [ ] T2:补充金额口径专章(consume_money 禁用说明 + items_sum 定义 + settle_type 映射)
|
||
- [ ] T3:补充会员字段断档说明(DQ-6/DQ-7)+ 常用 ETL 查询模式
|
||
|
||
### 批次 B:MCP Server 扩展 + 业务库手册(依赖 P5-A)
|
||
- [ ] T4:创建 `db_pool.py` — 双连接池管理(etl_feiqiu + zqyy_app)
|
||
- [ ] T5:扩展 `server.py` — 4 个工具支持 schema 自动路由
|
||
- [ ] T6:创建 `security.py` — 敏感字段脱敏策略实现
|
||
- [ ] T7:创建 `AI-DATABASE-QUERY-MANUAL-BIZ.md` — 业务库全字段说明 + 常用查询模式
|
||
|
||
### 批次 C:百炼平台验证
|
||
- [ ] T8:手册上传百炼平台并关联 AI 应用
|
||
- [ ] T9:执行验证场景测试(5 个场景),确认 AI 引用效果
|