Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Database CLI Plugin

📖 项目主页:https://cassianflorin.github.io/database-cli/ — 安全模型概览、护栏演示与快速上手

这是一个 CLI-first 的 Codex Plugin,内置 database-cli Skill。它面向数据库问题排查:查看表结构、搜索 schema/table/column/index/procedure、执行有范围的 SQL、跨环境核对记录,以及在需要修数时产出或执行用户明确允许的变更 SQL。

底层使用 sq 作为数据库 CLI 后端,并通过本项目的 wrapper 做安全限制。scripts/db-query 是唯一真实执行入口;scripts/database-mcp 是可选的薄适配层,只把同一套 CLI 能力暴露给支持 MCP 的客户端。

核心理念

database-cli 不是 DBHub 替代品,也不是 MCP 平台。它的核心是一个可安装、可审计、可由 Agent 和人类共同使用的数据库 CLI Skill。

项目边界:

  • CLI 是产品本体:安装、配置、临时连接、schema 搜索、SQL 安全校验和修数 SQL 工作流都先落在 scripts/db-query 和 Skill 指令中。
  • MCP 是适配层:scripts/database-mcp 不能另起查询逻辑,只能委托 CLI;安全规则必须由 CLI 层兜底。
  • Skill 是使用规范:Agent 应按 SKILL.md 先确认环境、读取真实 schema、默认执行有界只读查询;需要改数据时,必须先获得用户明确允许,再使用显式写入开关。
  • 不追求 DBHub 平台能力:不做 Workbench、权限平台、多租户服务端或独立数据库管理产品。

能力范围

  • 通过 scripts/db-query 执行 SQL,这是唯一真实执行入口;默认只读,只有显式 --allow-write 才允许 DML。
  • 通过 scripts/db-query --setup-status 输出 Agent 友好的安装状态、缺失项和下一步动作;这个命令不连接数据库。
  • 通过 SKILL.md 固化 Agent 查询流程、安全边界和人工修数 SQL 输出规范。
  • 通过 scripts/database-mcp 可选暴露 stdio MCP 工具;它只委托 scripts/db-query,不拥有独立查询逻辑。
  • 可通过本地 connections.local.json 保存连接配置,也可以由用户在单次调用里提供 --url--host、用户名和密码环境变量等连接信息。
  • 按环境/账号权限管理连接,例如 qa01prod,让 Agent 和开发者使用同一套入口。
  • 连接配置支持 display_nameenvironmentprojectdescriptionaliases 等元信息,便于 Agent 选择正确连接。
  • 默认按数据库实例/服务端连接,不把配置限制到某个 database/schema。
  • 支持只配置域名,不配置端口;适用于域名或反向代理已处理端口的场景。
  • 支持对象搜索:schema、table、column、index、procedure/function metadata,并支持 namessummaryfull 三档详情。
  • 支持配置级 max_rows 上限;readonly=false 会被拒绝,不会用配置隐式打开写权限。
  • 默认拦截写入;用户明确允许后可用 --allow-write 执行 INSERTUPDATEDELETEREPLACE。DDL、权限、事务、过程、锁、导出和副作用 SQL 仍会被拦截。
  • 写权限由配置声明,不由命令行声明:环境必须写明 "writable": true 才接受 --allow-write,临时连接(--url/--host)则需要额外的 --writable,避免把受保护的库改写成临时连接绕过配置。
  • 已批准的 UPDATE/DELETE 在执行前会先 COUNT 实际影响行数,超过 max_write_rows(默认 1000)直接拒绝,WHERE 1=1 这类看似有 WHERE 实则全表的语句不会放行。
  • 避免把密码写入命令行 DSN;本地密钥文件不提交到仓库。

目录结构

.
├── .codex-plugin/
│   └── plugin.json
├── INSTALL.md
├── README.md
├── skills/
│   └── database-cli/
│       ├── SKILL.md
│       ├── agents/openai.yaml
│       ├── references/
│       │   ├── config.example.json
│       │   └── config.md
│       └── scripts/
│           ├── database-mcp
│           ├── db-query
│           ├── install
│           └── init-config
└── scripts/
    ├── database-mcp
    ├── db-query
    ├── install
    └── init-config

安装并初始化

