0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS 公式の Postgres MCP Server を Claude Desktop から Aurora につないでみた — Data API と直接接続を同一クラスタで比較

0
Posted at

1. はじめに

これまで OCI Database Tools MCP Server1 や SQLcl MCP2、Google の MCP Toolbox for Databases3 と、「MCP サーバ経由で LLM クライアントから DB につなぐ」検証を続けてきました。今回はその AWS 版として、awslabs/mcp リポジトリにある Amazon Aurora Postgres MCP Server(awslabs.postgres-mcp-server4 を Claude Desktop につなぎ、Aurora PostgreSQL(Serverless v2)に SQL を実行できるところまでを確かめます。今回検証したバージョンは 1.1.75 です。

着手前は「このサーバは RDS Data API6 経由らしい。だとすると Data API を有効化した Aurora が前提で、通常の RDS for PostgreSQL にはつなげないのでは」と想定していました。ところが公式 README の "Connection Methods" を読むと、接続方式は Data API 限定ではなく 3 つあります4

方式 説明(README の対応表より) 対応 DB
pgwire PostgreSQL ワイヤプロトコルでの直接接続 Aurora PostgreSQL / RDS for PostgreSQL
pgwire_iam pgwire と同じ経路で、認証に IAM を使う Aurora PostgreSQL のみ
rdsapi RDS Data API 経由で接続 Aurora PostgreSQL のみ

そこで本記事は「つないでみた」に加えて、同一の Aurora クラスタに rdsapi と pgwire の両方で接続し、前提条件の違いを実機で確かめることを軸にします。あわせて、デフォルトの読み取り専用(readonly)構成で書き込みが本当に拒否されるかも確認します。

1.1. 今回の検証ゴール

# 検証項目 達成できたとみなす条件
1 Claude Desktop から Aurora PostgreSQL(Serverless v2)に接続できる サンプルスキーマへの SELECT の結果が、投入データと一致する形で会話に返る
2 接続 2 方式(rdsapi / pgwire)を同一クラスタで比較できる 両方式で SELECT が返り、Data API 無効時に rdsapi だけが使えなくなることを確認できる
3 読み取り専用の構成で書き込みを防げる 書き込みを指示した際に実行が拒否され、DB 側に変更が入っていない

1.2. 結論(先出し)

  • 接続方式は RDS Data API 限定ではなく 3 方式。同一の Aurora クラスタに rdsapi・pgwire の両方で接続し、SELECT や JOIN 集計が投入データ・手計算と一致する結果を返した
  • 方式の切り替えは会話中に connect_to_database ツールで行え、MCP サーバの再起動は不要だった
  • rdsapi は「クラスタ側で Data API を有効化済み」が前提。無効化すると MCP サーバは起動時の疎通検証で終了してしまう(HttpEndpointNotEnabledException
  • デフォルト(--allow_write_query なし)では INSERT(DML)も DROP(DDL)も拒否され、前後のスナップショット比較で DB が無変更であることを確認した
  • ただしこの読み取り専用が対象にするのは run_query の SQL だけで、create_cluster のような AWS API を呼ぶツールは対象外だった(1.1.7 のソースコードで確認)
  • README の設定例と 1.1.7 の実引数は食い違っており、セットアップは --help の出力をもとに作る必要があった

2. 検証環境

項目 内容
MCP クライアント Claude Desktop(Windows 版)
MCP サーバ awslabs.postgres-mcp-server 1.1.75(WSL2 上の uvx で実行)
Aurora PostgreSQL 17.9 / Serverless v2(0〜2 ACU・ゼロスケール)/ 東京リージョン
クラスタ pgmcp-cluster(Data API 有効・マスターパスワードは RDS 管理)/ インスタンス pgmcp-instance-1(db.serverless・パブリックアクセス可)
サンプル DB appdb(products 8 行 / orders 10 行 / order_items 19 行)

クラスタ構成(0〜2 ACU・300 秒で自動停止のゼロスケール)は、以前ゼロスケールの再開時間を計測したときの構成の流用です7。検証中しか動かさないのでコストを抑えられます。

3. 構成と準備

3.1. 全体構成

Claude Desktop(Windows)から stdio で WSL2 上の MCP サーバを起動し、そこから Aurora へ 2 経路でつなぎます。

本記事では接続方式を公式 README の呼び名(rdsapi / pgwire / pgwire_iam)で書きます。起動引数やツール引数に渡す値は RDS_API / PG_WIRE_PROTOCOL / PG_WIRE_IAM_PROTOCOL です。

3.2. Aurora PostgreSQL Serverless v2 の作成

Aurora クラスタは次の方針で作りました。

  • --enable-http-endpoint: rdsapi 用に RDS Data API を有効化する。Serverless v2 でも Data API が使えることは公式のリージョン表で確認できます(東京は Aurora PostgreSQL 13.11 以降など)8
  • --manage-master-user-password: マスターパスワードを RDS が Secrets Manager に自動生成・管理する。postgres-mcp-server は --secret_arn を省略すると「クラスタの MasterUserSecret」に自動でフォールバックするため(--help に記載)、シークレットの手動作成が要らなくなります
  • セキュリティグループ: pgwire の直接接続用に、TCP 5432 のインバウンドを検証マシンのグローバル IP /32 だけに許可。インスタンスはパブリックアクセス可で作成
# クラスタ(Serverless v2・ゼロスケール・Data API 有効・マスターパスワードは RDS 管理)
aws rds create-db-cluster \
  --db-cluster-identifier pgmcp-cluster \
  --engine aurora-postgresql \
  --engine-version 17.9 \
  --master-username postgres \
  --manage-master-user-password \
  --database-name appdb \
  --enable-http-endpoint \
  --serverless-v2-scaling-configuration "MinCapacity=0,MaxCapacity=2,SecondsUntilAutoPause=300" \
  --vpc-security-group-ids sg-xxxxxxxxxxxx \
  --region ap-northeast-1

# インスタンス(db.serverless・パブリックアクセス可)
aws rds create-db-instance \
  --db-instance-identifier pgmcp-instance-1 \
  --db-cluster-identifier pgmcp-cluster \
  --db-instance-class db.serverless \
  --engine aurora-postgresql \
  --publicly-accessible \
  --region ap-northeast-1

# pgwire 用: 5432 を検証マシンの IP だけに許可
aws ec2 authorize-security-group-ingress \
  --group-id sg-xxxxxxxxxxxx \
  --protocol tcp --port 5432 \
  --cidr <検証マシンのグローバル IP>/32

作成から約 7 分でインスタンスが available になりました。

3.3. サンプルスキーマの投入 — Data API だけで完結

自然言語からの JOIN・集計が試せるように、小さな書店の商品・注文データを appdb に投入します。

CREATE TABLE products (
    product_id   integer      PRIMARY KEY,
    name         text         NOT NULL,
    category     text         NOT NULL,
    price_yen    integer      NOT NULL
);

CREATE TABLE orders (
    order_id      integer      PRIMARY KEY,
    ordered_at    timestamp    NOT NULL,
    customer_name text         NOT NULL
);

CREATE TABLE order_items (
    order_id     integer      NOT NULL REFERENCES orders (order_id),
    product_id   integer      NOT NULL REFERENCES products (product_id),
    quantity     integer      NOT NULL,
    PRIMARY KEY (order_id, product_id)
);

INSERT INTO products (product_id, name, category, price_yen) VALUES
    (1, 'PostgreSQL 実践入門',        '書籍',   3200),
    (2, 'Aurora 設計パターン',        '書籍',   3800),
    (3, 'MCP プロトコル解説',         '書籍',   2800),
    (4, 'SQL チューニング事典',       '書籍',   4500),
    (5, 'ノート PC スタンド',         '雑貨',   2400),
    (6, 'キーボードクリーナー',       '雑貨',    800),
    (7, 'データベースステッカー',     '雑貨',    500),
    (8, 'クラウド認定問題集',         '書籍',   3000);

INSERT INTO orders (order_id, ordered_at, customer_name) VALUES
    (101, '2026-06-01 10:15:00', '佐藤'),
    (102, '2026-06-03 14:30:00', '鈴木'),
    (103, '2026-06-05 09:45:00', '高橋'),
    (104, '2026-06-08 16:20:00', '田中'),
    (105, '2026-06-10 11:05:00', '伊藤'),
    (106, '2026-06-14 13:50:00', '渡辺'),
    (107, '2026-06-18 18:10:00', '山本'),
    (108, '2026-06-21 10:40:00', '中村'),
    (109, '2026-06-25 15:25:00', '小林'),
    (110, '2026-06-28 12:00:00', '加藤');

INSERT INTO order_items (order_id, product_id, quantity) VALUES
    (101, 1, 1), (101, 7, 2),
    (102, 2, 1), (102, 4, 1),
    (103, 3, 2),
    (104, 1, 1), (104, 5, 1),
    (105, 8, 1),
    (106, 4, 1), (106, 6, 3),
    (107, 2, 2), (107, 3, 1),
    (108, 1, 1), (108, 8, 1), (108, 7, 1),
    (109, 5, 2),
    (110, 3, 1), (110, 4, 1), (110, 6, 1);

投入は psql ではなく Data API(aws rds-data execute-statement)で行いました。SG の 5432 開放を待たなくても DDL・INSERT が通るので、先にデータを入れられます。ただし Data API は 1 コールにつき 1 ステートメント(複文不可)なので、上の SQL を 1 文ずつ実行しました。

# 行数の確認(投入後の検証)
aws rds-data execute-statement \
  --resource-arn arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:cluster:pgmcp-cluster \
  --secret-arn "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:rds!cluster-xxxxxxxx" \
  --database appdb \
  --sql "SELECT (SELECT count(*) FROM products), (SELECT count(*) FROM orders), (SELECT count(*) FROM order_items)"

行数は products = 8、orders = 10、order_items = 19 で投入どおりです。pgwire 側の疎通も WSL2 の psql からライターエンドポイントに SSL 接続し、PostgreSQL 17.9 on aarch64 が返ることを確認しました。

3.4. 起動引数は --help で確定する — README の設定例と食い違う

最初のつまずきです。公式サイト / README の設定例には --connection-string postgresql://... を渡す形が載っていますが、1.1.7 の --help にそのオプションは存在しません。実際の引数体系は次のとおりです。

usage: awslabs.postgres-mcp-server [-h]
                                   [--connection_method CONNECTION_METHOD]
                                   [--db_cluster_arn DB_CLUSTER_ARN]
                                   [--db_type DB_TYPE]
                                   [--db_endpoint DB_ENDPOINT]
                                   [--region REGION] [--allow_write_query]
                                   [--database DATABASE] [--port PORT]
                                   [--secret_arn SECRET_ARN]

options:
  --connection_method CONNECTION_METHOD
                        Connection method to the database. It can be RDS_API,
                        PG_WIRE_PROTOCOL OR PG_WIRE_IAM_PROTOCOL)
  --db_cluster_arn DB_CLUSTER_ARN
                        ARN of the RDS or Aurora Postgres cluster
  --db_type DB_TYPE     APG for Aurora Postgres or RPG for RDS Postgres
  --db_endpoint DB_ENDPOINT
                        Instance endpoint address
  --region REGION       AWS region
  --allow_write_query   Enforce readonly SQL statements
  --database DATABASE   Database name
  --port PORT           Database port (default: 5432)
  --secret_arn SECRET_ARN
                        Optional Secrets Manager ARN override. ...(中略)...

2025 年時点の AWS Blog の設定例(--resource_arn / --secret_arn を渡す Data API 前提の形)9とも異なるので、Web 上のセットアップ記事を参照するときはバージョンに注意が必要です。設定はドキュメントの例を写すのではなく、使うバージョンの --help の出力を確認して作るのが確実でした。

細かい点ですが、--allow_write_query のヘルプ文は "Enforce readonly SQL statements" となっていて紛らわしいです。実際の挙動は「無指定 = 読み取り専用、付けると書き込みを許可」で(README の記述とも整合します)、6 章の実測でも無指定で書き込みが拒否されました。

3.5. Claude Desktop への登録 — --db_endpoint は省略すると起動に失敗する

claude_desktop_config.json に次を追記します(アカウント ID とエンドポイントの固有部は xxxx でマスクしています。AWS_PROFILE はご自身のプロファイル名に読み替えてください)。

{
  "mcpServers": {
    "awslabs.postgres-mcp-server": {
      "command": "wsl.exe",
      "args": [
        "bash",
        "-lc",
        "AWS_PROFILE=aws-verify uvx awslabs.postgres-mcp-server@1.1.7 --connection_method RDS_API --db_cluster_arn arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:cluster:pgmcp-cluster --db_type APG --db_endpoint pgmcp-cluster.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com --database appdb --region ap-northeast-1"
      ]
    }
  }
}

なお AWS_PROFILE で指定するプロファイルは、Windows 側ではなく WSL 側の ~/.aws/credentials~/.aws/config)に定義したものを参照します。MCP サーバの実行環境は WSL なので、認証情報も WSL 側に用意しておいてください。

