mcpField
P
PgVouch

PgVouch

本地服务
github.com/Shubh-Sgr数据库04 周前更新

关于 PgVouch

PgVouch 是用于检查 PostgreSQL 模式漂移、迁移锁和数据一致性的只读 MCP 服务及命令行工具。它面向数据库团队和编码 Agent,提供确定性校验、安全改写建议与影子运行验证。

主要功能

  1. 01检测 PostgreSQL 模式对象漂移
  2. 02通过校验和验证数据并定位差异行
  3. 03分析迁移锁及当前锁冲突
  4. 04建议更安全的分步迁移改写
  5. 05通过影子运行校验计划并生成回滚 SQL

适用场景

  1. 01比较预发布与生产环境的模式
  2. 02部署前检查迁移锁风险
  3. 03验证复制或同步的数据库内容
  4. 04在 CI 中审查迁移拉取请求

MCP 相关

通过 stdio 向 AI 客户端提供 7 个只读工具,用于检查 PostgreSQL 数据库和迁移计划。LLM 负责提出计划,校验器与影子运行负责判定是否通过。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"shubh-sgr-pgvouch": {
"command": "npx",
"args": [
"-y",
"pgvouch"
],
"env": {
"SOURCE_DATABASE_URL": "<SOURCE_DATABASE_URL>",
"TARGET_DATABASE_URL": "<TARGET_DATABASE_URL>",
"PGVOUCH_LLM": "<PGVOUCH_LLM>"
}
}
}
}
启动命令npx -y pgvouch
需要配置的环境变量
SOURCE_DATABASE_URL密钥Read-only postgres:// URL of the reference database
TARGET_DATABASE_URL密钥Read-only postgres:// URL of the database to check
PGVOUCH_LLMOptional planner LLM: none (default), ollama or gemini

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmpgvouch0.4.4

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

PgVouch

一个 MCP 服务 + CLI,让 AI 助手能够安全地检查、规划并_证明_ PostgreSQL 迁移。 大模型提出方案;确定性代码负责裁定。

CI License: Apache 2.0

PgVouch 在终端中的展示:模式漂移、确切的差异行、迁移所获取的锁,以及安全的重写方案

使用预置的演示数据库(100 万笔事务、200 万条账本记录)运行的实际输出;目标数据库按下方第 2 步所述设置为故障状态。输入为实时录制;命令运行时间经过缩短(verify 运行耗时 14.0 s)。

问题

编写 ALTER TABLE 是数据库迁移中最简单的部分。难点在于:

  1. 有什么差异? 不同环境中的模式会发生漂移(热修复、迁移失败、手动更改)。
  2. 会造成什么锁定? 在繁忙的表上执行 CREATE INDEX 会阻塞所有写入,直到操作完成。即使 ALTER TABLE 只需“1 ms”,也可能因在锁队列中等待而导致服务中断。
  3. 数据真的相同吗? “行数一致”并不能证明这一点。
  4. 哪些行有问题? 验证失败时,你需要确切的行,而不是“这张包含 200 万行的表里有些问题”。

AI 助手现在会编写迁移,但它们会臆造对象、忽略锁,也无法证明任何事情。 PgVouch 为它们(以及你)提供只读工具,回答上述四个问题,并通过确定性检查验证每一条 AI 建议。

结果(实测,非估算)

所有数据均来自针对预置 Docker 数据库运行的 npm run eval。完整表格见 evals/。

项目结果
检测 32 个预置场景中的漂移(表、视图、函数、触发器、枚举、扩展、RLS)精确率 100%,召回率 100%(34 个真正例,0 个假正例,0 个漏检)
通过校验和二分查找发现的确切差异行预置行变更的 100%,0 个错误行
为找到这些差异而读取的行数311 行,而非 6,079,997 行(不匹配表中的行数,两端合计)
预测的锁模式与实际获取的锁模式(从 pg_locks 读取)在 PostgreSQL 13、14、15、16 和 17 上,36 条语句全部匹配
预测的表重写与实际重写(pg_class.relfilenode 已更改)35 条语句全部匹配
复制后序列落后于数据(下次 INSERT 会遇到重复键)发现 1/1,10 次检查中 0 次误报
通过真实架构副本影子运行的纯规则迁移计划27/27
LLM 计划(本地 llama3.2,3B),首个包含 21 个场景的套件中 17 个漂移场景,仅验证器接受率(v0.1.0)首次尝试有 5.9% 有效,重试一次后为 17.6%,82.4% 回退到规则计划;0/3 个被接受的 LLM 计划通过影子运行

迁移期间的应用停顿,在 100 万行表上测量,每隔约 10 ms 执行一次探测查询(evals/results-rewrite.md):

