F2T相談してみる
データ分析・基盤

MCP Toolbox for Databasesを試した -- LLMからSQLを安全に実行する仕組み

MCP Toolbox for Databasesを試した -- LLMからSQLを安全に実行する仕組み

LLMエージェントにデータベースを触らせたい場面が増えてきた。社内データの自然言語検索、レポートの自動生成、問い合わせボットでのリアルタイム在庫参照。

問題は「LLMに生SQLを自由に実行させるのは怖い」ということだ。プロンプトインジェクションでDROP TABLEされたら洒落にならない。

LLMからDBにアクセスする方法は、ざっくり3つある。

方法1: LLMにSQLを生成させて直接実行する

# 危険なパターン
sql = llm.generate(f"ユーザーの質問: {user_query}\nSQLを生成してください")
cursor.execute(sql)  # プロンプトインジェクションのリスク

自由度は高いが、安全性がゼロに等しい。本番環境では使えない。

方法2: 事前定義のクエリだけを許可する

ALLOWED_QUERIES = {
    'get_user': 'SELECT * FROM users WHERE id = ?',
    'list_orders': 'SELECT * FROM orders WHERE user_id = ? LIMIT 100',
}

安全だが、対応できる質問が固定される。新しい質問パターンのたびにコード更新が要る。

方法3: MCP Toolbox(間に入るミドルウェア)

MCP Toolbox for Databases(旧称: Gen AI Toolbox for Databases)は、Googleが2025年4月にオープンソースで公開したミドルウェアだ。この2つの中間に位置する。事前に「ツール」としてクエリテンプレートを定義し、LLMはツールを呼ぶ形でデータにアクセスする。パラメータはバインド変数として渡されるので、SQLインジェクションは構造的に防げる。

AIエージェント → (MCP) → Toolbox → (SQL) → データベース

GitHub上の googleapis/genai-toolbox リポジトリで開発されている。MCP(Model Context Protocol)に準拠しているので、Claude DesktopやCursorなどのMCPクライアントからそのまま使える。

セットアップ

インストール

Go製のバイナリが提供されている。

# バイナリをダウンロード(Linux/macOS)
export OS=$(uname -s | tr '[:upper:]' '[:lower:]')
export ARCH=$(uname -m)
curl -L "https://github.com/googleapis/genai-toolbox/releases/latest/download/toolbox-${OS}-${ARCH}" -o toolbox
chmod +x toolbox

Docker経由でも動く。

docker pull us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest

設定ファイル(tools.yaml)

Toolboxの設定は1つのYAMLファイルで完結する。

sources:
  my-postgres:
    kind: postgres
    host: localhost
    port: 5432
    database: myapp
    user: readonly_user
    password: ${DB_PASSWORD}

tools:
  get_monthly_sales:
    kind: postgres-sql
    source: my-postgres
    description: "指定月の売上合計を返す"
    statement: |
      SELECT
        DATE_TRUNC('month', order_date) AS month,
        SUM(amount) AS total_sales
      FROM orders
      WHERE DATE_TRUNC('month', order_date) = DATE_TRUNC('month', $1::date)
      GROUP BY month
    parameters:
      - name: target_month
        type: string
        description: "対象月(YYYY-MM-DD形式)"

  search_customers:
    kind: postgres-sql
    source: my-postgres
    description: "名前で顧客を検索する"
    statement: |
      SELECT id, name, email, created_at
      FROM customers
      WHERE name ILIKE '%' || $1 || '%'
      LIMIT 20
    parameters:
      - name: search_name
        type: string
        description: "検索する顧客名(部分一致)"

toolsセクションで定義した各ツールが、LLMから見える「使えるアクション」になる。descriptionフィールドがLLMのツール選択に直接影響するので、何ができるのか、どんなパラメータが必要なのかを明確に書く。

起動

./toolbox --tools-file tools.yaml --port 5000

ヘルスチェック:

curl http://localhost:5000/healthz
# {"status":"ok"}

エージェントからの接続(Python)

MCP対応のクライアントから接続できる。LangChainの場合:

from toolbox_langchain import ToolboxClient

# Toolboxサーバーに接続
client = ToolboxClient("http://localhost:5000")

# 利用可能なツールを取得
tools = client.load_toolset()

# LangChainのエージェントに渡す
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent

model = ChatOpenAI(model="gpt-4o")
agent = create_react_agent(model, tools)

# エージェントに質問
response = agent.invoke({
    "messages": [{"role": "user", "content": "先月の売上を教えて"}]
})