ここで 2 つ目のつまずきがありました。1.1.7 は --db_endpoint を省略すると、rdsapi(RDS_API)構成でも起動に失敗します("No database connection available" で終了)。原因は接続情報の検索キーの不一致です。サーバ内部では、接続の登録キーに AWS から解決したライターエンドポイントが入ります。一方、起動時の疎通検証(SELECT 1)は CLI 引数の db_endpoint(未指定なら None)をそのままキーにして接続を探すため、未指定だと登録済みの接続が見つかりません(1.1.7 のソースで確認10)。

対処は上の設定のように --db_endpoint にクラスタのライターエンドポイントを指定することです。エンドポイントの文字列は、aws rds describe-db-clusters で取得した値をそのまま使ってください。なお、指定した値はクラスタの正規エンドポイント一覧(writer / reader / カスタム / メンバー)と突き合わされ、一致しないと接続を拒否する検査も入っています(認証情報を第三者のホストに向けさせない対策、とソースコメントに記載があります)。別解として、起動時は接続指定なしで立ち上げておき、会話の中で connect_to_database ツールから接続する方法もあります。

エンドポイントを指定した状態では、起動ログに "Successfully validated database connection to Postgres" が出て正常に起動しました。

4. つないで聞いてみる(ゴール 1)

4.1. ツール一覧 — SQL 実行だけでなくクラスタ作成まである