安装或复制这个 Plugin 后,在插件根目录运行安装入口:

scripts/install

这个命令会:

  1. 检查本机是否已安装 sq
  2. 如果没有 sq,询问是否通过 Homebrew 安装。
  3. 向用户收集数据库连接信息。用户可以给完整数据库链接,也可以分开给 driver、host、用户名、密码或密码环境变量。
  4. 生成本地 connections.local.json

标准 Codex Plugin/Skill 安装机制不会自动执行任意 post-install hook。因此,scripts/install 是这个插件的安装后必跑配置入口。

如果已经知道连接信息,优先用一条命令完成依赖检查和配置写入:

scripts/install \
  --env qa01 \
  --url "mysql://mysql-qa01.example.internal" \
  --display-name "QNVIP QA01" \
  --environment qa01 \
  --project qnvip \
  --description "QA01 shared readonly connection; search all visible schemas unless narrowed." \
  --alias qa-01 \
  --username readonly_user \
  --password-env QA01_DB_PASSWORD \
  --non-interactive

这条命令会把连接参数透传给 scripts/init-config。如需写到指定配置文件,可加 --config /path/to/connections.local.json;如需覆盖已有环境,可加 --force

安装后优先让 Agent 运行状态检查,而不是直接尝试连接数据库:

scripts/db-query --setup-status

输出是 JSON,包含 readysq_availableconfigenvironmentsconnectionsproblemsnext_actions。Agent 应先按 next_actions 处理缺失项;只有 ready=true 且用户确认目标环境后,才继续做真实只读查询。

从已有查询习惯迁移

如果你已经知道常用环境名和连接信息,不需要先理解 sq 的 source 管理方式,直接用 scripts/install 创建本地环境即可:

scripts/install \
  --env qa01 \
  --url "mysql://mysql-qa01.example.internal" \
  --display-name "QNVIP QA01" \
  --environment qa01 \
  --project qnvip \
  --description "Shared QA readonly connection; search all visible schemas unless narrowed." \
  --alias qa-01 \
  --username readonly_user \
  --password-env QA01_DB_PASSWORD \
  --non-interactive
scripts/db-query --setup-status
scripts/db-query --list-envs
scripts/db-query --env qa01 --sql "SELECT 1"

建议保留你原来习惯的环境名,并把连接理解为“这个环境下账号可访问的一组库”,而不是某一个 database。--setup-status--list-envs 会返回连接元信息,帮助 Agent 判断该用哪个连接。真正查询数据时,在 SQL 里写全限定表名:

scripts/db-query --env qa01 --sql "SELECT id FROM qnvip_center_commerce.cc_order WHERE order_no = 'YP...'"

对象搜索

如果只知道表名、字段名或索引名的一部分,可以直接查 metadata,不必先手写 information_schema SQL。默认不要要求用户先指定 database;不传 --schema 时,会在当前连接账号权限可见的 schema/database 范围内搜索:

scripts/db-query --env qa01 --search-objects "%cc_order%" --object-type table
scripts/db-query --env qa01 --search-objects "%order_no%" --object-type column --table cc_order
scripts/db-query --env qa01 --search-objects "%idx_order%" --object-type index --table cc_order
scripts/db-query --env qa01 --search-objects "%sync_order%" --object-type procedure
scripts/db-query --env qa01 --search-objects "%calc%" --object-type function --detail-level full

当结果过多或用户已明确范围时,再用 --schema 收窄:

scripts/db-query --env qa01 --schema qnvip_center_commerce --search-objects "%order_no%" --object-type column

--detail-level 支持:

  • names:只返回对象定位字段。
  • summary:返回常用排查字段,默认值。
  • full:返回更完整的 metadata,例如 MySQL routine definition、table comment、index detail 等。

当前对象搜索支持 MySQL/MariaDB/Postgres 直连配置。其他数据库或高级 sq source 配置仍可使用:

scripts/db-query --env qa01 --inspect
scripts/db-query --env qa01 --inspect cc_order

可选 MCP 适配层

