Erdmates Logo
Erdmates
ブログ一覧へ
AIMCPスキーマ設計PostgreSQL

AIエージェントが読むデータベース:MCP時代のスキーマ設計原則

AIエージェントがMCPを通じてデータベースに直接接続するケースが増えています。エージェントがスキーマを誤って解釈しないように名前・コメント・制約を設計し、権限を安全に分ける方法を整理します。

2026年10月12日8 分で読めます

AIエージェントがデータベースを直接読み始めた

MCP(Model Context Protocol)は、AIツールが外部のデータやシステムに接続する方式を一つに揃えようとするオープン標準です。Anthropicが2024年11月25日に公開し、2025年12月9日にLinux Foundation傘下のAgentic AI Foundationに寄贈されました。データベース用のMCPサーバーを接続すると、AIエージェントがテーブル一覧やカラムを照会し、SQLを直接実行できます。

ここで設計の観点に変化が生まれます。人間の開発者は社内Wikiを読んだり同僚に尋ねたりできますが、エージェントが見るのはほとんどがデータベースカタログ — テーブル名、カラム名と型、制約、コメント — です。スキーマそのものがドキュメントになってはじめて、エージェントは見当違いのテーブルを結合したり、単位を取り違えたりせずに済みます。

この記事では、人間にとっても有益で、エージェントにとってはさらに重要な5つの原則をPostgreSQLを基準に整理します。

1. 名前は略さず、意味どおりに

エージェントは usr_amt_cd のような略語を推測して解釈します。推測は外れることがあります。

-- 避けるべき名前:略語、単位なし、意味のないフラグ
CREATE TABLE ord (
  id     BIGINT PRIMARY KEY,
  usr    BIGINT,
  amt    NUMERIC,
  flg    CHAR(1),
  dt     TIMESTAMP
);

-- 推奨:意味・単位・タイムゾーンが名前と型に表れる
CREATE TABLE orders (
  id            BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  customer_id   BIGINT        NOT NULL,
  amount_krw    NUMERIC(12,0) NOT NULL,
  is_refunded   BOOLEAN       NOT NULL DEFAULT false,
  ordered_at    TIMESTAMPTZ   NOT NULL DEFAULT now()
);
  • 単位と通貨を名前に:amount_krw、duration_ms、weight_g
  • ブール値は is_・has_ で:flg の代わりに is_refunded
  • 同じ概念はすべてのテーブルで同じ名前に:あるところでは user_id、別のところでは member_no だと、エージェントは両者が同じものかどうか判断できません
  • 時刻は TIMESTAMPTZ で:タイムゾーンのない値は、人間もエージェントも解釈が分かれます

2. COMMENT ONで意味をカタログに残す

PostgreSQLの COMMENT ON は、説明をカタログ(pg_description)に保存します。コードコメントやWikiと違ってデータベースに付いて回るため、スキーマを照会するツールであれば同じ経路で一緒に読み取れます。

COMMENT ON TABLE orders IS '顧客の注文。決済完了時点で作成され、キャンセルしても行を削除しない(is_refundedで示す)。';
COMMENT ON COLUMN orders.amount_krw IS '決済金額(ウォン、付加価値税込み)。割引適用後の金額。';
COMMENT ON COLUMN orders.is_refunded IS '全額返金の有無。部分返金はrefundsテーブルを参照。';

保存された説明は次のように照会します。

SELECT a.attname                                  AS column_name,
       format_type(a.atttypid, a.atttypmod)       AS data_type,
       col_description(a.attrelid, a.attnum)      AS description
FROM pg_attribute a
WHERE a.attrelid = 'orders'::regclass
  AND a.attnum > 0
  AND NOT a.attisdropped;

何を書いておけばよいでしょうか?

  • 値の単位・含まれる範囲(付加価値税を含むかどうか、割引の前か後か)
  • ステータス値の意味と遷移ルール
  • **論理削除(ソフトデリート)**の有無と「実際に有効な行」の条件
  • 他のテーブルとの関係で注意すべき点(部分返金は別のテーブル、など)

3. ルールは制約で — エージェントはアプリケーションコードを見られない

「このカラムは pending、paid、shipped のいずれか」というルールがアプリケーションコードにしかなければ、エージェントにとっては存在しないルールです。制約として宣言すればカタログから読み取れますし、誤った値を書き込もうとしてもデータベースが拒否する最後の防衛線になります。

CREATE TABLE customers (
  id     BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  email  TEXT NOT NULL UNIQUE
);

CREATE TABLE shipments (
  id           BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  order_id     BIGINT NOT NULL REFERENCES orders (id),
  status       TEXT   NOT NULL
               CHECK (status IN ('pending', 'paid', 'shipped', 'delivered')),
  shipped_at   TIMESTAMPTZ,
  CHECK (status <> 'shipped' OR shipped_at IS NOT NULL)
);
  • 外部キーを明示すれば、エージェントは結合経路を推測せず、カタログで確認できます
  • CHECK は許容される値とカラム間のルールを明らかにします
  • NOT NULL・UNIQUE は「必ず存在する」「一つしかない」という事実を伝えます