Claude Desktop を再起動し、まずツール一覧を聞いてみます。

postgres-mcp-server で使えるツールを一覧してください

返ってきたのは次の 7 ツールです(事前に stdio の JSON-RPC で取得した tools/list とも一致)。

ツール名 用途
run_query PostgreSQL に対して SQL を実行
get_table_schema 指定テーブルのカラム定義・コメントを取得
connect_to_database 指定した DB に接続し、接続情報を内部保存
is_database_connected 接続済みかどうかを確認
get_database_connection_info 保存済みの接続情報を全件取得
create_cluster Aurora PostgreSQL クラスタを新規作成
get_job_status バックグラウンドジョブ(クラスタ作成など非同期処理)の状態を確認

ツール一覧を尋ねた会話。7 ツールの表が返っている

SQL 実行系(run_query / get_table_schema)だけでなく、クラスタ作成という AWS API 側の操作(create_cluster / get_job_status)を持つのが特徴です。これまで触った OCI Database Tools MCP や SQLcl MCP は SQL 実行が中心だったので、この点は後で 6.4 章・7.3 章で掘り下げます。

Claude Desktop 側では、MCP サーバのツールごとに使用可否・承認要否を設定できます。今回はすべて「承認が必要」のまま進めました。

awslabs.postgres-mcp-server のツールの権限画面。ツール単位で設定できる