迁移原始方式:最长停顿PgVouch 重写:最长停顿重写总耗时
CREATE INDEX1.58 秒47 毫秒2.1 秒
ADD FOREIGN KEY(200 万行)1.01 秒49 毫秒1.2 秒
ADD CHECK440 毫秒63 毫秒0.85 秒
SET NOT NULL625 毫秒31 毫秒0.68 秒
ADD COLUMN ... NOT NULL DEFAULT gen_random_uuid()10.94 秒964 毫秒108.7 秒(分批回填)
ALTER COLUMN merchant_id TYPE bigint6.51 秒93 毫秒28.0 秒(包括重新创建其外键;+3 个手动步骤)

**LLM 数据说明了什么:**小型本地模型无法可靠地规划迁移。这就是 PgVouch 从不信任它的原因。验证器拒绝了 17 个计划中的 14 个(SQL 无法解析、虚构或重复的对象、会阻塞的 DDL)。它接受的 3 个计划安全但不完整,只有影子运行发现了这些问题(例如缺少索引,以及重建已删除表时遗漏的序列)。确定性规则计划通过了全部 17 个场景(加入后续场景后为 27/27)。详情见:evals/results-llm.md。

因此发生的变化:这些数据是在仅由验证器做出决定时测得的。现在,LLM 计划只有在通过验证器并且通过影子运行后才会被接受,且影子运行的结果必须与源端完全一致;影子运行失败时,会将结果反馈给 LLM 重试一次,之后 PgVouch 会回退到规则计划。因此,上述 3 个不完整计划现在都会被拒绝。新流程下的 LLM 评估尚未重新运行,因此这里没有新的数据。

权衡显而易见:需要回填的重写总耗时要长得多,但应用可以持续运行。 这些是在笔记本电脑(Apple M1、8 核、Docker Desktop)上进行的单次运行。绝对数值可能会有变化;重要的是差距。

工作原理

flowchart LR
  A["AI assistant<br/>(Claude Code, Cursor)"] -- "MCP (JSON-RPC, stdio)" --> S
  U["You (terminal)"] -- CLI --> S
  subgraph S["PgVouch core"]
    I["F1 introspect<br/>pg_catalog"] --> D["F2 diff<br/>(pure function)"]
    D --> P["F7 planner<br/>LLM + guardrail validator"]
    L["F5 lock analyzer<br/>(Postgres parser)"] --> R["F6 safe rewrites"]
    R --> P
    P --> SH["F10 shadow run<br/>(throwaway container)"]
    V["F3 chunked checksums"] --> B["F4 bisection"]
    P --> RC["F12 receipt<br/>(SHA-256)"]
  end
  S -- "read-only SQL" --> SRC[("source DB")]
  S -- "read-only SQL" --> TGT[("target DB")]
  P -. "structured facts only, no rows" .-> LLM["Ollama (local)<br/>or Gemini"]

黄金法则: 大模型绝不会接触数据库,也不会判定通过或失败。它负责提出建议;解析器、规则和影子运行负责做出判断。

#FeatureHow
F1Schema 内省pg_catalog(而不是 information_schema,后者会隐藏索引方法、部分索引谓词和 NOT VALID)
F2漂移检测对表、列、索引、约束、序列、视图、函数、触发器(包括已禁用的触发器)、枚举类型、扩展和行级安全执行纯函数 diffSchemas(source, target):结果确定且排序,并遵循严重性规则,绝不猜测重命名
F3数据验证在设置已规范化的会话中,于 REPEATABLE READ 快照内按主键分块计算 md5(string_agg(md5(row::text) ORDER BY pk))。文本键按字节顺序排列(COLLATE "C"),因此使用不同排序规则的服务器也能得出一致结果。还会检查目标端的每个 identity/serial 序列是否都领先于其数据。对于仍在接收复制的目标,--recheck 会在延迟后再次检查差异,并只报告始终未能追上的差异
F4校验和二分类似 Merkle 树:在中位键处拆分不匹配的分块,并仅递归检查哈希不同的部分
F5锁分析器libpg-query(Postgres 自带的解析器,基于 WASM)→ 规则表 → 根据 reltuples 评估风险
F6安全重写CONCURRENTLY、NOT VALID + VALIDATE、UNIQUE ... USING INDEX、扩展/收缩、每批执行 COMMIT 的分批 DO 循环
F7受保护的大模型规划器经 zod 检查的 JSON → 验证器(解析、允许列表、对象存在性检查、禁止不安全的 DDL)→ 影子运行(结果必须与源端一致)→ 携带错误重试一次 → 仅使用规则的回退方案
F8MCP 服务通过 stdio 提供 7 个只读工具
F9评测套件32 个漂移/数据场景、36 条具有 Postgres 实际结果作为基准的锁语句,以及一项负载下的停滞基准测试
F10影子运行将目标端的架构复制到一次性容器中,应用计划,并将结果与源端进行差异比较
F11可逆性为每个步骤标记 reversible / reversible-with-backfill / data-lossy,并生成回滚 SQL
F12收据包含漂移 + 验证 + 计划 + 影子运行结果的 JSON,并附带对规范化(按键排序)JSON 计算的 SHA-256
F13锁队列预检“现在可以安全运行吗?”:将每条语句所需的锁与实时 pg_locks + pg_stat_activity 对照,使用 Postgres 完整的 8×8 锁冲突表
F14PR 审查操作pgvouch review --format markdown + GitHub Action:在作业摘要和一条 PR 评论中提供锁分析以及对变更迁移的安全重写

