Database & MCP

Postgres MCP サーバー:リードレプリカと接続プール最適化

クイックアンサー:自律型AIエージェント向けの postgres mcp サーバーをスケールさせるには、読み取りクエリをPostgreSQLリードレプリカへ分散し、PgBouncerまたはSupavisorをトランザクションモード(ポート6543)で配置し、厳格な statement_timeout(2,000〜5,000ms)を設定し、実行前に EXPLAIN クエリプラン解析を行ってフルテーブルスキャンを遮断する必要があります。


1. はじめに:自律型データベースAIエージェントのスケーラビリティ危機

2026年、Claude CodeCursor ComposerPydanticAI といった自律型AIエージェントは、Model Context Protocol(MCP) を介してリレーショナルデータベースと直接通信するようになりました。開発者が手作業でクエリを書くのを待つことなく、自律型の postgresql ai agent はテーブル定義を自律探索し、外部キー制約を解析し、リアルタイムに複雑な分析SQLを実行します。

しかし、無保護な database mcp server を本番のPostgreSQLプライマリノードに直結すると、致命的な障害が発生します:

  • コネクション枯渇: 自律エージェントのループが多数のサブタスクを並行起動。標準PostgreSQLはプロセスごとに5〜10MBのRAMを消費するため、瞬時に max_connections に達し、FATAL: remaining connection slots are reserved エラーで通常APIを巻き込んでダウンします。
  • プライマリノードのロック競合とCPU枯渇: エージェントがインデックスのない巨大テーブルのスキャン(Seq Scan)や直積結合を含む重いSQLを書き込み用マスター上で直接実行し、業務トランザクションを麻痺させます。
  • 暴走クエリ(Runaway Queries): 適切なタイムアウト制御がない場合、モデルのハルシネーションによる無限集計クエリがリソースを占有し続けます。
  • ブラインド実行リスク: 従来のMCPツールはLLMが生成したSQLをノーチェックで実行するため、事前コスト検証が欠落しています。

安全にAIエージェントを運用するには、リードレプリカ負荷分散PgBouncer/Supavisorによるトランザクションプーリング厳格なタイムアウト設定、そして 事前EXPLAIN解析 を組み合わせたエンタープライズ級 mcp tool アーキテクチャが不可欠です。


2. 高可用性アーキテクチャ:リードレプリカの負荷分散とルーティング

エンタープライズPostgreSQLは、単一の読み書きPrimary(Master)ノードと複数のストリーミングRead Replicaで構成されます。Postgres MCPサーバーはインテリジェントルーターとして機能し、読み取り専用の探索処理とデータ更新トランザクションを厳密に分離します。

+----------------------------------------------------------------------------------------------------+
|                                    ホスト AI エージェント実行基盤                                  |
|                     (Claude Code CLI, Cursor Composer, LangGraph, PydanticAI)                      |
|                                                                                                    |
|    +------------------------------------------------------------------------------------------+    |
|    |                                      MCP クライアント機構                                |    |
|    |  - JSON-RPC 2.0 ツール呼び出しの送信 (execute_sql, explain_query, describe_schema)       |    |
|    +---------------------------------------------+--------------------------------------------+    |
+--------------------------------------------------|-------------------------------------------------+
                                                   | stdio / ストリーミング SSE (HTTP/2)
                                                   v
+----------------------------------------------------------------------------------------------------+
|                               POSTGRESQL MCP サーバー & インテリジェントルーター                   |
|                                                                                                    |
|    +------------------------+   +------------------------+   +--------------------------------+    |
|    | SQL AST & 構文解析器   |   | 事前コスト評価ガード   |   | レプリカ健全性・遅延監視       |    |
|    | - SELECT -> レプリカ   |   | - EXPLAIN (COSTS ON)   |   | - pg_last_xact_replay_ts()     |    |
|    | - WRITE  -> プライマリ |   | - 最大コスト閾値: 1.5万|   | - 自動フェイルオーバー         |    |
|    +-----------+------------+   +-----------+------------+   +---------------+----------------+    |
+----------------|----------------------------|--------------------------------|---------------------+
                 | 動的ルーティング判定       +--------------------------------+
                 |
                 +---------------------------------------+
                 |                                       |
                 v (更新トランザクション: DDL/DML)       v (読み取りクエリ: SELECT/EXPLAIN)