4.2. 自然言語で SELECT

サンプルデータについて聞いてみます。

appdb の products テーブルにどんな商品があるか教えて

会話の流れは次のようになりました。

  1. 「appdb の接続情報を確認してから products テーブルを見てみます」と、まず get_database_connection_info で接続情報を確認
  2. スキーマ確認と SELECT を実行するも、一度失敗
  3. connection_method が必須のようなので、接続情報にあった rdsapi を指定して再実行します」と自己修正して成功

返ってきた表がこちらです。

product_id name category price_yen
1 PostgreSQL 実践入門 書籍 3,200
2 Aurora 設計パターン 書籍 3,800
3 MCP プロトコル解説 書籍 2,800
4 SQL チューニング事典 書籍 4,500
5 ノート PC スタンド 雑貨 2,400
6 キーボードクリーナー 雑貨 800
7 データベースステッカー 雑貨 500
8 クラウド認定問題集 書籍 3,000

products テーブルの内容を尋ねた会話。8 行の表が返っている

3.3 章で投入した 8 行と完全一致しており、ゴール 1 は達成です。途中で run_query 系ツールの必須引数 connection_method を LLM が一度省略して失敗し、保存済みの接続情報から rdsapi を読み取って自己修正する場面がありました(7.4 章で触れます)。