快速开始

使用 PgVouch 有两种方式:

选项 A:npm 包选项 B:克隆仓库
适用场景自己的数据库、CI 或 AI 助手在预置演示数据库上试用所有功能,或参与贡献
需要Node 22(或 20.12+)Node 22(或 20.12+)和 Docker
运行命令的方式pgvouch <command>(或 npx pgvouch <command>)npm run cli -- <command>
选项 A:使用 npm 包

1. 立即试用,无需数据库。 指定任意迁移文件:

npx pgvouch locks my_migration.sql --offline     # the locks each statement takes, and the risk
npx pgvouch rewrite my_migration.sql --offline   # a safe, non-blocking version of the same migration

手头没有迁移文件?创建一个:echo "CREATE INDEX idx_amount ON transactions (amount);" > my_migration.sql

2. 安装(可选:无需安装即可运行 npx pgvouch <command>):

npm install -g pgvouch
pgvouch --help

3. 指定数据库。 在每个数据库上创建一个只读角色(SQL 语句见此处),然后在运行 PgVouch 的目录中放置一个 .env 文件:

SOURCE_DATABASE_URL=postgres://pgvouch_ro:PASSWORD@staging-host:5432/your_db
TARGET_DATABASE_URL=postgres://pgvouch_ro:PASSWORD@prod-host:5432/your_db
PGVOUCH_LLM=none   # rules-only plans; set it to ollama to let a local LLM propose plans

环境中已设置的变量优先于 .env。然后检查两个连接是否均为只读:

pgvouch doctor   # must say read_only=true and write privileges: none

4. 运行:

pgvouch diff                                      # schema drift (exit code 1 if any)
pgvouch verify --rows                             # checksums + exact differing rows
pgvouch verify --rows --recheck 3                 # target still being replicated to: ignore rows in flight
pgvouch locks my_migration.sql                    # lock impact per statement, with real table sizes
pgvouch preflight my_migration.sql                # would it have to wait for locks RIGHT NOW?
pgvouch rewrite my_migration.sql                  # safe multi-step script
pgvouch review --format markdown migrations/*.sql # PR-comment report (offline, used by the GitHub Action)
pgvouch plan --no-llm                             # rules-only plan that makes target match source
pgvouch plan                                      # LLM plan (Ollama) behind guardrails
pgvouch shadow                                    # plan, then prove it on a throwaway container (needs Docker)
pgvouch receipt --shadow                          # hashed audit record
pgvouch receipt-verify pgvouch-receipt.json

locks --fail-on high 会以代码 1 退出,因此可用于在 CI 流水线中拦截风险较高的迁移。

preflight 回答的是另一个问题:不是“这会锁住什么?”,而是“现在是否有人持有或正在等待冲突锁?”。它会列出它需要排在其后等待的会话(pid、用户、应用程序、状态、事务时长;绝不显示查询文本),并提示 CREATE INDEX CONCURRENTLY 会等待数据库中的所有较早事务。若迁移需要等待,它会以代码 1 退出。PgVouch 不会终止会话。

5. 另外: 可通过AI 助手使用它(npx -y pgvouch mcp),也可以使用 GitHub Action(其中的第 4 步)检查每个迁移拉取请求。

选项 B:克隆仓库(包含演示数据库)

仓库包含两个已填充数据的 Postgres 数据库,因此你无需接触真实数据库即可试用所有功能。要求:Node 22(或 20.12+)和 Docker。

git clone https://github.com/Shubh-Sgr/pgvouch.git && cd pgvouch
npm install
cp .env.example .env
npm run db:up          # two Postgres 16 containers, seeded: ~3 min on first start
npm run cli -- doctor  # confirms both connections are read-only
容器端口内容
source-db5433金融科技架构,10 张表:1M 条 transactions、2M 条 ledger_entries、复合主键表和无主键表
target-db5434完全相同的副本。评估场景会在它的临时副本中制造偏差。

然后按照下方的分步指南:测试所有功能操作:有意破坏目标数据库,观察各项功能如何发现并修复问题。

从克隆仓库运行命令

选项 A 中的所有命令都可在此处通过 npm run cli -- <command> 运行。这些命令使用仓库中的示例迁移:

npm run cli -- diff                                   # schema drift (exit code 1 if any)
npm run cli -- verify --rows                          # checksums + exact differing rows
npm run cli -- verify --rows --recheck 3              # target still being replicated to: ignore rows in flight
npm run cli -- locks examples/risky-migration.sql     # lock impact per statement
npm run cli -- preflight examples/risky-migration.sql # would it have to wait for locks RIGHT NOW?
npm run cli -- rewrite examples/risky-migration.sql   # safe multi-step script
npm run cli -- review --format markdown examples/*.sql # PR-comment report (offline, used by the GitHub Action)
npm run cli -- plan --no-llm                          # rules-only plan
npm run cli -- plan                                   # LLM plan (Ollama) behind guardrails
npm run cli -- shadow                                 # plan, then prove it on a throwaway container
npm run cli -- receipt --shadow                       # hashed audit record
npm run cli -- receipt-verify pgvouch-receipt.json
在 8 GB 笔记本电脑上运行

PgVouch 是在 8 GB MacBook Air(M1)上构建并测量的。遵循以下建议即可保持运行流畅:

  • 为 Docker Desktop 分配 3 GB 内存(Settings → Resources)。两个数据库在 docker-compose.yml 中各限制为 768 MB,影子容器则限制为 256 MB。
  • 一次只运行一个高负载任务:db:up、集成测试和评估都会创建或扫描数百万行。
  • 默认设置为 PGVOUCH_LLM=none,因此除非你启用模型,否则绝不会向模型发送任何内容。使用 LLM 规划器时,Ollama 会在最后一次请求后 30 s 卸载模型。
  • 除非你需要这些数据,否则请跳过 npm run eval -- --llm ...(使用 3B 模型时约需 1 小时);默认评估不会调用 LLM。
  • 想要更轻量的配置?减少填充的数据行数:npm run db:down && SEED_TRANSACTIONS=100000 npm run db:up(只需几秒,而非约 3 分钟)。CI 使用 20,000 行。已发布的评估数据和 npm run eval 需要默认的 1,000,000 行。

分步操作:测试每项功能

本演练使用 选项 B 中的两个演示数据库。你会故意破坏目标数据库,然后观察每项功能如何发现并修复问题。 请在 pgvouch 文件夹中逐条运行命令。想自动执行吗? npm run demo 会运行步骤 1–9,中途暂停,并在最后修复目标数据库。

macOS:如果命令因 Operation not permitted / EPERM uv_cwd 而失败,请授予终端访问该文件夹的权限:系统设置 → 隐私与安全性 → 文件与文件夹 →(你的终端)→ 文稿。

1. 基准状态:一切匹配

npm run cli -- diff      # "No schema drift: source and target match."
npm run cli -- verify    # "IDENTICAL": 10 tables, ~3.1M rows compared by hash

2. 破坏目标数据库(这模拟“有人犯了错”;PgVouch 本身无法写入)

docker exec pgvouch-target-db-1 psql -U postgres -d fintech -c "DROP INDEX transactions_account_created_idx"
docker exec pgvouch-target-db-1 psql -U postgres -d fintech -c "ALTER TABLE ledger_entries DROP CONSTRAINT ledger_entries_transaction_id_fkey"
docker exec pgvouch-target-db-1 psql -U postgres -d fintech -c "ALTER TABLE customers ADD COLUMN legacy_code int"
docker exec pgvouch-target-db-1 psql -U postgres -d fintech -c "UPDATE transactions SET amount = amount + 1 WHERE id = 424242"
docker exec pgvouch-target-db-1 psql -U postgres -d fintech -c "DELETE FROM ledger_entries WHERE id IN (777001, 777002)"

3. 架构漂移(F1 + F2)

npm run cli -- diff

预期有 3 项:缺失的索引(低)、缺失的外键(高)、额外的 legacy_code 列(中)。退出代码为 1。

4. 精确差异行(F3 + F4)

npm run cli -- verify --table transactions ledger_entries --rows

预期出现 changed id=424242 columns: amount、missing_in_target id=777001 和 id=777002,以及显示从 3M 行中获取约 150 行的 bisection: 行。

5. 迁移的锁影响(F5)

npm run cli -- locks examples/risky-migration.sql
npm run cli -- locks examples/risky-migration.sql --fail-on high; echo "exit code: $?"   # 1 = a CI pipeline would stop here

每条语句都会显示其锁(例如,SHARE ... blocks writes)、是否会扫描或重写表,以及风险级别;此外还会警告缺少 lock_timeout。

5b. 现在运行安全吗?(F13)

打开第二个终端,并保持一个事务处于打开状态,模拟被遗忘的会话:

docker exec -it pgvouch-target-db-1 psql -U postgres -d fintech
# then, inside psql:  BEGIN; SELECT count(*) FROM accounts;   (don't COMMIT yet)

回到第一个终端:

npm run cli -- preflight examples/risky-migration.sql

预期出现 WOULD WAIT behind 1 session(s):ALTER TABLE accounts ADD COLUMN 需要 ACCESS EXCLUSIVE 锁,而打开的会话在 accounts 上持有 ACCESS SHARE 锁(显示 state=idle in transaction 及其持续时间)。其他语句都没问题:外键需要 SHARE ROW EXCLUSIVE 锁,该锁不会与读操作冲突。在 psql 中输入 COMMIT; 并再次运行:SAFE NOW。

6. 安全地重写相同的迁移(F6)

npm run cli -- rewrite examples/risky-migration.sql

预期首先出现 SET lock_timeout。CREATE INDEX 会改为 CONCURRENTLY,外键会先设置为 NOT VALID,再进行 VALIDATE,新建的 NOT NULL 列则会使用分批回填循环。

7. 规划修复(F7 + F11)

npm run cli -- plan --no-llm   # rules-only: each step has risk, reversibility and rollback SQL
npm run cli -- plan            # optional, ~2 min: the LLM plans (needs Ollama + Docker); watch the validator and the shadow run reject bad plans

除非传入 --allow-data-loss,否则会注释掉可能导致数据丢失的 DROP COLUMN legacy_code 步骤。

8. 在一次性副本上验证计划(F10)

npm run cli -- shadow --no-llm

预期出现 Shadow run: PASS,每一步的状态都是 applied,并显示 the shadow matches the source schema。

9. 防篡改回执(F12)

npm run cli -- receipt --no-llm --out receipt.json
npm run cli -- receipt-verify receipt.json   # "OK: receipt intact"

编辑 receipt.json 中任意值,然后再次运行 receipt-verify:会报告 MODIFIED。

回执仅按主键列出差异行和变更列,因此可以附加到工单,而无需复制个人数据。--include-values 会添加行值。

10. 从 AI 助手使用(F8): 请先按照下文从 AI 助手(MCP)使用操作,然后询问 “使用 pgvouch 查找架构漂移,以及 ledger_entries 中的差异行。”

11. 重置

npm run db:down && npm run db:up   # fresh, identical databases again (~3 min)

自动化测试: npm test(单元测试,无需数据库)和 npm run test:integration(需要数据库)。

从 AI 助手(MCP)使用

MCP(Model Context Protocol)是 AI 助手调用外部工具的标准方式。PgVouch 以本地 MCP 服务的形式运行:助手(Claude Code、Cursor、……)将其作为子进程启动,并通过 stdin/stdout 与其通信。然后,你可以用日常语言提问,由助手决定调用哪些 PgVouch 工具。

PgVouch 已列入官方 MCP Registry,名称为 io.github.Shubh-Sgr/pgvouch,因此读取该注册表的客户端和目录都能找到它。无论如何,它都在你的机器上运行:注册表只说明如何启动它。

步骤 1:确保数据库已启动
npm run db:up          # in the repo; or use your own databases (see "Use it on your own databases")
npm run cli -- doctor  # both connections must say read_only=true
步骤 2:注册服务

选择一个选项。npx -y pgvouch mcp 会下载并启动已发布的软件包,因此此步骤无需克隆仓库。

Claude Code(终端或桌面应用)。 在安装了 claude CLI 的任意终端中运行一条命令:

claude mcp add pgvouch \
  -e SOURCE_DATABASE_URL=postgres://pgvouch_ro:pgvouch_ro_local@localhost:5433/fintech \
  -e TARGET_DATABASE_URL=postgres://pgvouch_ro:pgvouch_ro_local@localhost:5434/fintech \
  -e PGVOUCH_LLM=none \
  -- npx -y pgvouch mcp

添加 --scope project,即可将其存储在项目的 .mcp.json 中(通过 git 与团队共享),而不是仅为你个人配置。若要改为运行本地克隆版本(在执行 npm run build 后),请将 npx -y pgvouch mcp 替换为 node /absolute/path/to/pgvouch/dist/cli/index.js mcp。

或者使用配置文件。 适用于 Claude Code(项目根目录中的 .mcp.json)和 Cursor(项目中的 .cursor/mcp.json,或供所有项目使用的 ~/.cursor/mcp.json)。将 examples/mcp.json 复制到相应位置。

或者使用 Docker,无需 Node。 使用 examples/mcp-docker.json。在容器中,localhost 指向容器自身,因此这些 URL 使用 host.docker.internal 来访问你机器上的数据库。在仓库目录中构建一次镜像:docker build -t pgvouch .

PGVOUCH_LLM=none 表示 plan_migration 会返回仅基于确定性规则的计划。设置为 ollama 可让本地模型提出计划。计划仍须通过验证器和影子运行,而影子运行需要在运行服务的机器上安装 Docker。若没有 Docker,计划会回退到规则计划,并在输出中说明原因。

步骤 3:检查连接状态
  • Claude Code: 运行 claude mcp list(应显示 pgvouch ... ✓ Connected),或在会话中输入 /mcp。添加服务后,请启动一个新会话。
  • Cursor: 前往“设置”→“MCP”。pgvouch 应显示绿点和 7 个工具。编辑文件后请重启 Cursor。
步骤 4:提问
向助手提问调用的工具
“目标数据库是否与源数据库存在偏差?请按严重程度对差异分组。”detect_drift
“源数据库和目标数据库中的数据是否完全一致?”verify_data
“ledger_entries 中具体哪些行不同?”find_differing_rows(仅返回键和已更改的列)
“显示这些行的实际值。”find_differing_rows,并设置 includeValues: true
“ALTER TABLE transactions ALTER COLUMN merchant_id TYPE bigint 会锁定什么,锁定多久?”analyze_locks
“现在运行 ALTER TABLE accounts ADD COLUMN note text 是否安全?”check_lock_queue
“重写此迁移,使其不会阻塞生产环境:……”suggest_safe_rewrite
“规划一个安全迁移,使目标数据库与源数据库一致。”plan_migration

典型的 Agent 工作流:“检查目标数据库是否存在偏差,解释有风险的项目,并提供安全的迁移计划”。助手会调用 detect_drift,然后调用 plan_migration,也可能对结果运行 analyze_locks。

安全性: 所有 7 个工具均为只读(标注为 readOnlyHint: true)。它们都无法写入你的数据库;返回的计划是 SQL,供你自行审查和执行。唯一的副作用是:配置了 LLM 时,plan_migration 会启动一个短暂运行的本地 Postgres 容器来执行影子运行,并在之后将其移除。连接字符串来自上述配置,绝不会来自对话。只有在明确请求时才会返回行值。

故障排除
症状解决方法
服务显示“failed”/未连接使用相同设置手动启动:SOURCE_DATABASE_URL=... TARGET_DATABASE_URL=... npx -y pgvouch mcp。它应打印 pgvouch MCP server ... ready on stdio(然后按 Ctrl-C)。配置错误会指出缺少哪个变量。(服务不会读取 .env;这些变量必须来自 MCP 配置。)
Cannot find module .../dist/cli/index.js(本地克隆)运行 npm run build,并确认路径是绝对路径。
工具报错 ECONNREFUSED/Connection terminated数据库未运行或仍在填充数据。运行 npm run db:up 并等待 Healthy。
Docker 版本无法连接数据库在 URL 中使用 host.docker.internal,而不是 localhost。
macOS 上出现 EPERM/“Operation not permitted”授予启动服务的应用(你的终端/Cursor)访问该文件夹的权限:系统设置 → 隐私与安全性 → 文件与文件夹。

再次移除它:运行 claude mcp remove pgvouch,或从 JSON 文件中删除该条目。

在你自己的数据库上使用

演示数据仅供试用。要在实际场景中使用 PgVouch:

1. 选择一对数据库。 适用哪些功能取决于数据库组合:

场景源数据库 → 目标数据库用途
预发布环境与生产环境(数据本应不同)staging → proddiff、plan、shadow(仅限架构)
迁移数据库(迁移到云端、升级版本、蓝绿部署)old → newdiff 和 verify --rows(数据应完全一致);复制仍在运行时添加 --recheck 3
副本/CDC 管道检查primary → replicaverify --rows --recheck 3
审查即将执行的迁移(将要执行迁移的数据库)locks、rewrite

2. 在每个数据库上创建一个只读角色(以管理员身份操作):

CREATE ROLE pgvouch_ro LOGIN PASSWORD 'choose-a-strong-password';
ALTER ROLE pgvouch_ro SET default_transaction_read_only = on;
GRANT CONNECT ON DATABASE your_db TO pgvouch_ro;
GRANT USAGE ON SCHEMA public TO pgvouch_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO pgvouch_ro;
-- Optional, for `preflight`: see other sessions' states and transaction ages.
-- It also lets the role read their query text; PgVouch never returns or stores it.
GRANT pg_read_all_stats TO pgvouch_ro;

3. 在 .env 中将 PgVouch 指向这些数据库(切勿提交此文件):

SOURCE_DATABASE_URL=postgres://pgvouch_ro:PASSWORD@staging-host:5432/your_db
TARGET_DATABASE_URL=postgres://pgvouch_ro:PASSWORD@prod-host:5432/your_db
PGVOUCH_LLM=none

然后,在该文件夹中运行 pgvouch doctor(克隆仓库时也可运行 npm run cli -- doctor),必须显示 read_only=true 和 write privileges: none,之后才能运行其他命令。对于超大型表,请在只读副本上运行 verify。

4. 在 CI 中设置迁移门禁。 使用 --offline 时无需数据库:

npx pgvouch locks migrations/0042_add_index.sql --offline --fail-on high

或者使用 GitHub Action 审查每个迁移拉取请求。 它会分析 PR 新增或修改的迁移文件(离线运行:无需数据库、无需密钥),将锁分析和建议的安全改写写入作业摘要,并发布一条 PR 评论,后续推送时会更新该评论:

# .github/workflows/migration-review.yml
name: Migration review
on:
  pull_request:            # never pull_request_target: PR code must not get a write token
    paths: ["migrations/**/*.sql"]