+-----------------------------------+   +------------------------------------------------------------+
| プライマリ PGBOUNCER (Port 6543)  |   | レプリカ負荷分散 PGBOUNCER プール (Port 6544)              |
| モード: Transaction               |   | ラウンドロビン / 最小接続数アルゴリズム                    |
+-----------------+-----------------+   +--------------+------------------------------+--------------+
                  |                                    |                              |
                  v                                    v                              v
+-----------------------------------+   +------------------------------+   +-------------------------+
| POSTGRESQL プライマリ (WRITER)    |   | POSTGRES リードレプリカ 1    |   | POSTGRES リードレプリカ 2|
| - WAL ストリーミング配信元        |==>| - Hot Standby (Streaming)    |==>| - Hot Standby (Replica) |
| - 高スループット書き込みトランザクション | - エージェント分析クエリ担当 |   | - スキーマ定義・探索担当 |
+-----------------------------------+   +------------------------------+   +-------------------------+

Postgres MCPレイヤーでのルーティング規則

エージェントが execute_sql を呼び出した際、MCPサーバーはSQL構文木(AST)を解析します:

  1. スキーマ情報・カタログ取得(\d, information_schema): 100% レプリカプールへルーティング。
  2. 分析SELECTクエリ: 健全なリードレプリカへラウンドロビン方式で均等分散。
  3. 実行前コスト評価(EXPLAIN ...): レプリカ上で本番統計情報を元に実行し、プライマリのバッファキャッシュを保護。
  4. 書き込み・DDL(INSERT, UPDATE, CREATE): 明示的な書き込み権限が付与されている場合のみプライマリへルーティング。

3. コネクションプーリング:PgBouncer / Supavisor 設定

数十〜数百のエージェントスレッドをPostgreSQLポート 5432 に直接繋ぐと即座に障害へ直結します。プーラーの導入は必須要件です。

セッションモードとトランザクションモードの比較

アーキテクチャ指標 直接接続 (ポート 5432) PgBouncer セッションモード PgBouncer / Supavisor トランザクションモード (6543)
バックエンドメモリ消費 接続ごとに 5〜10 MB 5〜10 MB (セッション固定) < 50 KB (プール接続をミリ秒で再利用)
最大同時クライアント 100〜300 (メモリ上限) 500〜1,000 10,000+ 仮想エージェント同時接続
接続確立オーバーヘッド 30〜80 ms 15〜30 ms < 1.5 ms チェックアウト速度
プリペアドステートメント 完全対応 完全対応 プロトコルレベルの匿名ステートメント対応が必要
セッション変数 (SET) 永続 セッション中保持 トランザクション内で SET LOCAL を使用
本番推奨基準 AIエージェントでは厳禁 メンテ作業時のみ 本番運用の必須スタンダード

最適化された pgbouncer.ini 設定例

[databases]
;; プライマリ書き込み先
postgres_primary = host=10.0.0.1 port=5432 dbname=production auth_user=pgb_auth pool_mode=transaction max_db_connections=40

;; レプリカ読み取り専用ロードバランスターゲット
postgres_replica = host=10.0.0.2 port=5432 dbname=production auth_user=pgb_auth pool_mode=transaction max_db_connections=80

[pgbouncer]
logfile = /var/log/postgresql/pgbouncer.log
pidfile = /var/run/postgresql/pgbouncer.pid
listen_addr = 0.0.0.0
listen_port = 6543
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt

;; AIエージェント向け高並行プール設定
pool_mode = transaction
max_client_conn = 10000
default_pool_size = 25
min_pool_size = 5
reserve_pool_size = 5
reserve_pool_timeout = 3