scripts/database-mcp 是一个无额外 Python 依赖的 stdio MCP adapter。它不是独立产品入口,实际查询、校验、限流和连接配置仍全部复用 scripts/db-query。它提供:

  • setup_status:返回安装状态、缺失项和下一步动作;不连接数据库。
  • list_envs:列出当前配置的环境。
  • add_connection:运行中的 Agent 新增或更新连接配置;后续工具调用会立即读取新配置,不需要重启 Agent。
  • query_readonly:执行只读 SQL。
  • execute_sql:执行 SQL,默认只读;用户明确允许后传 allow_write=true 才允许 DML。
  • inspect:查看 source 或表结构。
  • search_objects:搜索 schema/table/column/index/procedure/function metadata。
  • check_sql:只校验 SQL 安全性,不执行。

每次 tools/call 都保留文本 content,并额外返回 structuredContent,包含 exit_codestdoutstderr,以及 stdout 可解析为 JSON 时的 json 字段。

如果 connections.local.json 配置了 top-level tools,MCP tools/list 会额外暴露这些参数化工具。custom tool 是 MCP 适配层的辅助能力,不是项目主线。它的 SQL 使用 :param_name 占位,调用时会先把参数渲染为 SQL literal,再交给 scripts/db-query 做只读校验和 max_rows 限制。

{
  "environments": {
    "qa01": {
      "driver": "mysql",
      "host": "mysql-qa01.example.internal",
      "username": "readonly_user",
      "password_env": "QA01_DB_PASSWORD",
      "max_rows": 100
    }
  },
  "tools": {
    "find_order": {
      "description": "Find one order by order number.",
      "env": "qa01",
      "sql": "SELECT id, order_no, status FROM cc_order WHERE order_no = :order_no",
      "parameters": {
        "order_no": {
          "type": "string",
          "description": "Order number."
        }
      }
    }
  }
}

MCP 客户端如需结构化工具入口,可以把 command 指到插件根目录下的入口:

/path/to/database-cli/scripts/database-mcp

也可以在安装到任意目录后使用对应的绝对路径。连接配置仍由 connections.local.jsonDATABASE_CLI_CONFIG 控制。

通过 Agent 安装和修改配置

用户可以直接让 Agent 代为安装和初始化。推荐把下面这段发给 Agent:

请使用 GitHub CLI 安装 database-cli:
1. 如果本地没有仓库,运行 gh repo clone CassianFlorin/database-cli "$HOME/src/database-cli"。
2. 进入 "$HOME/src/database-cli"。
3. 把 skills/database-cli 安装到 ~/.codex/skills/database-cli(可用符号链接)。
4. 运行 scripts/install,帮我完成 database-cli 的安装后配置;如果我已给出连接信息,直接把 --env/--url/--username/--password-env 等参数传给 scripts/install。
5. 运行 scripts/db-query --setup-status,并根据 JSON 里的 next_actions 继续处理。
如果缺少 sq,请先询问我是否允许用 Homebrew 安装。
如果缺少数据库连接信息,请向我询问连接链接或 host、用户名、密码或密码环境变量,不要猜测地址、用户名、密码或访问范围。

如果已经知道连接信息,也可以让 Agent 走非交互式配置:

请为 database-cli 创建 qa01 环境配置:
url=mysql://mysql-qa01.example.internal
display_name=QNVIP QA01
environment=qa01
project=qnvip
description=QA01 共享只读连接,默认搜索账号可见库
alias=qa-01
username=readonly_user
password 使用环境变量 QA01_DB_PASSWORD
然后运行 scripts/db-query --setup-status 验证配置已写入;ready=true 后再运行 scripts/db-query --list-envs。

Agent 实际会执行类似命令:

mkdir -p "$HOME/src"
gh repo clone CassianFlorin/database-cli "$HOME/src/database-cli"
cd "$HOME/src/database-cli"
ln -sfn "$PWD/skills/database-cli" "$HOME/.codex/skills/database-cli"
scripts/install
scripts/db-query --setup-status

或非交互式安装并创建配置:

scripts/install \
  --env qa01 \
  --url "mysql://mysql-qa01.example.internal" \
  --display-name "QNVIP QA01" \
  --environment qa01 \
  --project qnvip \
  --description "QA01 shared readonly connection; search all visible schemas unless narrowed." \
  --alias qa-01 \
  --username readonly_user \
  --password-env QA01_DB_PASSWORD \
  --non-interactive

也可以更新已有环境:

scripts/install \
  --env qa01 \
  --url "mysql://mysql-new.example.internal" \
  --display-name "QNVIP QA01" \
  --environment qa01 \
  --project qnvip \
  --username readonly_user \
  --password-env QA01_DB_PASSWORD \
  --non-interactive \
  --force

如果 Agent 已经通过 MCP adapter 运行,不需要重启 Agent 来新增连接。让 Agent 调用 add_connection 工具即可,例如:

{
  "config": "/path/to/connections.local.json",
  "env": "qa02",
  "url": "mysql://mysql-qa02.example.internal:3306/qnvip_center_order",
  "username": "readonly_user",
  "password_env": "QA02_DB_PASSWORD",
  "display_name": "QNVIP QA02",
  "aliases": ["qa-02"],
  "max_rows": 100
}

调用成功后,Agent 可以先调用 setup_status 确认配置已可见,再继续调用 list_envssearch_objectsquery_readonlyexecute_sql 使用 qa02。MCP adapter 每次工具调用都会读取配置文件,所以不依赖进程重启。

边界如下:

  • Agent 可以运行 scripts/installscripts/init-configscripts/db-query
  • Agent 可以先运行 scripts/db-query --setup-status 或 MCP setup_status,根据结构化 next_actions 决定下一步。
  • Agent 可以不创建本地配置,直接把用户提供的 --url/--host--username--password-env 传给 scripts/db-query 或 MCP execute_sql
  • Agent 默认只能执行只读 SQL;只有用户明确允许修改时,才可以传 --allow-write 或 MCP allow_write=true 执行 DML。
  • Agent 可以通过 MCP add_connection 工具在运行中创建或更新连接配置。
  • Agent 可以根据用户提供的信息创建或更新 connections.local.json
  • Agent 可以帮用户检查 sq 是否安装,并在用户允许时通过 Homebrew 安装。
  • Agent 不会也不应该猜测数据库地址、用户名、密码或访问范围;缺失时必须向用户询问。
  • 敏感密码优先由用户配置到环境变量,然后在配置中使用 password_env
  • 如果用户直接提供明文密码,Agent 只能写入本地且被 git 忽略的 connections.local.json,不应提交或展示。
  • custom tools 只适合固化只读查询模板;不要把修数 SQL 写进配置。

Codex 插件 Manifest

插件入口位于:

.codex-plugin/plugin.json

它声明:

  • 插件名:database-cli
  • Skill 目录:./skills/
  • UI 名称:Database CLI
  • 能力:ReadWriteInteractive

这与 Superpowers 的插件化思路一致:插件安装负责把 Skill 暴露给 Codex,安装后的敏感连接配置由 scripts/install 向用户收集。

依赖

真实查询前需要安装 sq

brew install sq

检查是否可用:

command -v sq

初始化数据库连接

如果只想创建或更新数据库配置,可以直接运行:

scripts/init-config

它会询问:

  • 环境名,例如 qa01prod
  • 数据库类型,例如 mysql
  • host 或域名
  • 可选端口
  • 可选默认 database/catalog
  • 用户名
  • 密码或密码环境变量

默认生成的配置路径是:

~/.config/database-cli/connections.json

目录权限 0700,文件权限 0600。放在仓库外是为了避免明文密码留在工作区里——.gitignore 只是最后一道防线,一次 git add -f 或上游调整忽略规则就可能把凭据带进版本库。

如果 skills/database-cli/connections.local.json 已经存在,则继续写入该文件并在 stderr 提示迁移。因为配置查找在第一个存在的文件处停止,且库内路径优先级高于 ~/.config,此时改写新位置不会生效。迁移时要移动而不是复制

mkdir -p ~/.config/database-cli && chmod 700 ~/.config/database-cli
mv skills/database-cli/connections.local.json ~/.config/database-cli/connections.json

配置文件专用的非交互式示例:

scripts/init-config \
  --env qa01 \
  --driver mysql \
  --host mysql-qa01.example.internal \
  --username readonly_user \
  --password-env QA01_DB_PASSWORD \
  --non-interactive

如果必须显式指定端口:

scripts/init-config \
  --env qa01 \
  --driver mysql \
  --host mysql.example.internal \
  --port 3306 \
  --username readonly_user \
  --password-env QA01_DB_PASSWORD \
  --non-interactive

