postgres-cli
通过 CLI 直连 PostgreSQL,填补只读 MCP 服务的写操作能力空缺,并为危险操作提供统一的安全护栏。
⚠️ Agent 必读:在执行
DROP / TRUNCATE / 无 WHERE 的 DELETE·UPDATE / 大范围 DML / prod 环境写操作时,必须遵守下文《🚨 高危 SQL 强制人类确认协议》,分三步执行,严禁一次性把 dry-run 与--confirm合并执行、严禁自行补齐--confirm直接提交。
核心能力
- 查询(只读):
pg_query.py执行 SELECT / WITH / EXPLAIN,自动追加 LIMIT 100 - 写操作:
pg_execute.py执行 INSERT / UPDATE / DELETE / DDL,默认 dry-run - 表结构:
pg_schema.py输出列 / 主键 / 索引 / 外键 - 表列表:
pg_list.py列出 schema 下所有表 + 行数估算 - 初始化:
pg_init.py生成 / 补齐凭据文件
Quick Start
# 1. 首次使用:生成凭据模板(密码字段留空,由用户手动填入)
python3 scripts/pg_init.py
# 2. 查询数据
python3 scripts/pg_query.py --env test --sql "SELECT count(*) FROM my_table"
# 3. 查看表结构
python3 scripts/pg_schema.py --env test --table my_table
# 4. 执行写操作(先 dry-run 看看影响多少行,确认后加 --confirm 真正提交)
python3 scripts/pg_execute.py --env test --sql "UPDATE foo SET x=1 WHERE id=2"
python3 scripts/pg_execute.py --env test --sql "UPDATE foo SET x=1 WHERE id=2" --confirm
Scripts
所有脚本均使用 Python 3 + psycopg2-binary,首次运行若缺少依赖会打印 pip install psycopg2-binary 提示后退出。
scripts/pg_init.py —— 凭据初始化
生成或补齐 ~/.codebuddy/postgres-cli/credentials.json,自动 chmod 600。若文件已存在,不会覆写已填的密码。
参数:
--env <name>:要补齐的环境名,默认test(内置骨架仅 test;其它环境名可手动新增到 JSON 中)
scripts/pg_query.py —— 只读查询
参数:
--sql <sql>(必填):SELECT / WITH / EXPLAIN / SHOW / VALUES / TABLE 开头--env <name>:默认test--no-limit:关闭自动追加 LIMIT 100--format table|json|csv:默认 table,table 中 NULL 显示为NULL--quiet:仅输出结果(不输出连接横幅与耗时)- 其他覆写:
--host/--port/--database/--user/--password
若 SQL 不是只读 → 报错并提示改用 pg_execute.py。
scripts/pg_execute.py —— 写操作(默认 dry-run)
参数:
--sql <sql>(必填):INSERT / UPDATE / DELETE / DDL--env <name>:默认test--confirm:真正 COMMIT(不加则仅 dry-run + ROLLBACK,打印预估影响行数)--force:允许高危语句(DROP TABLE / TRUNCATE / DROP DATABASE / DROP SCHEMA / DROP INDEX / ALTER TABLE ... DROP)--confirm-prod:当 env 名包含prod时必须追加
若 SQL 是 SELECT 等只读语句 → 报错并提示改用 pg_query.py。
scripts/pg_schema.py —— 表结构
参数:
--table <name>(必填)--schema <name>:默认public--env <name>:默认test--format table|json|csv:默认 table
输出分 4 段:Columns / Primary Key / Indexes / Foreign Keys(json 格式则合并为单个对象)。
scripts/pg_list.py —— 列出表
参数:
--schema <name>:默认public--pattern <like>:按LIKE过滤表名(例:--pattern "my_prefix%")--env <name>:默认test--format table|json|csv:默认 table
🚨 高危 SQL 强制人类确认协议(Agent 必读,不可跨越)
本协议是本 skill 最重要的使用规范。Agent(AI 助手)在执行高危 SQL 时,严禁一次性把所有参数凑齐后直接提交,必须分三步执行,并在 Step 2 处显式回到用户等待确认。
适用范围(命中下列任一即触发本协议)
- DDL 破坏性操作:
DROP TABLE/DROP SCHEMA/DROP DATABASE/DROP INDEX/DROP VIEW/DROP FUNCTION - 列/约束破坏性操作:
ALTER TABLE ... DROP COLUMN/ALTER TABLE ... DROP CONSTRAINT - 全表清空类:
TRUNCATE - 无 WHERE 的全表更新/删除:
DELETE FROM xxx;(无 WHERE) /UPDATE xxx SET ...;(无 WHERE) /WHERE 1=1/WHERE true - dry-run 预估影响行数超过阈值:影响行数 > 1000 的 UPDATE / DELETE
- 任何 env 名含
prod/production的写操作(即使是普通 UPDATE / DELETE)
三步执行流程(Agent 必须严格遵守)
Step 1:Dry-run 预检(Agent 可自行完成)
先执行 dry-run,了解影响面:
# 高危 DDL:仅加 --force,不加 --confirm
python3 scripts/pg_execute.py --env test --sql "DROP TABLE public.ai_test" --force
# 大范围 DML:先 dry-run 看影响行数
python3 scripts/pg_execute.py --env test --sql "UPDATE foo SET bar=1 WHERE dept='X'"
对于 DDL(如 DROP TABLE),dry-run 不会返回行数(返回 -1),Agent 必须额外执行一条 pg_query.py 来告知用户"这张表里还有多少行、占多少空间":
python3 scripts/pg_query.py --env test --sql "SELECT count(*) AS rows FROM public.ai_test"
python3 scripts/pg_query.py --env test --sql "SELECT pg_size_pretty(pg_total_relation_size('public.ai_test')) AS size"
Step 2:停下来,向用户显式求确认(Agent 必须回到用户)
Agent 禁止在同一轮工具调用里接着执行带 --confirm 的命令。必须在对话中输出一段结构化的确认请求,格式如下:
⚠️ 即将执行【高危 SQL】,请您人工复核后确认:
· 环境:[env=test] <YOUR_HOST>:5432 / <YOUR_DATABASE>
· 操作类型:DROP TABLE(破坏性 DDL,不可回滚)
· SQL 原文:
DROP TABLE public.ai_test;
· 影响评估:
- 目标表现有 0 行数据
- 目标表占用 16 kB
- dry-run 返回影响行数:-1(DDL 无行数概念)
❓ 请回复以下之一:
- 「确认执行」/「yes」/「go」:继续 Step 3 真实提交
- 「取消」/「no」/「stop」:中止本次操作
- 「先改一下 SQL …」:我来调整 SQL 重新走 dry-run
Agent 在此刻必须结束本轮,等待用户明确答复。 用户如果只回复"嗯"、"好"、"那就删吧"这种模糊肯定,Agent 应该再追问一次以确保语义无误(特别是 prod 环境与 DROP / TRUNCATE 场景)。
Step 3:收到用户明确肯定答复后,才允许真实提交
只有在用户显式回复肯定词("确认执行" / "yes" / "go" / "执行" / "确认" 等)之后,Agent 才能追加 --confirm 真正提交:
python3 scripts/pg_execute.py --env test --sql "DROP TABLE public.ai_test" --force --confirm
若目标环境是生产环境(env 名含 prod),还需额外追加 --confirm-prod。
反例(Agent 严禁出现下列行为)
❌ 用户只说了一句"删除 ai_test 表",Agent 就一口气跑完 dry-run + --confirm 全流程,没有回到用户确认。
❌ 用户说"把 foo 表的 status 都改成 1",Agent 直接跑带 --confirm 的 UPDATE,没有展示影响行数、没有让用户复核 SQL。
❌ dry-run 显示将影响 50000 行,Agent 未提示用户"影响面超出阈值,请确认"就继续执行。
❌ Agent 将 Step 1 / Step 2 / Step 3 合并到同一次工具调用批次里(这会让用户没有插手机会)。
正例
✅ Step 1 跑完 dry-run → 结束工具调用 → 输出 Step 2 格式化确认文本 → 停下等用户 → 收到用户"确认执行" → Step 3 追加 --confirm 提交 → 回报执行结果。
Safety Rules
以下安全规则务必严格遵守(程序层护栏,与上方协议配合使用):
- 写操作默认 dry-run:
pg_execute.py不加--confirm时,所有写 SQL 都在事务中执行后 ROLLBACK,只回显预估影响行数。这是第一道护栏。 - 高危语句需
--force:DROP TABLE / TRUNCATE / DROP DATABASE / DROP SCHEMA / DROP INDEX / ALTER TABLE ... DROP不加--force直接拒绝执行。 - 生产环境需
--confirm-prod:env 名包含prod或production时会打印醒目横幅并强制要求--confirm-prod,否则拒绝。 - Ctrl+C 自动 ROLLBACK:所有脚本捕获 KeyboardInterrupt 后先回滚再退出。
- 异常退出码非 0:参数错误返回 2,连接失败返回 3,SQL 错误返回 4,其他异常返回 5,用户中断返回 130。
- 密码脱敏:任何日志 / 连接横幅 / 报错输出中,password 字段一律显示为
***。 - Agent 侧硬性义务:以上程序层护栏可被 Agent 自行补齐参数绕过,因此 Agent 必须额外遵守上方《高危 SQL 强制人类确认协议》,把最终决策权交还给人类。绝不允许"Agent 自判定风险足够低就直接 --confirm"。
Credentials Setup
凭据文件的位置是固定且唯一的:
~/.codebuddy/postgres-cli/credentials.json
严格约束:
- ✅ 仅允许存放在上述用户目录路径;
- ❌ 严禁在项目仓库的任何位置(包括
.codebuddy/、skills/、references/、plan/、项目代码目录等)创建、复制或粘贴含有密码的文件; - ❌ 严禁把密码硬编码在任何
.py/.md/.sql文件里; - ❌ 严禁通过
git add/git commit方式提交任何含密码的文件。
首次使用:
python3 scripts/pg_init.py # 会自动生成骨架并 chmod 600
# 然后手动编辑文件,把 test 环境的 password 填入
凭据文件结构示例(实际密码请自行填写,不要照抄占位符):
{
"test": {
"host": "<YOUR_HOST>",
"port": 5432,
"database": "<YOUR_DATABASE>",
"user": "<YOUR_USER>",
"password": "<YOUR_PASSWORD>"
}
}
新增环境:直接在 JSON 根节点追加新 key 即可,例如:
{
"test": { ... },
"dev": {
"host": "...", "port": 5432, "database": "...", "user": "...", "password": "..."
}
}
非敏感环境元信息(用途说明、host 归属)请记录在 references/connections.md。
环境变量与参数覆写优先级
命令行参数 > credentials.json。例如临时换一个库:
python3 scripts/pg_query.py --env test --database another_db --sql "SELECT 1"
常见错误排查
若遇到连接失败 / 依赖缺失 / SQL 报错等问题,请查阅 references/troubleshooting.md。
微信扫一扫