permissions:
  contents: read
  pull-requests: write     # only for the comment; fork PRs get read-only and just the summary
jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: Shubh-Sgr/[email protected] # or pin the release's commit SHA
        with:
          paths: migrations/**/*.sql     # one glob per line
          fail-on: high                  # optional: fail the check at this risk

或者在本地运行相同的报告:pgvouch review --format markdown migrations/*.sql。PR 中的不可信文本(文件名、标识符)会经过转义,SQL 会放入比其中最长反引号序列更长的代码围栏中,评论长度也会限制在 GitHub 的大小限制以内。此仓库会针对涉及 examples/**/*.sql 的 PR 运行该 Action(migration-review.yml)。

5. 或者使用 Docker 运行(无需安装 Node):使用 docker build -t pgvouch . 构建一次,然后运行 docker run -i --rm --env-file .env pgvouch diff。可以用任何 CLI 命令替换 diff;不指定命令时会启动 MCP 服务。shadow 需要 Docker 守护进程,因此请改为从 CLI 运行。

安全模型

PgVouch 可以访问的内容。 这对安全审查以及阅读供应链扫描器报告(例如 Socket 的“网络访问”或“Shell 访问”)很有用:

内容时机
网络你配置的源数据库和目标数据库每条需要数据库的命令
Ollama(OLLAMA_URL,默认在本地运行)或 Gemini API仅在设置 PGVOUCH_LLM=ollama 或 gemini 时(默认关闭)
127.0.0.1 上的临时 Postgres 容器shadow 和 LLM 计划(必须通过 shadow 运行)
进程使用 execFile 启动的 docker(直接传递参数,不使用 shell)同上。不会执行其他任何内容
文件读取 ./.env 和你指定的迁移文件或回执文件;只写入你指定的 --out / receipt 文件仅 CLI。MCP 服务不会读写任何文件