配置示例

域名或代理已经处理端口时:

{
  "environments": {
    "qa01": {
      "display_name": "QNVIP QA01",
      "environment": "qa01",
      "project": "qnvip",
      "description": "QA01 shared readonly connection; search all visible schemas unless narrowed.",
      "aliases": ["qa-01", "test"],
      "driver": "mysql",
      "host": "mysql-qa01.example.internal",
      "username": "readonly_user",
      "password_env": "QA01_DB_PASSWORD",
      "max_rows": 200,
      "limit_style": "limit"
    }
  }
}

显式端口:

{
  "environments": {
    "qa01": {
      "driver": "mysql",
      "host": "mysql.example.internal",
      "port": 3306,
      "username": "readonly_user",
      "password_env": "QA01_DB_PASSWORD",
      "limit_style": "limit"
    }
  }
}

databaseschema 都是可选默认值,不是访问范围限制。用户要查哪个库,优先在 SQL 里写全限定名:

SELECT id, order_no
FROM qnvip_center_commerce.cc_order
WHERE order_no = 'YP...'

对于支持三段式名称的数据库:

SELECT column_name
FROM dbname.schema_name.table_name
WHERE id = 1

查询用法

列出已配置环境:

scripts/db-query --list-envs

执行只读查询:

scripts/db-query --env qa01 --sql "SELECT id FROM qnvip_center_commerce.cc_order WHERE order_no = 'YP...'"

不落本地配置,直接使用用户提供的临时连接信息:

scripts/db-query \
  --url "mysql://mysql-qa01.example.internal:3306/qnvip_center_commerce" \
  --username readonly_user \
  --password-env QA01_DB_PASSWORD \
  --sql "SELECT id, order_no FROM cc_order WHERE order_no = 'YP...'"

预览将要执行的 sq 命令,不真正查询数据库:

scripts/db-query --env qa01 --sql "SELECT 1" --print-command

查看数据源元信息:

scripts/db-query --env qa01 --inspect

查看表元信息:

scripts/db-query --env qa01 --inspect qnvip_center_commerce.cc_order

使用指定配置文件:

DATABASE_CLI_CONFIG=/path/to/connections.json scripts/db-query --list-envs

只校验 SQL,不执行:

scripts/db-query --check-sql "SELECT * FROM qnvip_center_commerce.cc_order WHERE order_no = 'YP...'"

用户明确允许修改后,才可以显式开启 DML。前提是该环境已在配置中声明 "writable": true,否则 --allow-write 会被拒绝:

scripts/db-query \
  --env qa01 \
  --allow-write \
  --sql "UPDATE qnvip_center_commerce.cc_order SET status = 1 WHERE id = 10"

临时连接(--url/--host)没有配置项可承载这个声明,需要额外传 --writable

scripts/db-query \
  --url "mysql://mysql-qa01.example.internal" --username repair_user \
  --writable --allow-write \
  --sql "UPDATE cc_order SET status = 1 WHERE id = 10"

安全规则

默认允许的起始关键字:

  • SELECT
  • SHOW
  • DESC
  • DESCRIBE
  • EXPLAIN
  • 只读的 WITH ... SELECT

环境声明 "writable": true、用户明确允许并传入 --allow-write 后,额外允许:

  • INSERT
  • UPDATE
  • DELETE
  • REPLACE

会被拦截的示例:

  • 未传 --allow-writeINSERTUPDATEDELETEREPLACE
  • 环境未声明 "writable": true 时的一切 DML,即使传了 --allow-write
  • 实际影响行数超过 max_write_rowsUPDATE/DELETE
  • 对 DML 的 EXPLAIN ANALYZE(MySQL 8.0.18+ 会真的执行)
  • MERGE
  • CREATEALTERDROPTRUNCATE
  • GRANTREVOKE
  • BEGINCOMMITROLLBACK
  • CALLEXECEXECUTE
  • LOCKUNLOCK
  • SELECT ... FOR UPDATE
  • 具有副作用或风险的函数,例如 nextvalsetvalget_locksleeppg_sleepbenchmarkdblink_exec