5. 接続方式を比べる(ゴール 2)

5.1. 会話の中で pgwire に切り替えて JOIN 集計

MCP サーバは rdsapi(RDS_API)構成で起動したままです。この状態で、会話から pgwire の接続を追加してみます。

東京リージョンの Aurora クラスタ pgmcp-cluster の appdb に、接続方式 pgwire で接続してください。接続できたら「6 月の注文で売上金額が多い商品トップ 3」を教えてください

  1. クラスタのライターエンドポイントを AWS CLI で取得し、connect_to_databasePG_WIRE_PROTOCOL 方式で実行 → 「接続に成功しました」
  2. run_query の 1 回目はカラム名の想定違い(id / unit_price を想定、実際は order_id / price_yen)で失敗。get_table_schema で実スキーマを確認してから再実行
  3. 3 テーブルの JOIN 集計の結果が返る
順位 商品名 売上金額
1 SQL チューニング事典 13,500円
2 Aurora 設計パターン 11,400円
3 MCP プロトコル解説 11,200円

pgwire で接続し直して 6 月の売上トップ 3 を集計した会話

投入データからの手計算と突き合わせると、次のとおり一致します。

  • SQL チューニング事典(4,500 円 × 3 冊)= 13,500 円
  • Aurora 設計パターン(3,800 円 × 3 冊)= 11,400 円
  • MCP プロトコル解説(2,800 円 × 4 冊)= 11,200 円
  • 次点の PostgreSQL 実践入門は 9,600 円でトップ 3 圏外

ポイントは MCP サーバを再起動していないことです。rdsapi で起動したサーバのまま、会話の中で pgwire の接続を追加できました。接続情報はサーバ内に保存され、get_database_connection_info で一覧できます。

5.2. Data API を無効化すると rdsapi はどうなるか

次に、rdsapi の前提条件「クラスタ側で Data API 有効化」を崩してみます。

aws rds disable-http-endpoint \
  --resource-arn arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:cluster:pgmcp-cluster

この状態で CLI の rds-data を実行すると、次のエラーになります。

An error occurred (HttpEndpointNotEnabledException) when calling the ExecuteStatement operation:
HttpEndpoint is being disabled for resource arn:aws:rds:ap-northeast-1:************:cluster:pgmcp-cluster.

(無効化直後は "is being disabled"、反映が終わると "is not enabled" にメッセージが変わります。API のレスポンス自体は即時に HttpEndpointEnabled: false を返しますが、実際の反映には数秒のラグがありました)

rdsapi 構成の MCP サーバをこの状態で起動すると、起動時の疎通検証(SELECT 1)で例外になり、サーバは起動せず終了します

ERROR | awslabs.postgres_mcp_server.connection.rds_api_connection:_execute_readonly_query:143
      - RDS Data API query failed, transaction rolled back