;; コネクション再利用とステートメント破棄
server_reset_query = DISCARD ALL
server_check_query = SELECT 1
server_check_delay = 10
max_user_connections = 500
query_timeout = 10.0
idle_transaction_timeout = 5.0

4. ベンチマーク検証:直結 vs プーリング vs レプリカ分散

LLMPodium開発チームは、3種類のPostgreSQL構成下で自律型AIエージェントの負荷テストを実施しました。

検証環境と測定手法

  • データベース環境: AWS Aurora PostgreSQL 17(Primary 1台 + Replica 2台、db.r7g.xlarge 各4 vCPU、32 GB RAM)。
  • エージェントクライアント: Claude Code CLI および LangGraph による並行100ワーカー。
  • クエリ内訳: 70% 結合・集計分析クエリ、20% スキーマメタデータ取得、10% pgvector HNSW 近傍検索。
+-------------------------------------------------------------------------------------------------------------------------+
|                               POSTGRESQL MCP スケーラビリティ&パフォーマンスベンチマーク (2026)                        |
+------------------------------------+------------------+------------+------------+-------------+------------+------------+
| 構成アーキテクチャ                 | 同時実行数 (Ops) | QPS        | レイテンシp50 | レイテンシp99 | 接続切断率 | マスターCPU|
+------------------------------------+------------------+------------+------------+-------------+------------+------------+
| 1. 単一ノード直結 (Port 5432)      | 100 Agents       | 412 req/s  | 84.5 ms    | 1,420 ms    | 18.4%      | 94.2%      |
| 2. PgBouncer プール (Primaryのみ)  | 100 Agents       | 1,280 req/s| 28.1 ms    | 142.0 ms    | 0.0%       | 88.6%      |
| 3. レプリカ分散 + PgBouncer (MCP)  | 100 Agents       | 3,850 req/s| 8.4 ms     | 24.8 ms     | 0.0%       | 12.1%      |
| 4. レプリカ + 事前EXPLAINガード    | 100 Agents       | 3,790 req/s| 9.1 ms     | 21.2 ms     | 0.0%       | 11.8%      |
+------------------------------------+------------------+------------+------------+-------------+------------+------------+

ベンチマークからの重要知見

  1. 接続切断の完全解消: 直結構成では接続上限超過により 18.4% が失敗。トランザクションプール導入により失敗率は 0.0% に激減。
  2. マスターCPU負荷の極小化: 読み取り処理をレプリカへ分散させた結果、マスターのCPU使用率は 88.6% から 12.1% へ劇的に低下。
  3. p99テールレイテンシが98%削減: 1,420 ms から 24.8 ms へ短縮され、エージェント側のタイムアウト連鎖を防止。

5. セキュリティガードレールとクエリタイムアウト制御

AIエージェントにスーパーユーザー権限を与えてはなりません。PostgreSQL標準のロールとタイムアウト機能で多層防御を構築します。

-- 1. エージェント専用の読み取りロールを作成
CREATE ROLE agent_readonly WITH LOGIN PASSWORD 'StrictAgentSecret2026!';

-- 2. データベース接続およびスキーマ参照権限の付与
GRANT CONNECT ON DATABASE production TO agent_readonly;
GRANT USAGE ON SCHEMA public TO agent_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO agent_readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON ALL TABLES TO agent_readonly;

-- 3. DDLおよびデータ変更権限を厳格に剥奪
REVOKE CREATE ON SCHEMA public FROM agent_readonly;
REVOKE ALL ON ALL FUNCTIONS IN SCHEMA public FROM agent_readonly;

-- 4. ロールレベルでフェイルセーフ設定を適用
ALTER ROLE agent_readonly SET statement_timeout = '4000ms';
ALTER ROLE agent_readonly SET lock_timeout = '1000ms';
ALTER ROLE agent_readonly SET idle_in_transaction_session_timeout = '3000ms';
ALTER ROLE agent_readonly SET default_transaction_read_only = on;

-- 5. 1クエリノードあたりのメモリ上限を設定しOOMを防ぐ
ALTER ROLE agent_readonly SET work_mem = '32MB';

6. 事前 EXPLAIN クエリプラン解析の実装

database mcp server において最も画期的な性能向上策は、実行前EXPLAIN検証(Pre-Flight EXPLAIN) です。SQLを実行する前に、MCPサーバーはリードレプリカ上で EXPLAIN (COSTS ON, FORMAT JSON) を実行し、推定実行コストとスキャン方式を検査します。

+----------------------------------------------------------------------------------------------------+
|                               事前 EXPLAIN クエリプラン評価フロー                                  |
+----------------------------------------------------------------------------------------------------+
                                 エージェントが execute_sql(query) を呼出
                                               |
                                               v
                             +-----------------------------------+
                             |  EXPLAIN (FORMAT JSON) を実行     |
                             +-----------------+-----------------+
                                               |
                                               v
                             +-----------------------------------+
                             | 計画ノード解析: コストとスキャン  |
                             +-----------------+-----------------+
                                               |
                      +------------------------+------------------------+
                      |                                                 |
             推定コスト > 15,000                               推定コスト <= 15,000
             または巨大テーブルの Seq Scan                      かつ全経路でインデックス使用
                      |                                                 |
                      v                                                 v
      +-------------------------------+                 +-------------------------------+
      | クエリの実行をブロック        |                 | リードレプリカ上で安全に実行  |
      | エージェントへ修正指示を返送: |                 | 取得データをエージェントの    |
      | "実行拒否: orders テーブルで  |                 | コンテキスト窓へストリーミング|
      | 全表走査 (Cost: 84,200)。     |                 +-------------------------------+
      | 検索条件にインデックスを追加。"|
      +-------------------------------+

TypeScript による事前評価ガードの実装

import { Pool } from 'pg';

const replicaPool = new Pool({
  connectionString: process.env.DATABASE_REPLICA_URL, // PgBouncerポート 6543
  statement_timeout: 4000,
});

const MAX_ALLOWED_QUERY_COST = 15000;

interface ExplainPlanNode {
  'Node Type': string;
  'Relation Name'?: string;
  'Total Cost': number;
  Plans?: ExplainPlanNode[];
}

export async function executeSafeAgentQuery(sql: string) {
  // 1. SELECTおよびWITHクエリのみを許可
  const trimmed = sql.trim().toUpperCase();
  if (!trimmed.startsWith('SELECT') && !trimmed.startsWith('WITH')) {
    throw new Error('拒否: レプリカ上では SELECT および WITH クエリのみ許可されます。');
  }

  // 2. 事前 EXPLAIN 評価
  const explainSql = `EXPLAIN (FORMAT JSON, COSTS ON) ${sql}`;
  const explainResult = await replicaPool.query(explainSql);
  const plan: ExplainPlanNode = explainResult.rows[0]['QUERY PLAN'][0]['Plan'];

  // 3. 実行計画ツリーの走査とコスト閾値チェック
  const violations: string[] = [];
  function inspectNode(node: ExplainPlanNode) {
    if (node['Total Cost'] > MAX_ALLOWED_QUERY_COST) {
      violations.push(`推定コスト ${node['Total Cost']} が上限値 ${MAX_ALLOWED_QUERY_COST} を超過`);
    }
    if (node['Node Type'] === 'Seq Scan' && node['Total Cost'] > 3000) {
      violations.push(`テーブル '${node['Relation Name']}' に対するフルテーブルスキャンを検出`);
    }
    if (node.Plans) {
      node.Plans.forEach(inspectNode);
    }
  }

  inspectNode(plan);

  if (violations.length > 0) {
    return {
      status: 'rejected',
      error: 'クエリプランが安全基準を満たしていません。',
      reasons: violations,
      suggested_action: 'インデックス付きカラムで絞り込むか、取得範囲を限定してください。',
    };
  }

  // 4. 安全な本番実行
  const startTime = Date.now();
  const result = await replicaPool.query(sql);
  return {
    status: 'success',
    duration_ms: Date.now() - startTime,
    rowCount: result.rowCount,
    rows: result.rows,
  };
}