SELECTWITH 查询会自动补 LIMIT 200,除非 SQL 已经包含 limit,或显式使用 --no-auto-limit。DML 不会自动补 limit;Agent 必须使用精确业务键和可审计的 WHERE 条件。

配置了 max_rows 时,它是硬上限;用户传入更大的 --limit 或 SQL 里已有更大的 LIMIT,都会被压到 max_rowsreadonly=false 不会启用写 SQL,database-cli 会直接拒绝该配置;readonly=true 也不授予任何权限,它只是默认姿态。写 SQL 需要两个条件同时成立:环境在配置里声明 "writable": true(临时连接则传 --writable),以及单次命令显式传 --allow-write。前者刻意放在配置文件里,使拼命令的一方无法自行主张写权限。

密码处理

推荐使用环境变量保存密码:

export QA01_DB_PASSWORD='...'

配置里写:

{
  "password_env": "QA01_DB_PASSWORD"
}

如果直接把 password 写进配置文件,必须只保存在本地,并优先放在仓库外的 ~/.config/database-cli/connections.json。Wrapper 会通过 sq add --password 的 stdin 传递密码,不会把密码放进命令行 DSN。

支持的 Driver

直连配置支持:

  • mysql
  • mariadb
  • postgres
  • postgresql
  • sqlite3
  • duckdb
  • sqlserver
  • clickhouse

其他 sq source 类型可以使用高级 handle 配置:

{
  "sq_config": "/path/to/sq.yml",
  "environments": {
    "qa01": {
      "source": "@qnvip_qa01_commerce"
    }
  }
}

修数 SQL 流程

默认不要通过这个 Skill 执行写 SQL。需要修数时,优先输出给人工执行的 SQL,并包含:

  • 目标环境
  • 执行前 SELECT 校验
  • 变更 SQL
  • 执行后 SELECT 验证
  • 回滚或恢复方案

如果用户明确要求并允许 Agent 直接执行修数 SQL,必须满足:

  • 目标环境已在配置声明 "writable": true(临时连接另需 --writable
  • 使用 --allow-write 或 MCP allow_write=true
  • 只执行单条 INSERTUPDATEDELETEREPLACE
  • 先给出执行前 SELECT 校验
  • UPDATE/DELETE 必须有 WHERE,且 SQL 必须有精确业务键或主键条件
  • 执行后再跑 SELECT 验证

发版

发版只发生在 releasehotfix 分支上,推 main 不会发版。

git switch -c release        # 或 release/1.2.0、hotfix、hotfix/1.1.2
git push -u origin release

推送后自动执行:跑测试 → 按 Conventional Commits 计算版本 → 把版本号写入 plugin.jsonSERVER_VERSION 与主页徽章并提交 → 在该提交上打 tag → 发布 GitHub Release → 把版本号同步回 main

几点需要知道:

  • 只有 featfixBREAKING CHANGE 会产生新版本default_bump: false)。 分支上若只有 docschorecitest 提交,本次运行不发版,日志会写明原因。
  • tag 指向的是已经写入新版本号的那个提交,不是它的父提交。
  • 同步回 main 时不会降级版本号:hotfix 常从旧 tag 切出,此时若 main 已声明 更高版本,这一步会跳过。
  • 只同步版本号,不做分支合并。 hotfix 分支上的代码修复需要人工合回 main
  • 发版会在 main 上产生一个回写提交,本地下次推送前先 git pull

验证

基础脚本校验:

python3 -m py_compile \
  skills/database-cli/scripts/_common.py \
  skills/database-cli/scripts/db-query \
  skills/database-cli/scripts/init-config \
  skills/database-cli/scripts/install \
  skills/database-cli/scripts/database-mcp
python3 -m unittest discover -s tests

tests/test_integration.py 会用真实的 sq 与临时 SQLite 文件跑端到端流程;本地没有 sq 时这部分会自动跳过,其余测试照常运行。CI 会安装 sq 并设置 DATABASE_CLI_REQUIRE_SQ=1,使安装失败导致构建失败,而不是静默跳过。

当环境里有 PyYAML 时,执行 Skill 校验:

python3 /path/to/skill-creator/scripts/quick_validate.py /path/to/database-cli

About

CLI-first database investigation skill for Codex and Claude Code — read-only by default, writes require a config-declared opt-in.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages