sql-steward について
sql-stewardは、ガバナンスを適用したデータベースアクセスを必要とするチーム向けのMCP SQLゲートウェイです。運用者が定義したセマンティックレイヤーから読み取り専用クエリを生成し、取得前にPIIを拒否します。
主な機能
- 01エンティティ、レコード、メトリクス用の型付きツール
- 02SELECTのみを生成するクエリコンパイル
- 03取得前のPIIポリシーチェック
- 04改ざん検知可能な監査検証
- 05SQL Server、Postgres、SQLiteに対応
活用シーン
- 01承認済みメトリクスをAIエージェントに公開
- 02生SQLを使わずにエージェントからレコードを参照
- 03制限対象のPIIフィールド取得を防止
- 04エージェント呼び出しの監査チェーンを検証
MCP 対応
MCPクライアントに型付きデータベースツールを公開し、生SQL実行ツールは提供しません。クエリは設定済みセマンティックレイヤーから生成され、ポリシーで禁止されたPIIは実行前に拒否されます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
uvx sql-stewardSQL_STEWARD_DB_URLシークレットSQLAlchemy URL of the database to read (read-only account recommended)SQL_STEWARD_LAYERPath to the semantic layer YAML (default: semantic.yaml)ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
9掲載時のツール一覧 · 2 週間前に更新
このツールにパラメーターはありません。
詳細
重要
このリポジトリは Governed Agent Stack モノレポに移行しました。
現在の開発は
packages/sql-steward/で行われています。 このリポジトリはアーカイブされ、読み取り専用です。すべてのコミット履歴はここに保存されています。 新しい開発、イシュー、リリースはモノレポで行われます。
sql-steward
Governed Agent Stack の一部です。実際のデータベースに接続して監査できる AI エージェント向けの、無料でオンプレミス利用可能な構成要素です。
Model Context Protocol 経由で公開される、AI エージェント向けの統制された SQL ゲートウェイです。エージェントが接続文字列を取得することも、SQL を書き込むこともありません。型付きツールを呼び出すと、sql-steward はすべてのクエリをお客様が管理するセマンティックレイヤーからコンパイルし、クエリ実行前にブロック対象の PII を拒否して、行を返します。SQL Server、Postgres、SQLite で同じツールを利用できます。
多くの SQL MCP サーバーは、モデルに run_sql ツールを渡し、実行後に不正なクエリを検出しようとします。sql-steward はそのツール自体をなくします。エージェントができるのは、エンティティやメトリクスを指定し、お客様が作成した許可リストから選ぶことだけなので、プロンプトからデータベースの生 SQL に至る経路はありません。
データベースを保護する様子をライブでご覧ください。 統制ありと統制なしのデモでは、同じリクエストを、顧客の PII を漏えいさせてテーブルを空にする単純な run_sql エージェントと、コンパイル時に拒否する sql-steward の両方に送ります。
3 つの保証
- 設計上、読み取り専用です。
run_sql、query、executeツールはありません。コンパイラーが生成できるのはSELECTだけなので、書き込みはブロックされるのではなく、表現できません。 - 取得前に PII を拒否します。 すべてのフィールドに PII タグを付けられます。リクエストがポリシーでブロックされたカテゴリに触れる場合、SQL のコンパイルや実行が始まる前に、sql-steward は構造化された理由とともに拒否します。
- 監査可能です。 agent-blackbox を使って、すべての呼び出し、拒否、エラーを改ざん検知可能なハッシュチェーンログに記録できます。また、
audit-verifyを使って、書き換えがないことを証明できます。
10 秒で確認
pip install sql-steward # or: pipx install sql-steward
sql-steward demo # zero config, no API key, no agent, SQLite
1) get_metric('mrr_total', dimensions=['plan']) -> safe aggregate
compiled: SELECT subscriptions.plan, SUM(subscriptions.mrr) AS mrr_total
FROM subscriptions GROUP BY subscriptions.plan LIMIT 1000
{'plan': 'pro', 'mrr_total': 297.0}
{'plan': 'team', 'mrr_total': 598.0}
2) get_metric('mrr_total', dimensions=['customers.country']) -> auto-join
compiled: ... INNER JOIN customers ON subscriptions.customer_id = customers.id ...
3) get_records('customers', fields=['id','email']) -> PII refusal
refused: {"kind": "pii_blocked", "detail": "Field 'customers.email' is tagged
EMAIL_ADDRESS, which this policy refuses."}
セマンティックレイヤー
この YAML が、エージェントとデータベース間の契約のすべてです。コードと同じようにレビューしてください。
dialect: postgres
entities:
customers:
table: customers
fields:
id: {type: int}
name: {type: text, pii: PERSON}
email: {type: text, pii: EMAIL_ADDRESS}
country: {type: text}
subscriptions:
table: subscriptions
fields:
customer_id: {type: int}
plan: {type: text}
mrr: {type: numeric}
joins: # nothing reachable that isn't listed here
- left: subscriptions
right: customers
on: subscriptions.customer_id = customers.id
metrics:
mrr_total: # the aggregation is fixed; the agent only
entity: subscriptions # chooses dimensions/filters from the lists
aggregate: sum
field: mrr
dimensions_allowed: [plan, status, customers.country]
filters_allowed: [status, customers.country]
policy:
block_pii: [EMAIL_ADDRESS, CREDIT_CARD]
max_rows: 1000
定義されていない結合を要求すると、関係が推測されるのではなく unreachable_entity が返されます。リストにないディメンションでメトリクスをグループ化しようとすると、dimension_not_allowed が返されます。メトリクスやフィールドの名前を誤ると、実在する項目と最も近い表記がエラーに表示されるため、エージェントは別の探索呼び出しをせずに、1 回のやり取りで自ら修正できます。
エージェントに公開されるツール
| ツール | 目的 |
|---|---|
list_entities() | 読み取り可能な対象と、利用可能なメトリクスを確認します |
describe_entity(entity) | フィールド、型、PII タグ(ブロック対象にはその旨を表示)を確認します |
list_metrics() | メトリクスと、それぞれに指定できるディメンション/フィルターを確認します |
get_records(entity, fields, filters, order_by, limit) | 1 つのエンティティから行を読み取ります |
get_metric(metric, dimensions, filters, limit) | 事前承認済みの集計を実行します |
semantic_search(entity, query, k, filters) | エンティティの埋め込み列を対象に、pgvector の最近傍検索を実行します |
audit_verify() | 改ざん検知可能な監査チェーンを検証します |
フィルターの形式は {field, op, value} です。演算子は =, !=, <, <=, >, >=, like, in, not in, is null, is not null です。値は常にバインドパラメーターとして渡され、SQL に直接埋め込まれることはありません。
MCP クライアントに接続する
セマンティックレイヤーの YAML は、SQL_STEWARD_LAYER で指定した場所に保存します。Claude Desktop(claude_desktop_config.json)の場合:
{
"mcpServers": {
"sql-steward": {
"command": "sql-steward",
"env": {
"SQL_STEWARD_LAYER": "/full/path/to/semantic.yaml",
"SQL_STEWARD_DB_URL": "postgresql+psycopg://[email protected]/warehouse"
}
}
}
}
SQL_STEWARD_DB_URL は SQLAlchemy URL なので、同じサーバーで SQL Server(mssql+pyodbc://...)、Postgres(postgresql+psycopg://...)、SQLite(sqlite:///path.db)を読み取れます。追加パッケージを指定して、対応するドライバーをインストールしてください:pip install "sql-steward[postgres]" または "[mssql]"。
オプション:スタックのその他の要素
セマンティックレイヤーが主要な制御機能です。以下は追加のレイヤーで、すべてオプトイン方式であり、ライブラリがインストールされていない場合は何もしません:
pip install "sql-steward[rbac,mask,audit]"
export SQL_STEWARD_POLICY=/path/to/policy.yaml # query-warden second-pass role check
export SQL_STEWARD_ROLE=analyst
export SQL_STEWARD_MASK=1 # pii-veil masks anything left in results
export SQL_STEWARD_AUDIT_DB=logs/steward.db # agent-blackbox audit chain (on if installed)
export SQL_STEWARD_QUERY_BUDGET=200 # persistent per-role query cap (SQLite-backed)
export SQL_STEWARD_BUDGET_WINDOW=3600 # optional: make the cap a sliding window, in seconds
export SQL_STEWARD_EMBED_URL=http://localhost:11434/api/embeddings # local embeddings for semantic_search
export SQL_STEWARD_EMBED_MODEL=nomic-embed-text
セマンティック検索(pgvector)
エンティティに pgvector 列を指定する search ブロックを設定すると、エージェントに semantic_search ツールが追加されます。他のすべての機能と同じルールに従います(PII は拒否され、結果はマスキングされ、呼び出しは監査されます):
entities:
documents:
table: documents
fields:
id: {type: int}
title: {type: text}
embedding: {type: vector}
search:
vector_column: embedding
dim: 768
returns: [id, title]
クエリテキストはローカルで埋め込み処理されます(ローカルの Ollama エンドポイントを指定するには SQL_STEWARD_EMBED_URL を設定してください。データが外部に送信されることはありません)。照合には pgvector の <=> 演算子を使用します。PostgreSQL 専用です。埋め込み列が返されることはありません。
- query-warden は、コンパイル済み SQL をロールポリシーに照らして再チェックします。
- pii-veil は、結果行に残った PII をマスキングします。
- agent-blackbox は、すべての呼び出しをハッシュチェーン付きの台帳に記録します。
sql-steward audit-verifyで検証できます。
セキュリティモデル
sql-steward は、モデルからデータベースまでの経路を管理します。ツールを呼び出すプロセスは信頼できるものと想定しています。この境界が、安全にデプロイできるか、リスクにさらされるかを分けるため、明確に述べておく価値があります。
モデルが何を求めても強制されること。 すべての呼び出しで同じゲートが適用されます。設計上読み取り専用であり、取得前にブロック対象の PII を拒否し、query-warden による任意のロールチェックを行い、pii-veil で結果をマスキングし、呼び出しをハッシュチェーンで監査します。モデルが脱獄されても、書き込み、ブロック対象の列の読み取り、このレイヤーで定義されていないエンティティへのアクセスはできません。これらはモデルが適切に振る舞うことを信頼するのではなく、設計によって保証されます。
行わないこと。 sql-steward は強制適用レイヤーであり、入口ではありません。
- 呼び出し元を認証しません。
SQL_STEWARD_ROLEは設定値であり、検証済みの ID ではありません。sql-steward は、渡されたロールが正しいものとして信頼します。 - ユーザーごとの権限を解決しません。ユーザーごとに異なるデータを表示する必要がある場合は、呼び出し元がユーザーをロールに対応付け、呼び出し前に設定します。ロールチェックはポリシーを適用しますが、ユーザーが誰なのかを判断するものではありません。
- 通信を保護しません。ローカルホストへの stdio で実行するか、TLS を終端するサービスの背後に配置してください。
- シークレットを管理しません。
SQL_STEWARD_DB_URLと監査キーAGENT_BLACKBOX_KEYは環境から読み込まれます。リポジトリに含めたファイルではなく、シークレットストアから渡してください。
利用者に用意していただくこと。 sql-steward は、同じマシン上の MCP ホストでも、ユーザーをすでに認証したゲートウェイでも、信頼できる呼び出し元の背後で動作するように設計されています。
- 信頼できるプロセスから呼び出してください。管理下にある MCP ホストのサブプロセス(stdio)、またはリクエストを認証し、検証済みの ID をロールに対応付けてから呼び出すゲートウェイの背後にあるサービスを利用します。
- 最小権限の読み取り専用データベースアカウントを使用してください。コンパイラーでは書き込みを表現できませんが、読み取り専用の権限を付与することは多層防御となり、依存関係に不備があった場合の影響範囲を適切に抑えます。
- データベースとローカルの埋め込みエンドポイントは、プライベートネットワーク内に置いてください。サーバーを信頼できない呼び出し元に公開しないでください。
- 接続文字列と監査キーはシークレットとして扱ってください。
想定する脅威。 この設計では、高度な能力を持つ、場合によっては侵害されたモデルと、信頼できる運用者を想定しています。エージェントがデータベースに対して実行できる操作を制限します。ID プロバイダーの代わりにはならず、信頼できないネットワークに単独で公開することを意図したものでもありません。信頼できるホストまたはゲートウェイの背後から実際のデータベースに接続すれば、モデルに許される操作はこの 3 つの保証によって制限されます。
他との違い
一般的な SQL MCP は、モデルが記述した任意の SQL を検証します(ブロックリスト方式:問題のあるものを見つけて阻止します)。sql-steward は、利用者が記述した定義から SQL をコンパイルします(許可リスト方式:記述されたものだけが存在します)。読み取り専用と PII に関する保証は検査ではなく設計によって確保され、クエリのインターフェースは 3 つのエンジンすべてで共通です。
セマンティックレイヤー(Cube、dbt Semantic Layer、Cortex Analyst、Genie)との比較
最も近いのは他の MCP サーバーではなく、セマンティックレイヤーです。Cube と dbt Semantic Layer は、コンパイル済みのメトリクス専用アクセスをすでに提供しており、Snowflake Cortex Analyst と Databricks Genie はどちらも、ガバナンスが適用されたモデルに対する自然言語での質問に回答します。それらのプラットフォームを利用しているなら、そちらを使ってください。このプロジェクトは、それらが対応していないケースを想定しています。
- オンプレミスで、エアギャップ環境にも対応します。 sql-steward は pip でインストールし、アカウントもデータウェアハウスも不要で、データを施設外に出すことなく SQL Server、Postgres、SQLite に接続します。Cortex Analyst は Snowflake、Genie は Databricks を前提としており、Cube のクラウド機能は同社のサービスを前提としています。データをベンダーに送信できない工場や病院にとって、この違いが判断のすべてです。
- PII は取得前に、同じチョークポイントで拒否されます。 ブロック対象のフィールドはコンパイル時にすべての呼び出し元に対して拒否されるため、モデルはポリシーで禁止された情報を、推論のためであっても読み取れません。セマンティックレイヤーはクエリ可能なメトリクスを管理しますが、タグ付けされた列がモデルに到達しないことを保証するようには設計されていません。
- SQL だけでなく、エージェント全体に対する改ざん検知可能な監査を提供します。 同じゲートパターンで、composed stack 内の KQL、ドキュメント取得、エージェントメモリを単一のハッシュチェーン台帳で管理します。データウェアハウスのセマンティックレイヤーが管理するのはデータウェアハウスであり、エージェントのその他のツールまでは管理しません。
要するに、セマンティックレイヤーはそのプラットフォーム上のクエリを安全にします。sql-steward は、エージェントがアクセス可能なすべての領域で、ユーザーのインフラストラクチャ上のエージェントを安全にします。
この違いは、孤立して運用するという意味ではありません。業界では、ツール間でセマンティックモデルを移行する中立的な形式として Apache Ossie(Open Semantic Interchange 形式。ASF でインキュベート中で、Snowflake、dbt、Salesforce の ワーキンググループが開始)に収束しつつあり、sql-steward もこれに対応しています。
sql-steward export semantic.yaml --out model.osi.yaml
エンティティ、結合、メトリクスは、それぞれ OSI のデータセット、リレーションシップ、メトリクスに対応します。
OSI にはまだガバナンスの語彙がないため、レイヤーをカタログではなく
コントラクトにする要素である PII タグ、ポリシーブロック、メトリクスの
許可リスト、チェックは、vendor_name: SQL_STEWARD の下の
custom_extensions に格納されます。表現できない要素は黙って破棄せず、
stderr に注記として出力します。出力は Ossie 独自のバリデーターを通るため、
sql-steward 用に作成したレイヤーを、標準を読み取れるあらゆるツールに渡せます。
実際のスキーマに合わせた拡張
セマンティックレイヤーは、コードのように読み、レビューできるよう、意図的に手作業で作成します。数十個のテーブルには適切な既定の方法ですが、数千個のテーブルには適していません。10,000 テーブルを持つ ERP 向けのレイヤーを手作業で書く人はいませんし、list_entities 呼び出し一回でレイヤー全体を返すと、エージェントのコンテキストにも収まりません。拡張方法は次のとおりです。
-
ひな形を作成してからレビューします。
sql-steward init --from-db <url>は稼働中のスキーマをリフレクトし、列の型をマッピングし、列名のヒューリスティックから PII タグを提案します(タグ付けが多めになるよう調整されているため、情報漏えいは既定の挙動ではなく、レビューでの修正になります)。また、外部キーから結合を推測します。読み込みと検証がそのままで可能なドラフトレイヤーを生成し、何を絞り込むべきかを示すヘッダーを付けます。目的はすべてを自動で公開することではありません。大規模なスキーマを、手入力ではなくレビュー可能なファイルから始められるようにし、白紙の状態から作る手間をなくすことです。sql-steward init --from-db "postgresql+psycopg://readonly@db/warehouse" --out semantic.yaml # then delete entities you do not need, check the PII tags, add metrics -
規模より範囲が重要です。 ガバナンスが適用されたレイヤーでは、データベース全体ではなく、エージェントが実際に必要とする少数のエンティティだけを公開します。10,000 テーブルのスキーマでも、20 エンティティのコントラクトにできます。何を含めるかを決める規律(
--include/--excludeを使って一部だけをドラフトすること)は、ツールの制限ではなく、モデルの特性です。 -
レイヤーの拡大に合わせて探索機能も拡張します。 レイヤーの拡大に合わせて
list_entities/describe_entityを参照します。この仕組みを非常に大きな単一レイヤーに適用する前に、これらのレスポンスに対する検索とページングを追加することが、次に解決すべき課題です。
開発
git clone https://github.com/Pawansingh3889/sql-steward
cd sql-steward
pip install -e ".[dev]"
pytest -q
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。