エージェントは get_monthly_salessearch_customers をツールとして認識し、質問に応じて適切なツールを選んでパラメータを渡す。SQL自体はToolboxが実行するので、エージェントはSQLを意識しない。

Claude DesktopからMCP経由で使う

claude_desktop_config.json に追加する。

{
  "mcpServers": {
    "my-database": {
      "command": "/path/to/toolbox",
      "args": ["--tools-file", "/path/to/tools.yaml", "--mcp"],
      "env": {
        "DB_PASSWORD": "your-password"
      }
    }
  }
}

--mcp フラグでMCPサーバーモードが有効になり、stdioで通信する。「先月の売上は?」と聞けば、Toolbox経由でDBを検索して回答してくれる。

対応データベース

2026年3月時点で以下に対応している。

データベース

ステータス

PostgreSQL

GA

MySQL

GA

Cloud SQL(PostgreSQL/MySQL)

GA

AlloyDB

GA

Cloud Spanner

GA

SQLite

ベータ

BigQuery

プレビュー

Google Cloudのマネージドデータベースとの統合が手厚い。Cloud SQLの場合、IAM認証でパスワード管理が不要になる。

sources:
  cloud-sql-prod:
    kind: cloud-sql-postgres
    project: my-gcp-project
    region: asia-northeast1
    instance: my-instance
    database: myapp
    # IAM認証を使う場合、user/passwordは不要

Cloud Runにデプロイすれば、サーバーレスで運用できる。

gcloud run deploy toolbox-server \
  --source . \
  --set-env-vars "TOOLS_FILE=tools.yaml" \
  --region asia-northeast1

セキュリティ面で評価できる点

パラメータ化クエリの強制

tools.yamlのSQL文では、パラメータがバインド変数($1, $2)として処理される。LLMの出力がSQL文の一部になることはない。SQLインジェクションに対する構造的な防御だ。

接続プール管理

各データソースへの接続プールがToolbox側で管理される。大量のリクエストが来ても、DBへの同時接続数はプール設定で制御できる。

sources:
  my-postgres:
    kind: postgres
    host: localhost
    port: 5432
    database: myapp
    user: readonly_user
    password: ${DB_PASSWORD}
    pool:
      max_connections: 10
      max_idle_time: 300s

読み取り専用ユーザーの推奨

SELECT権限だけ持つユーザーを作成しておけば、万が一ツール定義にミスがあっても、データの変更や削除は起きない。

CREATE USER readonly_user WITH PASSWORD 'secure_password';
GRANT CONNECT ON DATABASE myapp TO readonly_user;
GRANT USAGE ON SCHEMA public TO readonly_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_user;

他のアプローチとの比較

方法

安全性

柔軟性

セットアップ

LLM生SQL直接実行

簡単

固定クエリのAPI化

中程度

MCP Toolbox

中程度

Hasura / PostgREST

やや複雑

HasuraやPostgRESTもDB APIを提供するが、MCP準拠でLLMのツール呼び出しにネイティブ対応している点がToolboxの差別化要素になる。

使ってみて気づいたこと

tools.yamlの設計がすべて

ツール定義の粒度が粗すぎると、LLMが適切なツールを選べない。細かすぎると、ツール数が増えて選択精度が落ちる。1テーブルに対して2〜3個のツール(一覧取得、条件検索、詳細取得)を定義するのがちょうどいい。

descriptionの書き方が精度に直結する

LLMはツールのdescriptionを読んでどのツールを呼ぶか判断する。「商品を検索する」だけだと、「在庫を確認したい」という質問でこのツールが選ばれない。「商品を名前・価格帯で検索する。在庫確認にも使える。」と書くと選択精度が上がる。

起動が速い

Go製のシングルバイナリなので起動は一瞬。Docker不要で動く点も、開発環境のセットアップが楽でいい。

向かないケース

tools.yamlに定義したクエリしか実行できないので、「自由にデータを探索させたい」ユースケースには向かない。探索的な分析にはText-to-SQLアプローチのほうが適切だ。

始めるなら

  1. PostgreSQLかMySQLが手元にあるなら、バイナリをダウンロードしてtools.yamlを書く
  2. 2〜3個のツールを定義してToolboxを起動する
  3. Claude DesktopのMCP設定に追加して、自然言語でクエリしてみる
  4. 動作を確認したら、ツール定義を増やしていく

DBとLLMをつなぐ「安全な橋」が必要な場面で、MCP Toolboxは堅実な選択肢だ。

関連記事