Files
opsxdb/docs/15-AI-MCP-Agent.md
logan 2c0bfafd8d 同步完整源码至远程:扁平化重构现状 + 未入库源文件
- 补入库:server/internal/db/dump.go、redis 分页/扫描预算测试、opsxdb-mcp main_test、
  packages/opsxdb-mcp package-lock、docs 审计与对比文档等 37 个新文件
- 含结构扁平化进行中的 80 处修改与 155 处旧结构删除(server/ src/ src-tauri/ 为当前有效源)
- 构建产物(bin/target/dist)与签名私钥仍按规则排除
2026-10-16 03:47:33 +08:00

263 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OpsxDB AI / MCP / Agent 任务书
> 当前行为(2026-10-15 更新):新配置默认启用读写与危险 SQL,连接仍需明确授权;旧配置沿用原权限,设置 → MCP 可一次性「使用默认权限」。设置页移除权限开关,改为紧凑状态展示。Agent 生成写命令后弹出确认框,展示连接、数据库和完整命令;仅确认当前一条,模型不能代确认。下文 P0 只读默认的描述属于历史阶段规划。
> 更新:2026-10-15 · 用户拍板:**先 MCP,再内部会话,最后 GUI 联动**
> 对标:优先 [DBX MCP](https://github.com/t8y2/dbx)(`packages/mcp-server` / `crates/dbx-mcp`);架构思路参考 oh-my-pi;可选对照 Google MCP Toolbox for Databases、DBHub、官方 MCP SDK。
## 产品结论(已采纳用户补充)
### 2026-10-15 产品 / PM / 设计确认(锁定)
| 项 | 决议 |
|----|------|
| 顺序 | MCP-first → 内部会话共用 Tools → GUI 插入/回写 |
| 首版引擎 | **仅** MySQL 族 + PostgreSQL + Redis;其它库不进 P0 |
| 写操作 | **P0 纯只读**;「确认后才可写」复用现有 dangerConfirm,进 **P1**,MCP 首版不可写 |
| 代码边界 | 只动根级 `src` + `server`;禁止 `packages/ui`(死树) |
| Redis | 对齐现有精确 TYPE / 集群 SCAN,不另起搜键 |
| UI | Ask\|Agent + SSE 时间线 + 插入/结果区 + MCP 状态点已落地;P1 确认条已接 |
| 冲突 | 与未推「补偿包」冲突先停报,勿 silently 覆盖 |
| 问题 | 结论 |
|------|------|
| 能不能用 AI 做 MySQL/Redis 等操作? | 能。底座 `/api/db/*` + danger 已有,缺的是工具层。 |
| 借鉴谁? | **优先 DBX**(MCP 工具粒度、只读/可写、连接 scope、审计)。oh-my-pi 借工具调用/会话规范,不当成 DB 产品抄。 |
| 要不要先做 MCP? | **要,优先做 MCP**。内部 AI 会话与 Cursor/Claude/Codex/omp **共用同一套 Tools**,避免两套逻辑。 |
| 形态 | GUI 管连接与会话;MCP 暴露安全的数据操作;Gin 仍是官网/docs,**不是**远程协作后端。 |
## P0 / P1 边界(2026-10-15 收紧)
| 阶段 | 范围 |
|------|------|
| **P0(本轮)** | **纯只读**。`execute_query` 只允许 SELECT/SHOW/EXPLAIN/DESCRIBE/PRAGMA/WITH…SELECT;任何写/DDL **一律拒绝**(**不做** write mode / confirm token)。Redis 仅白名单读命令(GET/SCAN/TYPE/TTL…);FLUSH*/KEYS/写命令拒。MCP stdio + tool runtime + 连接落盘 + 审计。 |
| **P1** | 可写 + 确认令牌/策略;内部 Ask \| Agent UI(设计阶段 2,**先只记文档不实现**);GUI 联动(插入编辑器 / 结果网格);设置页 MCP 白名单 UI。 |
设计阶段 2(内部会话 Ask \| Agent):Agent 调同一 `aitools` runtime;Ask 保持现有生成/解释/优化。**本轮不实现 UI。**
## 落地顺序(锁定)
1. **核心 MCP Tools(最小集)** + 连接落盘可读
2. **安全策略**:默认只读、危险 SQL 拦截、连接白名单、审计日志
3. **内部 AI 会话**:Ask \| Agent;Agent 调同一工具层(进程内调用,不必绕 stdio)
4. **GUI 联动**:SQL 一键插入编辑器;结果可回写网格 / 展示
## P0 工具契约
| Tool | 说明 | 安全默认 |
|------|------|----------|
| `opsxdb_list_connections` | 列出可见连接(id/name/driver/host,无密码) | 受白名单过滤 |
| `opsxdb_list_databases` | 列库 | 连接须在白名单 |
| `opsxdb_list_tables` | 列表/视图(及引擎等价物) | 只读 |
| `opsxdb_describe_table` | 字段与表元数据 | 只读 |
| `opsxdb_get_schema_context` | 紧凑 schema 文本,供模型上下文 | 截断上限(与现 AI schema cap 对齐,约 4k) |
| `opsxdb_execute_query` | 执行 SQL;最多 N 行(建议 100) | **P0 纯只读**(非读语句直接拒绝);可写+确认 = P1 |
| `opsxdb_execute_redis_command` | 执行一条 Redis 命令 | **P0 仅读命令白名单**;FLUSH*/KEYS/写一律拒;P1 再开确认写 |
首版引擎验收:**MySQL 族 + PostgreSQL + Redis(单机)**;其余引擎有连接即可试,不阻塞发版。
## 安全策略(MCP 层统一)
- **P0 强制只读**:`execute_query` 非读类 SQL 一律拒绝;`mcp.json` 的 `mode=read_write` 本轮不生效(P1 才启用写+确认)
- 复用 `server/internal/db/danger.go` 的危险词表;无 WHERE 的 DELETE/UPDATE 拦截
- **连接白名单**(配置文件 `~/.opsxdb/mcp.json`:`allowed_connection_ids`;空=拒绝全部或仅显式 allow——首版建议「空=拒绝」,避免默认放开)
- **行数 / 字节上限**;超时;取消
- **审计**:`~/.opsxdb/logs/mcp-audit.jsonl`(时间、tool、connection_id、只读/写、摘要、错误;不含密码/全文大结果)
- 不暴露:增删连接、原始密码、远程 HTTP 无 token 的开放端口(stdio 默认;本机 HTTP 可选且必须 bearer)
## 连接存储(MCP 可读)
现状:连接在桌面 `localStorage`(`opsxdb.connections.v1`),独立 MCP 进程读不到。
**本轮必做:** GUI `saveConnections` 同步写 `~/.opsxdb/connections.json`(脱敏字段完整、密码仍按现有混淆策略;MCP 与桌面同钥/同解码逻辑,或 MCP 仅经本机已打开的 session——优先**文件同步 + 现有 secrets 解码**,与 DBX「读桌面连接库」同构)。
## 内部会话与 MCP 的关系
```
┌─────────────┐ ┌──────────────────┐ ┌─────────────┐
│ Cursor/omp │───▶│ opsxdb-mcp │───▶│ tool runtime │
└─────────────┘ │ (stdio/HTTP) │ │ (db.* API) │
└──────────────────┘ └──────┬──────┘
┌─────────────┐ ┌──────────────────┐ │
│ 侧栏 Agent │───▶│ 同一 tool runtime │◀───────────┘
└─────────────┘ └──────────────────┘
```
侧栏 **不要**再直接拼 prompt 假装执行;Agent 模式只通过 tool runtime。Ask 模式保持现有生成/解释/优化(可不调执行工具)。
## GUI 联动(第 4 步,可薄)
- 工具结果中的 SQL →「插入当前编辑器」
- `execute_query` 结果 → 可选「在结果网格打开」(限行)
- ~~设置页:MCP 开关说明、白名单、只读/可写、复制 Cursor `mcp.json` 片段~~ ✅ 设置 → MCP
## 刻意首版不做
- MCP 增删连接、Kafka/MQ、桌面 `open_table` 远程遥控(可后置)
- 把 Gin `:8788` 做成公网 Agent 后端
- 两套危险策略(GUI 一套、MCP 一套)
## 验收清单
- [x] `opsxdb-mcp` stdio:`tools/list` 含上表工具(二进制 + 单测注册表)
- [x] 白名单外连接调用失败且有明确错误(空白名单=拒绝全部)
- [x] 只读模式下 `DELETE`/`DROP`/写 SQL 被拒;审计写 `mcp-audit.jsonl`
- [x] 通路代码就绪;单测用 sqlite 覆盖 list/describe/exec;MySQL/PG 真库待桌面验收
- [x] Redis 读白名单 + FLUSH*/KEYS/写拒(单测);真库待验
- [x] 侧栏 Agent 调同一 runtime(Ask|Agent + `/api/ai/agent` SSE + 步骤时间线 + 结果区/确认)
- [x] 文档:`docs/mcp-cursor.example.json` + 本文件
## 参考路径(本机)
- DBX:`/Users/logan/devops/demo/db-gui/dbx/packages/mcp-server`、`crates/dbx-mcp`
- oh-my-pi:`/Users/logan/devops/demo/ai-agent/oh-my-pi/docs/mcp-*.md`、`docs/custom-tools.md`
- OpsxDB 现有:`server/internal/db/*`、`server/internal/ai/*`、`src/AiPanel.tsx`、`docs/DATABASE-OPERATIONS-AUDIT.md`
## P0 验收方式(命令行优先)
> 产品边界:P0 是 **MCP 工具层**,不是 Web 工作台。验收不走浏览器 `:5174`/官网;Web 只看文档。DeepSeek 侧栏 **Ask 写 SQL** 已可测生成;**Agent 调工具查真库**属阶段 2。
### 环境(本机已有)
| 库 | 端口 | 账号 | 说明 |
|----|------|------|------|
| MySQL 8.4 (`opsxdb-mysql`) | 3306 | root 或 opsx / `Demo@123`,库 `demo` | `tests/dbctl.sh up a` |
| Redis 7 (`opsxdb-redis`) | 6379 | 无密码 | `tests/dbctl.sh up f` |
### A. 单测(无真库也可)
```bash
cd /Users/logan/devops/opsxdb/server
go test ./internal/aitools/ -count=1
```
覆盖:白名单拒绝、只读挡 DROP/DELETE、Redis 危险命令拒绝。
### B. 真库 MCP(推荐主路径)
1. GUI 里保存 MySQL / Redis 连接一次(会双写 `~/.opsxdb/connections.json`),记下 `id`。
2. 写白名单:
```bash
mkdir -p ~/.opsxdb/logs
cat > ~/.opsxdb/mcp.json <<'EOF'
{
"mode": "read_only",
"allowed_connection_ids": ["<mysql-conn-id>", "<redis-conn-id>"]
}
EOF
```
3. 编译并跑:
```bash
cd /Users/logan/devops/opsxdb/server
go build -o ../bin/opsxdb-mcp ./cmd/opsxdb-mcp
# Cursor:mcp.json 指向该二进制;或用临时脚本对 stdio 发 initialize + tools/list + tools/call
```
4. 用例清单:
| # | 工具 | 期望 |
|---|------|------|
| 1 | list_connections | 只见白名单内连接,无密码字段 |
| 2 | list_tables(MySQL demo) | 有表名 |
| 3 | describe_table | 有列 |
| 4 | get_schema_context | 截断文本 |
| 5 | execute_query `SELECT … LIMIT 10` | 有行,≤100 |
| 6 | execute_query `DROP TABLE …` | **拒绝** + 审计 |
| 7 | execute_redis_command `PING` / `GET` | 成功 |
| 8 | execute_redis_command `FLUSHDB` | **拒绝** |
| 9 | 白名单外 connection_id | **拒绝** |
| 10 | 审计文件 | `~/.opsxdb/logs/mcp-audit.jsonl` 有记录 |
### C. DeepSeek(当前能验什么)
- **现在**:设置里选 DeepSeek → Ask「生成/解释」对当前 Tab SQL(不执行工具)。
- **阶段 2**:Agent 模式多轮调同一 MCP tool runtime,再验「让 AI 查 demo 表结构再写 SELECT」。
### D. 验收通过后交付物
在本机 `~/Downloads/` 生成:`AI-Agent接入GUI工具开发实践.md`,供 opsxapi / opsxshell 及其他项目复用(MCP-first、只读默认、连接落盘、Ask|Agent、危险确认)。
## 设计备忘(阶段 2–4,P0 不实现)
来源:设计师 2026-10-15。紧凑桌面、深浅主题;不抄 dbx 整屏工具条。
1. **Ask | Agent**:输入框上方同高同宽小分段;Ask/Agent 不同占位;危险写在执行前确认条(结果区顶或气泡内),Ask 不生成执行条;模式跟连接/Tab,切换不丢草稿。
2. **步骤时间线**:挂在该条 Agent 回复下,可折叠,默认最近 3 步;行内状态点+工具名+一行摘要+耗时;点开才见全文;无独立全高工具面板。
3. **插入/结果**:气泡底「插入当前查询」+「新开查询」;行列结果才给「在结果区打开」;默认不抢焦点。
4. **MCP 状态**:设置 → AI/MCP(开关+白名单);有活跃外部会话时标题旁小点「MCP」,悬停摘要,点开最近调用可断开;无活跃不显示。
落地次序:MCP 开关+白名单 → Ask|Agent Seg → 时间线与插入 → MCP 状态点。
### 阶段 2(内部 Ask | Agent)2026-10-15
| 项 | 说明 |
|----|------|
| Ask | 侧栏分段 **Ask**:走既有 `/api/ai/chat`,不调工具(生成/解释/优化) |
| Agent | 分段 **Agent**:`POST /api/ai/agent` → `ai.RunAgent` → 进程内 `aitools.Runtime.Call`(与 MCP 同源) |
| 协议 | Agent tool calling 支持 openai-chat、Anthropic 与 OpenAI Responses;云模型真链路仍需实测 |
| 安全 | 默认只读;工具限定当前连接/库,模型不能自行确认写入;白名单 / 审计同 MCP |
| UI | 输入框上 Ask\|Agent;回复下可折叠步骤时间线(默认最近 3 步) |
| 单测 | `go test ./internal/ai/ ./internal/aitools/`(含 mock tool loop) |
| 真库冒烟 | `cd server && go run ./cmd/opsxdb-agent-accept/`(需 `~/.opsxdb/ai.json` 真 key) |
手动测:打开侧栏 → Agent →「列出 demo 有哪些表并查 users 几行」→ 步骤应出现 `list_tables` / `execute_query`。
### 真库验收 2026-10-15
MySQL 3306 demo + Redis 6379:`go run ./cmd/opsxdb-mcp-accept/` 全过。实践文档:`~/Downloads/AI-Agent接入GUI工具开发实践.md`。
### 本地回归 2026-10-15(当前隔离执行环境)
| 路径 | 结果 |
| --- | --- |
| `go test ./internal/ai/ ./internal/aitools/ ./internal/server/ -count=1` | 通过;补测 Ask 不强制生成 SQL、MySQL Agent 越界连接/库拒绝、Redis DB1 GET 与 SET 需确认 |
| stdio MCP `initialize` / `tools/list` / `tools/call` | 7 个工具可列出;MySQL `DROP` 与 Redis `FLUSHDB` 均按只读策略拒绝 |
| `opsxdb-mcp-accept` | 连接列表通过;MySQL `127.0.0.1:3306` 遇 `operation not permitted`,后续真库调用未运行 |
| `opsxdb-crud-accept` | 只读拒写通过;MySQL 预检同样被本地连接权限拦截,未进入真实写操作;命令已改为预检失败立即停止并显示原因 |
| `opsxdb-agent-accept` | 真模型请求在解析 `api.deepseek.com` 时失败(`no such host`),未得到模型与真库结果 |
| 桌面交互 | Computer Use 自动审批拒绝访问 OpsxDB;未验证桌面按钮、视觉和真库操作 |
上述限制只影响本次环境的真库/云模型回归;不可将失败命令记为产品功能验收通过。实际真库重测仍执行本节 P0 命令,并核对唯一标记的数据写入与清理。
## 会话产品层(阶段 5,2026-10-15)
工具面(MCP / Ask|Agent / SSE / P1 确认)已齐;下一层是 **会话生命周期**。权威契约见 **[16-AI-Session-Harness.md](./16-AI-Session-Harness.md)**:
| 项 | 说明 |
|----|------|
| RunOutcome | `completed` / `incomplete` / `failed` / `cancelled` / `awaiting_confirm` |
| 真·续跑 | 落盘 tool 轨迹 + 注入 prior;仅气泡回放不算 |
| Harness | MaxRounds、trim、循环拒、检查点(桌面裁剪,无 Evolver) |
| 排队 | 忙时单槽 pending(对齐 aiops 14) |
| 安全 | 脱敏落盘;写确认绑定 connection+语句哈希 |
本轮代码:outcome / run_id 审计 / TrimMessages / Redact / ConfirmBind;会话 HTTP 与排队 UI 后挂。
## 阶段 3–4 完成记录(2026-10-15)
| 项 | 状态 |
|----|------|
| Agent SSE | ✅ `stream=true` / `Accept: text/event-stream`;步骤边推 + 正文分块;非流式 JSON fallback;停止=Abort |
| Anthropic / responses tool calling | ✅ 解析与回灌单测;DeepSeek 仍走 openai-chat |
| 在结果区打开 / 插入编辑器 | ✅ 气泡步骤与代码块动作;不抢编辑器 focus |
| MCP 状态点 | ✅ 仅 `source=mcp` 近 5 分钟活跃时显示;`GET /api/ai/mcp-status` |
| P1 可写+确认 | ✅ 默认只读;`mode=read_write` + 确认条 / `confirm_danger`;Agent 剥离模型自带令牌;`POST /api/ai/agent/confirm` |
| 官网/文档 | ✅ intro / AI / FAQ + homepage AI/MCP 文案;**未**宣传默认可写 |
手动测:
```bash
cd server && go test ./internal/ai/ ./internal/aitools/ ./internal/server/ -count=1
# 侧栏 Agent:发问看步骤流式出现;有行列结果点「在结果区打开」
# 写:mcp.json mode=read_write 后让 Agent 尝试写 → 气泡确认条 → 执行/取消
# MCP:npx @rlwj-lab/opsxdb-mcp 调工具后侧栏应出现 MCP 点
```