PgVouch 及其依赖项均没有遥测,也没有安装脚本(preinstall / postinstall)。从 0.4.1 版起,发布版本由 GitHub Actions 构建,并带有 npm provenance,因此 npm 上的每个版本都关联到构建它的提交和工作流运行记录。CI 只能暂存版本:须由维护者通过 2FA 批准后才会正式发布。扫描器还会报告官方 MCP SDK 依赖项中的 eval 和网络使用情况(ajv 会将 JSON schema 编译为函数;express 和 hono 会提供其 HTTP 传输服务,而 PgVouch 不使用该传输:它通过 stdio 通信)。

  • 三层只读保护: pgvouch_ro 角色只有 SELECT 权限,该角色默认使用 default_transaction_read_only,并且每个连接都会在其启动数据包中设置 default_transaction_read_only=on、statement_timeout 和 lock_timeout。即使你提供的是超级用户 URL,这些保护仍然有效;有一项集成测试专门验证了这一点。
  • 绝不将表加载到内存中: 哈希在 Postgres 内部计算,网络中只传输 32 个字符的摘要。二分查找每个叶节点每侧最多获取 50 行。
  • 所有值都使用参数化查询。 标识符只从目录中获取,并会加引号。
  • 连接字符串仅来自环境变量,不会来自工具输入。
  • 不会向 LLM 发送行数据。 提示词只包含漂移报告和表结构。这可以防止通过数据库内容进行提示词注入;使用 Ollama 时,你的数据也不会离开本机。
  • Shadow 运行只会写入 PgVouch 在 127.0.0.1 上创建的容器,该容器使用随机密码,并在之后删除(包括按下 Ctrl-C 时)。计划 SQL 被视为不可信内容:它以拥有已复制 schema 的非超级用户角色运行,因此 pg_read_file() 或 COPY ... PROGRAM 会因“permission denied”而失败。每条语句都有计划无法取消的客户端超时;容器资源上限为 256 MB、1 CPU 和 256 个进程。
  • LLM 计划会经过验证,而非盲目信任: 只有验证器和 shadow 运行都通过后,才会接受计划(PGVOUCH_SHADOW_VERIFY=off 会跳过 shadow 运行,此时输出会警告该计划尚未证明完整)。如果无法运行 shadow(例如没有 Docker),则不会接受 LLM 计划。发回给 LLM 的错误消息来自仅含 schema 的数据库,因此不会包含行数据。