7. Claude Code および Cursor での接続設定

Claude Code CLI での登録 (~/.claude.json)

# プール経由のリードレプリカを登録
claude mcp add postgres-cluster -- npx -y @modelcontextprotocol/server-postgres \
  "postgresql://agent_readonly:StrictAgentSecret2026!@pgbouncer.internal:6543/production?sslmode=require"

詳細ルーティング設定 (claude_desktop_config.json):

{
  "mcpServers": {
    "postgres-cluster": {
      "command": "node",
      "args": ["/usr/local/bin/postgres-mcp-router/dist/index.js"],
      "env": {
        "PRIMARY_DB_URL": "postgresql://agent_writer:SecretWrite2026@primary-pooler.internal:6543/production?sslmode=require",
        "REPLICA_DB_URL": "postgresql://agent_readonly:StrictAgentSecret2026!@replica-pooler.internal:6543/production?sslmode=require",
        "STATEMENT_TIMEOUT_MS": "4000",
        "MAX_EXPLAIN_COST": "15000",
        "ENABLE_EXPLAIN_GUARD": "true"
      }
    }
  }
}

Cursor Composer での設定 (.cursor/mcp.json)

{
  "mcpServers": {
    "database-agents": {
      "command": "npx",
      "args": [
        "-y",
        "@supabase/mcp-server-supabase",
        "--db-url",
        "postgresql://agent_readonly:StrictAgentSecret2026!@aws-0-us-east-1.pooler.supabase.com:6543/postgres?sslmode=require"
      ]
    }
  }
}

8. インフラ TCO コスト分析と投資対効果

+----------------------------------------------------------------------------------------------------+
|                               AIエージェントDBクラスタの月間運用TCO                                |
+------------------------------------+--------------------------+------------------+-----------------+
| インフラ構成要素                   | スペック                 | 想定ワークロード | 月額コスト      |
+------------------------------------+--------------------------+------------------+-----------------+
| AWS Aurora Serverless v2 主ノード  | 2〜8 ACU (4〜16 GB RAM)  | コア業務の書き込み | $120.00         |
| Aurora リードレプリカ (2台構成)    | 各 2〜4 ACU (4〜8 GB RAM)| エージェント分析 | $140.00         |
| PgBouncer 独立コンテナクラスタ     | 2x AWS Fargate (0.5 vCPU)| 10,000 クライアント| $22.00          |
| Supabase チームプラン(代替候補)  | Pro + コンピュート追加   | プーラー内包     | $85.00          |
| Claude 3.7 Sonnet 推論費用         | 入力1.5億 / 出力2,000万  | 5,000タスク実行  | $675.00         |
| DeepSeek V3 推論費用(コスト重視) | 入力1.5億 / 出力2,000万  | 5,000タスク実行  | $27.30          |
+------------------------------------+--------------------------+------------------+-----------------+
| 合計月額コスト (Claude 3.7運用)    | エンタープライズ構成     | 5,000タスク/月   | $957.00         |
| 合計月額コスト (DeepSeek V3運用)   | コスト最適化構成         | 5,000タスク/月   | $309.30         |
+------------------------------------+--------------------------+------------------+-----------------+

9. 本番運用チェックリストとまとめ

  1. トランザクションモード必須化: エージェントの接続はすべて PgBouncer/Supavisor ポート 6543 経由とし、5432 直結を禁止する。
  2. リードレプリカへの完全オフロード: SELECT、スキーマ探索、ベクトル検索をストリーミングレプリカに限定する。
  3. タイムアウトのロール固定: statement_timeout = '4000ms'lock_timeout = '1000ms' を設定する。
  4. EXPLAIN事前ガードの配備: 推定コスト15,000超または大テーブルのフルスキャンを自動遮断する。
  5. 読み取り専用属性の強制: default_transaction_read_only = on をエージェントロールに適用する。
  6. レプリケーション遅延の監視: pg_last_xact_replay_timestamp() を監視し、データ鮮度を保証する。
← 記事一覧へ
0 / 4