botocore.errorfactory.HttpEndpointNotEnabledException: An error occurred (HttpEndpointNotEnabledException)
when calling the BeginTransaction operation: HttpEndpoint is not enabled for resource
arn:aws:rds:ap-northeast-1:************:cluster:pgmcp-cluster.
ERROR | awslabs.postgres_mcp_server.server:main:1225
      - Failed to validate database connection to Postgres. Exit the MCP server

クライアント側からは「MCP サーバが落ちている」ようにしか見えないので、この状態の原因はサーバログを見ないと分かりません。

すでに rdsapi の接続が保存されている稼働中のセッションで試すと、会話面まで前提条件の違いが伝わってきました。

接続方式 rdsapi で products テーブルの件数を数えてください(pgwire は使わないでください)

  1. 保存済みの rdsapi 接続で run_query を実行 → エラー
  2. LLM が AWS CLI でクラスタ状態を自ら確認し、HttpEndpointEnabledFalse であることを特定
  3. 「Data API を再度有効化する必要があります」と対処を提示し、設定変更の実行可否を確認(→ 今回は「実行しない」を選択)
  4. 「rdsapi 接続方式では products の件数を取得できません(HttpEndpointNotEnabledException になります)。pgwire 接続で代わりに数えることもできますが、いかがですか?」と代替案を提示

Data API 無効の状態で rdsapi を指定した会話。原因の特定と pgwire の代替案が提示されている

rdsapi と pgwire の前提条件の違いが、そのまま会話の代替案として現れた形です。なお再有効化(enable-http-endpoint)はレスポンス即時に HttpEndpointEnabled: true を返すものの、クエリが通るまで約 2 分かかり、その間は "HttpEndpoint is being enabled" のエラーでした。反映中に enable を再発行すると InvalidResourceStateFault になる点も注意です。復旧後の SELECT count(*) FROM products は 8 で、無効化 → 再有効化によるデータへの影響はありませんでした。

5.3. 対応関係と前提条件のまとめ

今回の実測と公式の対応表4を突き合わせると次のようになります。