设计决策

  • 安全关键型转换由规则负责,而非大模型。 对生产数据而言,“大多数时候”正确的重写远远不够。大模型负责排序和解释,也可以不使用。
  • 以 Postgres 作为真实数据来源。 锁评测从 pg_locks 读取真实锁,并从 relfilenode 读取真实重写,而不是与我自己编写的表进行比较。
  • 哈希的哈希。 先对每行使用 md5,再对它们的拼接结果使用 md5,这样无论表有多宽,聚合结果每行都限制在 32 字节。
  • 根据真实键确定分块边界(row_number() % chunk_size),因此稀疏键、UUID 和复合键都能均匀分块。首尾分块不设边界,因此仅存在于目标端的行也能被捕获。
  • 纯差异函数。 它非常容易进行单元测试,并被 CLI、MCP 服务、规划器、影子运行和评测复用。
  • 一个服务层(src/service.ts)同时供 CLI 和 MCP 使用,确保两者不会产生分歧。
  • 影子运行发现了实际缺陷: 类型变更重写最初会删除列的 DEFAULT/NOT NULL(已在提交 cc4f55b 中修复),之后又会在交换后将列的外键和索引留在旧列上。这两个问题都已修复,并补充了回归测试和评测场景。

限制(如实列出)

  • 仅支持 PostgreSQL。CI 会在 13、14、15、16 和 17 上运行集成测试和锁准确性评估;已发布的评估数据是在 16 上测得的。
  • 漂移检测涵盖表、列、索引、约束、序列、视图、函数/存储过程、触发器、枚举类型、扩展和行级安全策略。暂不支持:授权和权限、列排序规则、注释、发布/订阅、外部服务器以及表存储选项。
  • 某些对象漂移需要人工处理:安装或升级扩展(需要特权角色)、已更改的物化视图(需要重新创建并刷新)、含有额外或重新排序标签的枚举(Postgres 无法原地删除或重新排序标签),以及列已更改的视图(CREATE OR REPLACE VIEW 无法删除或更改列类型;影子运行会报告此情况)。
  • 文本主键按字节进行比较(COLLATE "C"),以便排序规则不同的服务器也能得出一致结果。此类键上的范围扫描无法使用主键索引,因此验证带文本键的超大表会比验证带整数或 uuid 键的表慢。
  • 启用行级安全策略时,没有 BYPASSRLS 权限的角色只能看到策略允许其查看的行;verify 会在该表的备注中说明这一点。
  • plan 和 shadow 适用于 public 架构。diff --schema 和 verify --schema 可检查其他架构,但目前尚未规划其中的漂移。
  • 重命名会报告为删除+新增,并附带 possible_rename 提示。PgVouch 绝不会自动重命名。
  • 对没有主键的表,可以检测到不匹配,但无法定位具体行。
  • 验证会比较两个快照,因此在活动目标上,仍在变动的行会有所不同。verify --recheck N 会重新检查这些差异(每隔 --recheck-delay 秒一次,默认为 5 秒),只保留始终无法匹配的差异。它只会重新检查首次检查发现的内容,因此新增写入不会导致表持续验证失败。每次检查时源端都发生变化的行仍可能被报告,并标记为“源仍在变化”。若要最终确认切换结果,短暂冻结写入仍是最可靠的证明。
  • 逻辑复制不会复制序列值,因此在逻辑副本上,verify 会报告序列值落后,直到你在切换时设置这些值。这是正确的:人们经常会忘记这一步。
  • 锁分析器了解 30 种语句形态。其他任何语句都会被标记为“规则表中不存在”,绝不会被默默判定为安全。
  • 自动分批回填需要单个整数主键;否则回填步骤会变为手动模板。
  • 影子运行只会复制架构,因此它能证明最终结构正确,但不能证明生产负载下的耗时(这由锁分析器覆盖)。
  • 演示数据库仅监听 127.0.0.1。在 Linux 上,影子容器通过 Docker 网桥而非回环接口访问主机,因此要对演示数据库运行影子运行,还需在网桥上发布这些数据库:npm run db:down && DB_BIND=172.17.0.1 npm run db:up(CI 在其临时运行器上使用 0.0.0.0)。macOS 和 Windows(Docker Desktop)则无需额外设置。
  • 类型更改的扩展/收缩仍需人工操作:部署双写并切换读取。列上的索引、外键、CHECK 和 UNIQUE 约束会自动复制到新列。主键、排除约束以及引用该列的其他表中的外键仍需手动处理。
  • 评估场景由我编写,涵盖已知情况,包括一些棘手情形(易变默认值、复合键、部分索引、会话设置陷阱);所有场景都公开在 evals/scenarios 中。
  • Gemini 适配器已实现,但未在评估中测试(未使用 API 密钥)。

