PgVouch について
PgVouchは、PostgreSQLのスキーマ差分、マイグレーションのロック、データ整合性を調べる読み取り専用のMCPサーバー兼コマンドラインツールです。データベースチームやコーディングエージェント向けに、決定的な検証、安全な書き換え案、シャドー実行による確認を提供します。
主な機能
- 01PostgreSQLのスキーマ差分検出
- 02チェックサム検証と差分行の特定
- 03マイグレーションロックと競合の分析
- 04安全な段階的マイグレーションへの書き換え案
- 05シャドー実行による計画検証とロールバックSQL生成
活用シーン
- 01ステージングと本番のスキーマ比較
- 02デプロイ前のロックリスク確認
- 03複製・同期されたデータベースの検証
- 04CIでのマイグレーションプルリクエスト審査
MCP 対応
stdio経由で、PostgreSQLデータベースとマイグレーション計画を調べる7つの読み取り専用ツールをAIクライアントに公開します。LLMが計画を提案し、検証器とシャドー実行が合否を判定します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
npx -y pgvouchSOURCE_DATABASE_URLシークレットRead-only postgres:// URL of the reference databaseTARGET_DATABASE_URLシークレットRead-only postgres:// URL of the database to checkPGVOUCH_LLMOptional planner LLM: none (default), ollama or geminiローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
PgVouch
AI アシスタントが PostgreSQL のマイグレーションを安全に調査、計画し、_証明_できる MCP サーバー+CLI です。 LLM が提案し、決定論的なコードが判断します。