4. エージェントに見せる面をビューで整理する

「月間売上」をエージェントに毎回元のテーブルから計算させると、質問のたびに返金を含めるかどうかやタイムゾーンの扱いが変わる可能性があります。合意した定義を一つのビューに固定して説明を付けておけば、エージェントはそのビューを使うだけで済みます。

CREATE VIEW monthly_revenue AS
SELECT date_trunc('month', ordered_at AT TIME ZONE 'Asia/Seoul') AS month_kst,
       sum(amount_krw)                                          AS revenue_krw,
       count(*)                                                 AS order_count
FROM orders
WHERE NOT is_refunded
GROUP BY 1;

COMMENT ON VIEW monthly_revenue IS '月間売上(ウォン)。韓国時間基準の月、全額返金された注文を除く。';

5. 権限は最小に — 境界はGRANT、それ以外は補助手段

エージェント用のアカウントは別のロールとして作成し、必要なスキーマの読み取り権限だけを付与します。

CREATE ROLE ai_reader LOGIN;  -- パスワード・認証方式は運用環境のポリシーに従って設定

GRANT USAGE  ON SCHEMA analytics TO ai_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA analytics TO ai_reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA analytics GRANT SELECT ON TABLES TO ai_reader;

-- ミス防止用のデフォルト値(セキュリティ境界ではない)
ALTER ROLE ai_reader SET default_transaction_read_only = on;
ALTER ROLE ai_reader SET statement_timeout = '15s';

注意点があります。default_transaction_read_only と statement_timeout は、セッション内でユーザーが変更し直せる設定です。誤って書き込みクエリを投げたり、重いクエリが長時間走り続けたりするのを減らしてはくれますが、防いでくれるわけではありません。実際の境界は GRANT で付与した権限です。

  • 個人情報のカラムは、エージェント用スキーマのビューから最初から外しておくほうが安全です
  • 行単位で範囲を分ける必要があるなら、ALTER TABLE ... ENABLE ROW LEVEL SECURITY とポリシー(CREATE POLICY)を使います
  • 本番のプライマリではなく読み取り用のレプリカ(スタンバイ)に接続すれば、重い分析クエリがサービスに与える影響を減らせます

Erdmatesで設計する

Erdmatesでテーブルやカラムに説明を書いておくと、PostgreSQLのDDLとしてエクスポートする際に COMMENT ON TABLE・COMMENT ON COLUMN 文として一緒に出力されます(MySQLの場合はテーブルの COMMENT)。逆に、既存のデータベースのSQLをインポートするときも COMMENT ON 文を読み取り、ERDの説明として復元します。ERDで外部キーの関係を線で確認しながら名前と説明を整えておけば、人間とエージェントが同じドキュメントを見ることになります。

まとめ

エージェントがデータベースを直接扱う時代のスキーマ設計は、新しい技術ではなく、昔からある原則をより厳格に守ることです。意味が伝わる名前、カタログに残る説明、制約として宣言されたルール、合意された定義を収めたビュー、そして最小権限。この5つを備えたスキーマはエージェントの間違いを減らし、たとえ間違えてもデータベースが食い止めてくれます。

Erdmatesで今すぐ始めましょう

AI搭載ERDエディタでデータベース設計を始めましょう。無料でご利用いただけます。

無料デモを試す無料で始める

関連記事

bigint・UUID v4・UUID v7:主キーの選び方(PostgreSQL 18 の uuidv7() 対応)

bigint・UUID v4・UUID v7 の主キーの長所と短所を比べ、PostgreSQL 18 に入った uuidv7() で変わった点と、状況別の選び方を整理します。

PostgreSQL 19プレビュー:スキーマ設計と運用に影響する変更点(ベータ4時点)

正式リリースを控えたPostgreSQL 19の変更点のうち、テーブル設計・マイグレーション・運用に直接影響するものを公式リリースノート(ベータ4)に基づいて整理します。ベータで取り下げられた機能や、アップグレード前に確認すべき動作の変更もあわせて見ていきます。

pgvectorでRAG用のベクトルテーブルを設計する:次元、インデックス、フィルタリングまで

PostgreSQLでpgvectorを使って文書の埋め込み(エンベディング)を保存する際のテーブル構造、ベクトル型ごとの次元制限、HNSWインデックス、メタデータフィルタリングの設計を、pgvector 0.8を基準に整理します。

Erdmates Logo
Erdmates

自然言語でデータベースを設計し、AI駆動ERDエディターでチームとリアルタイムでコラボレーション。

サービス

  • 機能紹介
  • 料金プラン
  • デモ
  • SQL→ERD変換

リソース

  • ブログ
  • ヘルプ
  • お問い合わせ

法的事項

  • 利用規約
  • プライバシーポリシー
  • 第三者提供
会社名: Produx|代表者: 최정회
住所: 강원특별자치도 원주시 솔우물2길 4-1 (무실동)
メール: master@erdmates.com
個人情報管理責任者: 최정회|ホスティングサービス提供者: Amazon Web Services

© 2026 Produx. All rights reserved.