路线图

  • 支持 MySQL。
  • 感知复制状态的验证:在已知 LSN 上比较两端。
  • 除 SHA-256 完整性哈希外,添加签名回执(Ed25519)。
  • 在免费套餐上托管演示(影子运行使用 Neon 分支)。

开发

npm test                  # 198 unit tests, no database needed
npm run test:integration  # needs `npm run db:up` and Docker (shadow runs)
npm run eval              # all evals → evals/results*.md
npm run eval -- --only scenarios --llm llama3.2   # include LLM plans (needs Ollama)
src/
  introspect/  F1   diff/     F2   verify/   F3 + F4   locks/  F5   rewrite/  F6
  plan/        F7   llm/      Ollama + Gemini           mcp/    F8   shadow/   F10
  reversibility/ F11  receipt/ F12   cli/   service.ts (shared by CLI + MCP)
evals/         F9   scenarios/, locks/, lib/, results*.md
docker/        docker-compose.yml + deterministic seed + read-only role

贡献

PgVouch 是开源项目,欢迎贡献:报告 Bug、新增锁定规则、新增评测场景和完善文档。请参阅 CONTRIBUTING.md 了解环境配置和基本准则,并参阅 SECURITY.md 私下报告安全漏洞。本项目遵循行为准则。

许可证

Apache License 2.0 © 2026 Shubham Sagar。可免费使用、修改和分发,包括用于商业用途;分发任何副本时,请保留 LICENSE 和 NOTICE 文件。该许可证还授予每位贡献者的专利许可。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。