構成 rdsapi pgwire pgwire_iam
Aurora PostgreSQL(Data API 有効) ✅ 実測 OK ✅ 実測 OK 未検証(IAM 認証の有効化が別途必要)
Aurora PostgreSQL(Data API 無効) ❌ 実測 NG(HttpEndpointNotEnabledException ✅ 実測 OK(Data API と無関係) 未検証
非 Aurora の RDS for PostgreSQL ❌ 非対応(公式) ✅ 対応(公式。実機は省略) ❌ 非対応(公式)

実測した 2 方式の前提条件を並べるとこうなります。

観点 rdsapi(RDS Data API) pgwire(直接接続)
ネットワーク前提 不要(HTTPS エンドポイント。SG の 5432 開放なしで届く) SG の 5432 許可+パブリックアクセス可(または VPC 内の到達性)が必要
クラスタ側の前提 Data API の有効化(--enable-http-endpoint なし
認証 IAM(rds-data:ExecuteStatement)+ Secrets Manager Secrets Manager のパスワード(マスターまたは指定シークレット)
対応 DB Aurora のみ Aurora & RDS for PostgreSQL
会話中の切り替え connect_to_database で可能(再起動不要) 同左

6. 読み取り専用で書き込みを頼んでみる(ゴール 3)

MCP サーバは --allow_write_query なし(= 1.1.7 のデフォルト、読み取り専用)で起動した状態です。

6.1. INSERT(DML)は拒否される

products テーブルに「試し書き」という商品を 1,000 円で追加してください

  1. LLM が接続先を確認し、接続確立とスキーマ確認まで進む
  2. product_id が自動採番でないことを確認し、「現在の最大値は 8。9 として追加、category はどうするか」と確認してくる(→ NULL のままを選択)
  3. run_query で INSERT を実行 → 「現在接続している MCP サーバは読み取り専用(readonly)モードで構成されているためブロックされました」

INSERT を頼んだ会話。readonly モードでブロックされている

6.2. DROP TABLE(DDL)も拒否される

では products テーブルを DROP してください

  1. LLM が「不可逆な破壊的操作」と警告し、実行可否を確認してくる(→ 検証のためそのまま実行を選択)
  2. run_query で DROP を実行 → 「想定通り、readonly 設定により DROP も拒否されました」「products テーブルは無傷です」

DROP を頼んだ会話。実行前の警告と、readonly による拒否

DML(INSERT)だけでなく DDL(DROP)もブロックされることを確認できました。

6.3. DB 側が無変更であることの確認

会話上の「拒否されました」だけでは不十分なので、書き込み指示の前後で同一クエリのスナップショットを Data API で取得し、突き合わせました。

指標 before after 判定
products 行数 8 8 一致
orders 行数 10 10 一致
order_items 行数 19 19 一致
products.price_yen 合計 21,000 21,000 一致
order_items.quantity 合計 25 25 一致
public スキーマのテーブル数 3 3 一致(DROP されていない)

INSERT・DROP とも実行が拒否され、DB 側に一切の変更が入っていません。ゴール 3 も達成です。

6.4. この読み取り専用の実体 — SQL のキーワード検査で、create_cluster は対象外

この readonly の実体は、run_query に渡された SQL に対するキーワード・関数のブロックリスト検査です。README 自身が次のように明記しています4

Treat this as a best-effort, defense-in-depth mechanism, not a security boundary.

— README "Security Consideration"

「ベストエフォートの多層防御であり、セキュリティ境界ではない」という位置づけで、README は最小権限の PostgreSQL ロールで接続することもあわせて推奨しています。

さらに 1.1.7 のソースを確認すると、readonly の検査があるのは run_query の SQL 検査だけで、create_cluster には readonly のチェックがありません。readonly 構成のままでも、create_cluster は AWS API でクラスタ作成を実行する実装です10(課金を避けるため実機では実行せず、ソースの確認にとどめています)。歯止めになるのは実行 IAM の権限と、4.1 章で見たクライアント側のツール単位の承認です。

7. 考察

7.1. 接続 3 方式の使い分け

README "Connection Methods" の対応表では、pgwire が Aurora と RDS for PostgreSQL の両対応、pgwire_iam と rdsapi は Aurora 専用です4

前提条件の差は 5.3 章のとおりで、rdsapi は SG を開けずに HTTPS で届き、pgwire は 5432 への到達性(SG 許可とパブリックアクセス可、または VPC 内)を用意する必要がありました。

この 2 点から、使い分けは次のように整理できます。

  • VPC の外の端末から SG を開けずにつなぎたい → rdsapi(クラスタ側で Data API の有効化が必要)
  • 非 Aurora の RDS for PostgreSQL、または Data API を有効化できないクラスタ → pgwire(ネットワーク到達性の確保が必要)
  • パスワードではなく IAM 認証に寄せたい → pgwire_iam(今回は未検証)

なお「MCP サーバがどの DB につなげるか」という観点では、以前 OCI Database Tools MCP が Oracle Database 接続限定であることを確かめました11が、こちらは pgwire で非 Aurora の RDS までカバーしており、PostgreSQL の範囲では適用先が広い設計です。

7.2. rdsapi は読み取りでもトランザクションを張る

Data API 無効時のエラーは ExecuteStatement ではなく BeginTransaction 呼び出しで発生しました。読み取り専用のクエリでも BeginTransaction → 実行 → Commit/Rollback という流れで Data API を呼ぶ実装で、ソースでも読み取り経路の関数(_execute_readonly_query)がロールバック付きで実装されています10。1 回の SELECT が複数回の API 呼び出しになることは、エラーの出どころを探すときに知っておくと迷わずに済みます。

7.3. 「読み取り専用」の境界は SQL だけ — 土台は IAM とツール承認

6.4 章のとおり、README は readonly を "best-effort, defense-in-depth mechanism, not a security boundary" と明記し、最小権限の PostgreSQL ロールの併用を推奨しています(README "Security Consideration"4)。

ツール一覧には SQL 実行系に加えて create_cluster / get_job_status という AWS API 側の操作が並びます。ソース確認のとおり create_cluster は readonly の検査対象外なので、--allow_write_query を外して守れる範囲は SQL のデータ操作だけです。クラスタ作成のような AWS リソース操作を止めるのは、readonly フラグではなく、(1) MCP サーバを動かす IAM プリンシパルの権限を最小にすること、(2) クライアント側でツール単位の承認を挟むこと、の 2 つです。

この構図は「MCP サーバに何を許可するか」を SQL 権限だけで考えていると見落とします。SQL 実行が中心の OCI Database Tools MCP や SQLcl MCP と違い、このサーバはクラウドのリソース操作まで持っているので、DB ユーザーの権限と IAM の権限の両方を検討する必要があります。

7.4. エラーからの LLM の自己修正

今回の検証では、LLM がエラーから自力で復帰する場面が 2 回ありました。

  • run_query の必須引数 connection_method を省略して失敗 → 保存済みの接続情報から rdsapi を読み取り、指定し直して成功
  • Data API 無効化中の run_query 失敗 → AWS CLI でクラスタ状態を自ら確認して HttpEndpointEnabled: False を特定 → 再有効化の提案と pgwire の代替案を提示

いずれも、エラーが具体的な内容(必須引数の名前、HttpEndpointNotEnabledException という例外名)で返ってきたことが、会話面での原因特定と代替案の提示につながっていました。一方で 3.5 章の起動失敗のように、MCP サーバ自体が起動できないケースはツール呼び出しの手前なので、LLM からは手の出しようがなく、サーバログの確認が必要です。

8. まとめ

# 検証項目 結果
1 Claude Desktop から Aurora PostgreSQL に接続できる OK。7 ツールを認識し、products の SELECT が投入 8 行と完全一致で返った
2 接続 2 方式(rdsapi / pgwire)を同一クラスタで比較できる OK。両方式で SQL 実行に成功し、会話中の切り替えも再起動不要。Data API 無効化で rdsapi だけが使えなくなり、pgwire は影響を受けなかった
3 読み取り専用の構成で書き込みを防げる OK。INSERT・DROP とも拒否され、前後スナップショットが完全一致。ただし対象は SQL のみで、create_cluster は対象外

「RDS Data API が前提」という着手前の想定は外れて、実際は 3 方式から選べる設計でした。そのぶん「どの方式を選ぶか=どの前提条件を用意するか」が最初の設計ポイントになります。今回試せていない pgwire_iam(IAM 認証の直接接続)や、同じ awslabs の DynamoDB MCP Server も続きの検証候補です。

  1. OCI Database Tools MCP Server を Claude Desktop につないでみた

  2. MCP経由でDBを触るエージェントを“端から端まで”追う ─ SQLcl MCP の監査証跡(Unified Audit)と Langfuse のトレースを突き合わせてみた

  3. Google の MCP Toolbox for Databases から Oracle Autonomous Database に wallet 接続してみた

  4. awslabs/mcp postgres-mcp-server(GitHub README) — "Connection Methods" / "Database Types" / "Security Consideration"。公式サイト版は Amazon Aurora Postgres MCP Server 2 3 4 5 6

  5. awslabs.postgres-mcp-server(PyPI) — 検証時バージョン 1.1.7(2026-06-25 リリース) 2

  6. Amazon RDS Data API の使用(AWS Docs) — 永続接続不要の HTTPS エンドポイントで SQL を実行する仕組み。認証情報は Secrets Manager 経由

  7. Aurora Serverless v2 のゼロスケール再開時間を Platform Version 4 で再計測してみた

  8. RDS Data API でサポートされているリージョンと Aurora DB エンジン(AWS Docs) — Aurora PostgreSQL の表。Serverless v2・プロビジョンドとも対応

  9. AWS Blog: Supercharging AWS database development with AWS MCP servers(2025-06-27)

  10. server.py(awslabs/mcp) 2 3

  11. OCI MySQL HeatWave に OCI Database Tools MCP でつなごうとしたら、MCP は Oracle 接続限定だった(2026/6)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?