以下の手順 2にあるとおり、ターゲットを壊した状態で、シード済みのデモデータベース(トランザクション 100 万件、台帳エントリ 200 万件)に対して実行した出力です。入力はリアルタイムですが、コマンドの実行時間は短縮しています(verify の実行には 14.0 s かかりました)。
問題
データベースのマイグレーションで ALTER TABLE を書くのは簡単です。難しいのは、次の点です。
- 何が異なるのか? 環境間でスキーマに差異が生じます(ホットフィックス、失敗したマイグレーション、手動変更など)。
- どのようなロックが発生するのか? 負荷の高いテーブルで
CREATE INDEXを実行すると、完了するまで書き込みがすべてブロックされます。「1 ms」のALTER TABLEでも、ロック待ちのキューに並ぶことでサービス停止につながる場合があります。 - データは本当に同じなのか? 「行数が一致する」だけでは証明になりません。
- どの行が誤っているのか? 証明に失敗したときに必要なのは、該当する行そのものです。「200 万行のテーブルのどこか」ではありません。
AI アシスタントはマイグレーションを作成するようになりましたが、存在しないオブジェクトを幻覚し、ロックを無視し、何も証明できません。 PgVouch は、これら 4 つの問いに答える読み取り専用ツールを AI アシスタントとユーザーに提供し、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/36件 |
予測したテーブルの書き換えと実際の書き換え(pg_class.relfilenode の変更) | ステートメント 35/35件 |
| コピー後にデータに追いつかず残ったシーケンス(次の INSERT で重複キーエラーが発生する状態) | 1/1件を検出、10回のチェックで誤検知0件 |
| 実スキーマのコピーでシャドウ実行に合格した、ルールのみのマイグレーション計画 | 27/27件 |
| LLM の計画(ローカルの llama3.2、3B)、最初の21シナリオのスイートのうち17件の差分シナリオ、バリデーターのみでの受け入れ(v0.1.0) | 初回に有効だったものは 5.9%、1回の再試行後は 17.6%、82.4% がルールによる計画にフォールバック;受け入れられた LLM の計画 0/3件 がシャドウ実行に合格 |
マイグレーション中のアプリケーションの停止時間。1M 行のテーブルに対し、約10ミリ秒ごとにプローブクエリを実行して測定しました(evals/results-rewrite.md)。
| マイグレーション | 元の処理:最大停止時間 | PgVouch による書き換え:最大停止時間 | 書き換えの合計時間 |
|---|---|---|---|
CREATE INDEX | 1.58 s | 47 ms | 2.1 s |
ADD FOREIGN KEY(2M 行) | 1.01 s | 49 ms | 1.2 s |
ADD CHECK | 440 ms | 63 ms | 0.85 s |
SET NOT NULL | 625 ms | 31 ms | 0.68 s |
ADD COLUMN ... NOT NULL DEFAULT gen_random_uuid() | 10.94 s | 964 ms | 108.7 s(バッチ処理によるバックフィル) |
ALTER COLUMN merchant_id TYPE bigint | 6.51 s | 93 ms | 28.0 s(外部キーの再作成を含む;手動手順を3つ追加) |
LLM の数値が示すこと: 小規模なローカルモデルは、マイグレーション計画の作成において信頼できません。そのため、PgVouch が LLM を決して信用することはありません。バリデーターは17件中14件の計画を却下しました(解析できない SQL、幻覚または重複したオブジェクト、ブロッキング DDL)。受け入れられた3件は安全でしたが不完全であり、それを検出したのはシャドウ実行だけでした(例:インデックスの欠落や、削除したテーブルの再作成時にシーケンスが含まれていなかったこと)。決定論的なルールによる計画は17件すべてに合格しました(後から追加されたシナリオを含めると27/27件)。詳細:evals/results-llm.md。
その結果として変更されたこと: これらの数値は、バリデーターだけで判定していた時点で測定されたものです。現在は、LLM の計画が受け入れられるのは、バリデーターに合格し、かつ結果がソースと完全に一致するシャドウ実行にも合格した場合に限られます。シャドウ実行に失敗した場合は LLM に返して1回再試行し、その後 PgVouch はルールによる計画にフォールバックします。そのため、上記の不完全な計画3件は現在なら却下されます。新しいパイプラインでの LLM 評価はまだ再実行されていないため、新しい数値はありません。
トレードオフは明らかです。バックフィルが必要な書き換えは合計時間が大幅に長くなりますが、アプリケーションは稼働し続けます。 これらはノート PC(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"]
基本原則: LLM はデータベースに一切アクセスせず、合否も判断しません。LLM は提案を行い、パーサー、ルール、シャドー実行が判断します。
| # | 機能 | 内容 |
|---|---|---|
| F1 | スキーマのイントロスペクション | pg_catalog(インデックス方式、部分インデックスの述語、NOT VALID を隠す information_schema ではありません) |
| F2 | ドリフトの検出 | テーブル、列、インデックス、制約、シーケンス、ビュー、関数、トリガー(無効なものも含む)、列挙型、拡張機能、行レベルセキュリティを対象とする純粋な diffSchemas(source, target):重大度ルールに従って決定的にソートされ、名前変更を推測することはありません |
| F3 | データの検証 | 主キーのチャンクごとに md5(string_agg(md5(row::text) ORDER BY pk)) を計算します。正規化したセッション設定を使用し、REPEATABLE READ スナップショット内で実行します。テキストキーはバイト単位でソート(COLLATE "C")するため、照合順序が異なるサーバー間でも結果が一致します。また、ターゲットのすべての identity/serial シーケンスがデータより先に進んでいることも確認します。ターゲットへのレプリケーションが続いている場合、--recheck は遅延後に差異を再確認し、追いつかなかったものだけを報告します |
| F4 | チェックサムの二分探索 | Merkle ツリー方式:不一致チャンクを中央値のキーで分割し、ハッシュが異なる半分だけを再帰的に調べます |
| F5 | ロックアナライザー | libpg-query(Postgres 独自のパーサー、WASM)→ ルールテーブル → reltuples に基づくリスク |
| F6 | 安全な書き換え | CONCURRENTLY、NOT VALID + VALIDATE、UNIQUE ... USING INDEX、拡張/縮小、バッチごとに COMMIT を行うバッチ処理の DO ループ |
| F7 | ガード付き LLM プランナー | zod で検証した JSON → バリデーター(解析、許可リスト、オブジェクトの存在、安全でない DDL がないことを確認)→ シャドー実行(結果がソースと一致する必要があります)→ エラーを使って 1 回再試行 → ルールのみのフォールバック |
| F8 | MCP サーバー | stdio 経由の読み取り専用ツール 7 個 |
| F9 | 評価スイート | ドリフト/データのシナリオ 32 件、Postgres の正解データを用いたロックステートメント 36 件、負荷下での停止ベンチマーク |
| F10 | シャドー実行 | ターゲットのスキーマを使い捨てコンテナにコピーし、プランを適用して、結果をソースと比較します |
| F11 | 可逆性 | 各ステップに reversible/reversible-with-backfill/data-lossy のタグを付け、ロールバック用 SQL を生成します |
| F12 | 実行記録 | ドリフト+検証+プラン+シャドー実行の JSON と、正規化(キーをソート)した JSON に対する SHA-256 |
| F13 | ロックキューの事前チェック | 「今すぐ安全に実行できますか?」を確認します。各ステートメントが必要とするロックを、Postgres の完全な 8×8 ロック競合テーブルを使って、実行中の pg_locks と pg_stat_activity に照らして調べます |
| F14 | PR レビューアクション | pgvouch review --format markdown + GitHub Action:変更されたマイグレーションのロック分析と安全な書き換えを、ジョブサマリーと 1 件の PR コメントとして出力します |
はじめに
PgVouch の使用方法は 2 通りあります。
| オプション 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 データベースが 2 つ含まれているため、実際のデータベースに触れずにすべての機能を試せます。必要なもの: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-db | 5433 | フィンテックのスキーマ、10 テーブル:transactions 100 万行、ledger_entries 200 万行、複合主キーのテーブルと主キーのないテーブル |
target-db | 5434 | 同一のコピー。評価シナリオでは、そのスクラッチコピーに差分を作成します。 |
以下の手順:すべての機能をテストするに進みます。意図的にターゲットを壊し、各機能がそれを検出して修正する様子を確認できます。
クローンしたリポジトリから実行するコマンド
オプション 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)。2 つのデータベースのメモリ上限はそれぞれ
docker-compose.ymlで 768 MB、シャドウコンテナーでは 256 MB です。 - 負荷の高い処理を同時に 1 つだけ実行します。
db:up、統合テスト、評価では、いずれも数百万行を作成またはスキャンします。 - デフォルトでは
PGVOUCH_LLM=noneなので、有効にしない限りモデルにデータが送信されることはありません。LLM プランナーを使う場合、最後のリクエストから 30 秒後に Ollama がモデルをアンロードします。 - その計測値を必要としない限り、
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 のデモデータベースを2つ使用します。意図的にターゲットを壊し、各機能が問題を検出して修正する様子を確認します。
pgvouch フォルダーから、コマンドを1つずつ実行してください。自動で実行しますか? 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、および取得行数が300万行中約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)
2つ目のターミナルを開き、セッションを忘れた場合のようにトランザクションを開いたままにします:
docker exec -it pgvouch-target-db-1 psql -U postgres -d fintech
# then, inside psql: BEGIN; SELECT count(*) FROM accounts; (don't COMMIT yet)
1つ目のターミナルに戻ります:
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
データを失う DROP COLUMN legacy_code の手順は、--allow-data-loss を渡さない限りコメントアウトされます。
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 は、io.github.Shubh-Sgr/pgvouch として公式 MCP レジストリに掲載されているため、レジストリを参照するクライアントやディレクトリから見つけられます。どちらの場合も、お使いのマシン上で実行されます。レジストリには起動方法が記載されているだけです。
ステップ 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:サーバーを登録する
いずれか 1 つの方法を選んでください。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
自分だけでなく、プロジェクトの .mcp.json に保存してチームと git で共有するには、--scope project を追加してください。代わりにローカルのクローンを実行する場合(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: Settings → MCP を開きます。
pgvouchに緑色の点と 7 個のツールが表示されます。ファイルを編集した後は Cursor を再起動してください。
ステップ 4:質問する
| アシスタントへの質問 | 呼び出すツール |
|---|---|
| 「ターゲットデータベースはソースと比べてドリフトしていますか?差分を重大度別に分類してください。」 | detect_drift |
| 「ソースとターゲットのデータは同一ですか?」 | verify_data |
「ledger_entries で異なる行を正確に教えてください。」 | find_differing_rows(キーと変更された列のみ) |
| 「それらの行の実際の値を表示してください。」 | includeValues: true を指定した find_differing_rows |
「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 |
典型的なエージェント型のフローは、「ターゲットのドリフトを確認し、リスクのある項目を説明して、安全なマイグレーションプランを提示してください」です。アシスタントは 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 の localhost を host.docker.internal に置き換えます。 |
macOS で EPERM/「Operation not permitted」が発生する | サーバーを起動するアプリ(ターミナル/Cursor)にフォルダーへのアクセスを許可します:システム設定 → プライバシーとセキュリティ → ファイルとフォルダー。 |
再度削除するには、claude mcp remove pgvouch を実行するか、JSON ファイルからエントリーを削除します。
自分のデータベースで使う
デモデータは、試用専用です。実際に PgVouch を使うには、次の手順に従います。
1. データベースの組み合わせを選びます。 どの機能が適しているかは、組み合わせによって異なります。
| 状況 | ソース → ターゲット | 用途 |
|---|---|---|
| ステージングと本番(データが異なる想定) | staging → prod | diff、plan、shadow(スキーマのみ) |
| データベースの移行(クラウド移行、バージョンアップ、ブルー/グリーン) | old → new | diff および verify --rows(データが同一であることを確認)。レプリケーションの実行中は --recheck 3 を追加します |
| レプリカ/CDC パイプラインの確認 | primary → replica | verify --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 コメントを 1 件投稿します。
# .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 に対して、このアクションを実行します(migration-review.yml)。
5. または、Docker で実行します(Node のインストールは不要です)。docker build -t pgvouch . で一度ビルドし、docker run -i --rm --env-file .env pgvouch diff を実行します。diff の代わりに任意の CLI コマンドを使えます。コマンドを指定しない場合は MCP サーバーが起動します。shadow には Docker デーモンが必要なため、CLI から実行してください。
安全モデル
PgVouch がアクセスできるもの。 セキュリティレビューや、サプライチェーンスキャナーのレポート(Socket の「ネットワークアクセス」や「シェルアクセス」など)を読む際に役立ちます。
| 内容 | タイミング | |
|---|---|---|
| ネットワーク | 設定した接続元および接続先のデータベース | データベースを必要とするすべてのコマンド |
Ollama(OLLAMA_URL、デフォルトではローカル)または Gemini API | PGVOUCH_LLM=ollama または gemini の場合のみ(デフォルトでは無効) | |
127.0.0.1 上の一時的な Postgres コンテナ | shadow と、LLM プラン(shadow run に合格する必要があります) | |
| プロセス | execFile で起動する docker(引数はシェルを介さず直接渡されます) | 上記と同じです。それ以外のものは実行されません |
| ファイル | ./.env と、指定したマイグレーションまたはレシートファイルを読み取ります。書き込むのは、指定した --out ファイルまたはレシートファイルのみです | CLI のみです。MCP サーバーはファイルを一切読み書きしません |
PgVouch にも依存関係にも、テレメトリーやインストールスクリプト(preinstall/postinstall)はありません。0.4.1 以降のバージョンは npm provenance を使用して GitHub Actions から公開されているため、npm 上の各バージョンから、そのビルドに使用されたコミットとワークフローの実行を確認できます。CI ができるのはバージョンを公開準備状態にすることだけです。メンテナーが 2FA で承認した後に公開されます。スキャナーは、公式 MCP SDK の依存関係内で使われる eval とネットワークアクセスも報告します(ajv は JSON スキーマを関数にコンパイルし、express と hono はその HTTP トランスポートを提供しますが、PgVouch はこれを使用せず、stdio で通信します)。
- 3 層の読み取り専用保護:
pgvouch_roロールにはSELECT権限しかなく、ロールはdefault_transaction_read_onlyをデフォルトに設定し、各接続は起動パケットでdefault_transaction_read_only=on、statement_timeout、lock_timeoutを設定します。スーパーユーザー URL を渡した場合でも、この保護は維持されます。このケースを対象とした統合テストもあります。 - テーブルをメモリに読み込むことはありません: ハッシュは Postgres 内で計算され、ネットワークを介して送信されるのは 32 文字のダイジェストのみです。二分探索では、各リーフの両側から最大 50 行を取得します。
- すべての値にパラメーター化クエリを使用します。 識別子はカタログからのみ取得し、引用符で囲みます。
- 接続文字列は環境変数からのみ取得し、ツールの入力から取得することはありません。
- LLM に行データは送信されません。 プロンプトに含まれるのはドリフトレポートとテーブルの形状のみです。これにより、データベースの内容を通じたプロンプトインジェクションを防ぎ、Ollama を使用する場合にデータがマシンの外に出ることもありません。
- Shadow run が書き込みを行うのは、PgVouch がランダムなパスワードを設定して
127.0.0.1上に作成したコンテナのみです。 実行後に削除されます(Ctrl-C の場合も同様です)。プランの SQL は信頼できない入力として扱われます。コピーしたスキーマを所有する非スーパーユーザーロールで実行するため、pg_read_file()やCOPY ... PROGRAMは「権限がありません」というエラーで失敗します。各ステートメントにはプランで延長できないクライアント側のタイムアウトが設定され、コンテナのリソース上限は 256 MB、1 CPU、256 プロセスです。 - LLM プランは信頼するのではなく、検証します: バリデーターと shadow run の両方に合格した場合のみプランを受け入れます(
PGVOUCH_SHADOW_VERIFY=offにすると shadow run は省略され、出力にはプランの完全性が証明されていないという警告が表示されます)。Shadow run を実行できない場合(例:Docker がない場合)、LLM プランは受け入れられません。LLM に返されるエラーメッセージはスキーマのみのデータベースから取得されるため、行データが含まれることはありません。
設計上の決定事項
- 安全性が重要な変換では、LLMではなくルールを使います。 「ほとんどの場合」正しい書き換えでは、本番データには不十分です。LLMの役割は順序付けと説明であり、使用は任意です。
- Postgresを正解の基準にします。 ロックの評価では、独自に作成したテーブルと比較するのではなく、
pg_locksから実際のロックを、relfilenodeから実際の書き換えを読み取ります。 - ハッシュのハッシュを使います。 行ごとに
md5を適用し、それらを連結したものにmd5を適用することで、テーブルの幅にかかわらず、集計結果を行あたり32バイトに抑えます。 - 実際のキーに基づいてチャンク境界を決めます(
row_number() % chunk_size)。これにより、疎なキー、UUID、複合キーをすべて均等にチャンク分割できます。最初と最後のチャンクには上限・下限を設けないため、ターゲットにのみ存在する行も検出できます。 - 純粋な差分関数を使います。 単体テストが非常に簡単で、CLI、MCP サーバー、プランナー、シャドー実行、評価で再利用できます。
- CLIとMCPの両方で、単一のサービスレイヤー(src/service.ts)を使うため、両者の動作に食い違いが生じません。
- シャドー実行で実際のバグが見つかりました。 型変更の書き換えで、最初は列の
DEFAULT/NOT NULLが削除されていました(コミットcc4f55bで修正)。その後、入れ替え後も列の外部キーとインデックスが古い列に残る問題が見つかりました。どちらも、回帰テストと評価シナリオを追加して修正済みです。
制限事項(正直な一覧)
- PostgreSQL のみ対応しています。CI では 13、14、15、16、17 で統合テストとロック精度の評価を実行します。公開している評価値は 16 で測定したものです。
- ドリフト検出の対象は、テーブル、カラム、インデックス、制約、シーケンス、ビュー、関数/プロシージャ、トリガー、列挙型、拡張機能、行レベルセキュリティです。未対応の対象は、GRANT と権限、カラムの照合順序、コメント、パブリケーション/サブスクリプション、外部サーバー、テーブルのストレージオプションです。
- 一部のオブジェクトのドリフトには人手での対応が必要です。拡張機能のインストールまたはアップグレード(特権ロールが必要)、変更されたマテリアライズドビュー(再作成とリフレッシュが必要)、ラベルが追加または並べ替えられた列挙型(Postgres ではラベルをその場で削除または並べ替えできません)、カラムが変更されたビュー(
CREATE OR REPLACE VIEWではカラムの削除や型の変更ができません。シャドウ実行で報告されます)が該当します。 - テキストの主キーは、異なる照合順序のサーバー間で一致するよう、バイト単位(
COLLATE "C")で比較されます。このようなキーでの範囲スキャンでは主キーインデックスを利用できないため、テキストキーを持つ非常に大きなテーブルの検証は、整数キーまたは uuid キーの場合より時間がかかります。 - 行レベルセキュリティが有効な場合、
BYPASSRLSのないロールには、ポリシーで許可された行のみが表示されます。その場合、verifyは該当テーブルに関する注記でそのことを示します。 planとshadowはpublicスキーマで動作します。diff --schemaとverify --schemaは他のスキーマも対象にしますが、そこでのドリフトはまだ計画されません。- 名前の変更は削除+追加として報告され、参考情報として
possible_renameのヒントが付与されます。PgVouch が名前を自動変更することはありません。 - 主キーのないテーブルでは不一致を検出できますが、該当する行を特定することはできません。
- 検証では 2 つのスナップショットを比較するため、稼働中のターゲットでは処理中の行に差異が生じます。
verify --recheck Nはそうした差異を再確認し(--recheck-delay秒ごと、デフォルトは 5 秒)、最後まで解消されないものだけを残します。最初のチェックで見つかった差異だけを再確認するため、新たな書き込みによってテーブルが失敗し続けることはありません。チェックのたびにソース側で変化する行は引き続き報告される場合があり、「source still changing」と表示されます。最終的な切り替えの承認には、短時間の書き込み停止が最も確実な証明となります。 - 論理レプリケーションではシーケンス値が複製されないため、論理レプリカでは切り替え時に値を設定するまで、
verifyはシーケンスが遅れていると報告します。これは正しい動作です。忘れがちな手順だからです。 - ロックアナライザーが認識するステートメントの形式は 30 種類です。それ以外は「not in the rule table」としてフラグ付けされ、安全だと黙って判定されることはありません。
- 自動のバッチバックフィルには、単一の整数主キーが必要です。そうでない場合、バックフィルの手順は手動テンプレートになります。
- シャドウ実行でコピーされるのはスキーマのみです。そのため、証明できるのは結果の構造であり、本番負荷時の実行時間ではありません(ロックアナライザーがその点を扱います)。
- デモデータベースは
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 はオープンソースであり、バグ報告、新しいロックルール、新しい評価シナリオ、ドキュメントなどのコントリビューションを歓迎します。セットアップ方法と基本ルールについては CONTRIBUTING.md を、脆弱性を非公開で報告する方法については SECURITY.md をご覧ください。このプロジェクトは 行動規範 に従います。
ライセンス
Apache License 2.0 © 2026 Shubham Sagar。商用利用を含め、自由に使用、変更、配布できます。複製物には LICENSE ファイルと NOTICE ファイルを含めてください。また、すべてのコントリビューターからの特許ライセンスも付与されます。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。