db-gateway について
db-gatewayは、LLMとデータベースの間にセキュリティ層を設けるMCPサーバーです。機密フィールドのマスキング、ロール別のテーブルアクセス制御、リクエスト制限、クエリ記録を行い、Prisma、Postgres、MySQL、SQLite、MongoDB用のアダプターを備えています。
主な機能
- 01機密フィールドのマスキングまたは除去
- 02ロール別のテーブル・フィールド制御
- 03全体およびテーブル別のレート制限
- 04監査履歴の記録と検索
- 05Prisma、Postgres、MySQL、SQLite、MongoDB用アダプター
- 06権限チェック付きの任意の書き込み
活用シーン
- 01PIIをマスキングしながらLLMでデータを照会
- 02ロールやテーブル単位でDBアクセスを制限
- 03クエリ履歴や拒否された操作を確認
- 04LLMに制御されたDB書き込みを許可
MCP 対応
テーブルの照会、一覧表示とスキーマ確認、ゲートウェイ状態および監査履歴の確認に使う読み取りツールを提供します。書き込みを有効にすると、挿入、更新、削除のツールも利用できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
5掲載時のツール一覧 · 1 日前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| limit | integer | いいえ | ゲートウェイの上限を適用する前に取得する最大行数(デフォルト:50) |
| table | string | はい | クエリ対象のテーブル名 |
| filter | object | いいえ | キーと値のフィルターペア。例:{ status: 'active' } |
詳細
@guardbee/mcp-db-gateway
🇬🇧 英語 | 🇹🇷 トルコ語 | 🇨🇳 中国語 | 🇯🇵 日本語 | 🇰🇷 韓国語 | 🇧🇷 ポルトガル語 | 🇪🇸 スペイン語 | 🇩🇪 ドイツ語
KVKK / GDPR に準拠した MCP(Model Context Protocol)サーバーです。LLM とデータベースの間にセキュリティレイヤーを追加します。
データベースに直接クエリを実行する代わりに、Claude(またはその他の LLM)はこのゲートウェイを経由します。機密フィールドは自動的にマスキングされ、テーブルへのアクセスはロールによって制御され、すべてのクエリが監査ログに記録されます。
テレメトリーはデフォルトでオフです。
GUARDBEE_TELEMETRY=1を設定すると、サーバー、ツール、成功の有無、処理時間、およびファイルパスなどの短いパラメーター値が送信されます。content、token、passwordなどの長い文字列やフィールドはプレースホルダーに置き換えられます。詳しくは@guardbee/mcp-telemetryをご覧ください。
Claude ──► MCP Gateway ──► Database
│
├─ PII masking (tcKimlik → [REDACTED])
├─ Role check (ai-agent can only reach the products table)
├─ Rate limiting (max 100 queries/minute)
└─ Audit log (every query is recorded)
機能
- PII のマスキング — トルコの国民識別番号、IBAN、メールアドレス、電話番号、パスワードハッシュなどを自動的にマスキングします
- ロールベースのアクセス制御(RBAC) — ロールごとのテーブル許可/拒否リストとフィールドルール
- レート制限 — グローバルおよびテーブルごとのリクエストウィンドウ
- 監査ログ — コンソール、ファイル、HTTP ウェブフックに書き込み可能です
- Prisma / Postgres / MySQL / SQLite / MongoDB アダプター — 既存の
PrismaClient、pgのPool、mysql2のPool、better-sqlite3のDatabase、または MongoDB のDbを直接接続できます - 書き込みのサポート(オプション) — insert/update/delete に対応します。デフォルトでは無効で、テーブルごとおよびロールごとの権限で制御され、保護対象フィールドのガードと「テーブル全体を変更しない」ためのセーフティーネットで保護されます
- ユニットテスト 195 件 — マスキング、パイプライン、RBAC、レートリミッター、監査ログ、すべてのアダプター(読み取り+書き込み)を網羅しています
最近の変更(2026-09-15)
このパッケージの AI Gateway 拡張に関する取り組みに、3 つの新しいステップが追加されました。
1. query_audit_log ツール
以前、ゲートウェイの監査ログは書き込み専用でした。console/file/http シンクのいずれかに記録されるだけで、Claude 自身が「たった今何が起きたのか、どの呼び出しが拒否されたのか」を振り返って確認する方法はありませんでした。現在は確認できます。
// Tool called from the Claude side:
query_audit_log({ table: "orders", deniedOnly: true, limit: 20 })
- 仕組み:
AuditLoggerに、設定されたシンク(audit.bufferSize、デフォルトは 200)から完全に独立した、常時有効のインメモリーリングバッファが追加されました。シンクが"http"(送信後の応答を待たない Webhook)の場合でも、このバッファを通じて履歴をクエリできます。プロセスが再起動するとバッファはリセットされ、audit.enabled: falseの場合はデータが格納されません。 - フィルター:
table、tool(MCP ツール名。例:"delete_row")、operation(read/insert/update/delete)、deniedOnly(拒否された呼び出しのみ)、since(ISO 8601 タイムスタンプ)、limit(デフォルトは 50、最大 200)。結果は新しい順に返されます。 - 合わせて修正した実際のバグ:
registerDbTools(読み取りツール)とregisterWriteTools(書き込みツール)は、それぞれ独自のGatewayPipeline/AuditLoggerインスタンスを作成していました。そのため、insert_row/update_row/delete_rowの呼び出しによる監査イベントは、query_audit_logが読み取るバッファには一度も記録されませんでした。互いを認識しない別々のバッファが二つ存在していたためです。現在、server.tsは単一のGatewayPipelineインスタンスを作成し、両方のツールグループで共有します。 - テスト:
src/__tests__/audit-logger.test.ts(10 件のテスト:バッファの上限、各フィルター、リングバッファの動作)に加え、pipeline.test.tsに 3 件のテストを追加しました(読み取りと書き込みが同じバッファに記録されること、deniedOnlyとtableフィルターが組み合わせて機能すること、audit.enabled: falseの場合にバッファが空のままであることを検証)。
2. SQLite アダプター
ゲートウェイが Prisma/Postgres/MySQL に加えて better-sqlite3 でも動作するようになりました。
import Database from "better-sqlite3";
import { createServer, createSqliteAdapter } from "@guardbee/mcp-db-gateway";
const db = new Database("./app.db");
const server = createServer({}, createSqliteAdapter(db));
- pg/mysql と同じセキュリティパターン: テーブル名とカラム名はパラメーター化できないため、SQL に埋め込む前に検証します。ここでは
information_schemaの代わりに SQLite のPRAGMA table_info(table)を使用します。形式チェックに失敗する名前(例:users"; DROP TABLE users;--)や、実際のスキーマに存在しない名前は、クエリが SQLite に送られる前に拒否されます。 better-sqlite3はオプションのpeerDependencyに限られます。 ネイティブバインディングが必要なため、パッケージ自身のdevDependenciesには追加していません。実際のパッケージをインポートせず、pg/mysql のテストと同様に、SqliteQueryableインターフェースに一致するシンプルなモックオブジェクトを使ってテストを作成しました。- 挿入では
RETURNINGの代わりにlastInsertRowidを使用: SQLite のRETURNINGのサポート状況はバージョンによって異なるため、MySQL アダプターのinsertIdと同じ方法を採用しています。テーブルにidカラムがあり、それがすでにdataに含まれていない場合は、挿入された行にlastInsertRowidが付与されます。 - 追加の修正:
AuditEvent/AuditQueryFilter型は、パッケージのルート(index.ts)からエクスポートされていませんでした。GatewayPipeline.queryAuditLog()の呼び出しを独自に型付けしたい利用者向けに、エクスポートを追加しました。 - テスト:
src/__tests__/sqlite-adapter.test.ts(21 件のテスト)。pg-adapter.test.tsと同じシナリオ一式をカバーします。テーブル一覧表示、フィルターあり/なしのクエリ、上限数、未知のテーブル/カラムの拒否、インジェクションの試みの拒否、挿入(ID の割り当てを含む)、更新、削除です。
3. MongoDB アダプター
ゲートウェイは、mongodb ドライバーの Db インスタンスにも対応するようになりました。
import { MongoClient } from "mongodb";
import { createServer, createMongoAdapter } from "@guardbee/mcp-db-gateway";
const client = new MongoClient(process.env.DATABASE_URL!);
await client.connect();
const server = createServer({}, createMongoAdapter(client.db("mydb")));
- 異なる種類のリスクです。SQL インジェクションではなく、オペレーターインジェクションです。 pg/mysql/sqlite では、テーブル名やカラム名が SQL に埋め込まれるリスクがありました。MongoDB では識別子が埋め込まれることはありませんが、
filter/dataのキーが$where/$neのような Mongo オペレーターの場合や、値が{ $ne: null }のようなオペレーターオブジェクトの場合、ツールが宣言する「単純なキーと値の等価フィルター」が、気づかないうちに任意のクエリーに変わる可能性があります。このアダプターでは、以下をすべて事前に拒否します。$で始まるキー(filterとdataの両方).を含むキー(ドット区切りのパス。例:"passwordHash.reset"。オペレーターに似たリスクがあるほか、findProtectedWriteFieldsの完全一致による照合を回避する手段にもなります(その glob 対応範囲外の場合))- スカラーでない(オブジェクト/配列)フィルター値。
{ status: { $ne: "active" } }のようなオペレーターオブジェクトによる回避の試みも含みます
mongodbはオプションのpeerDependencyにすぎません。 SQLite アダプターと同様に、実際のパッケージをインポートせず、MongoDatabaseインターフェースに合致するモックオブジェクトを使ってテストを作成しました。- 「テーブル」はコレクションを指します。
tables()はlistCollections()に対応します。挿入時には、返される行に_id(ドライバーのinsertedId)を付加します。更新では{ $set: data }を指定してupdateManyを実行し、削除ではdeleteManyを実行します。 - テスト:
src/__tests__/mongo-adapter.test.ts(19 件のテスト)。コレクション一覧、フィルターあり/なしのクエリー、上限、3 つのオペレーターインジェクションのケース($で始まるキー、ドットを含むキー、オペレーターオブジェクトの値)、挿入/更新/削除をテストします。
クイックスタート
1. Smithery 経由でワンクリック接続
Smithery 経由でワンクリックで Claude Desktop に追加できます。
2. グローバルインストールで Claude Desktop に接続
npm install -g @guardbee/mcp-db-gateway
macOS の場合、~/Library/Application Support/Claude/claude_desktop_config.json に追加します。
{
"mcpServers": {
"guardbee-db-gateway": {
"command": "guardbee-gateway",
"env": {
"DATABASE_URL": "postgresql://user:pass@localhost:5432/mydb"
}
}
}
}
Windows:
%APPDATA%\Claude\claude_desktop_config.jsonLinux:~/.config/Claude/claude_desktop_config.json
Claude Desktop を再起動します。デモデータベースが自動的に読み込まれ、PII マスキングが有効になります。
3. プロジェクトで使用(Prisma)
npm install @guardbee/mcp-db-gateway
import { PrismaClient } from "@prisma/client";
import { createServer, createPrismaAdapter } from "@guardbee/mcp-db-gateway";
const prisma = new PrismaClient();
const server = createServer(
{
audit: { enabled: true, sink: "file", filePath: "./audit.jsonl" },
},
createPrismaAdapter(prisma)
);
Prisma を使用していない場合は、pg または mysql2 の接続を直接渡すこともできます。
// Postgres
import { Pool } from "pg";
import { createServer, createPgAdapter } from "@guardbee/mcp-db-gateway";
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const server = createServer({}, createPgAdapter(pool /*, { schema: "public" } */));
// MySQL
import mysql from "mysql2/promise";
import { createServer, createMysqlAdapter } from "@guardbee/mcp-db-gateway";
const pool = mysql.createPool(process.env.DATABASE_URL!);
const server = createServer({}, createMysqlAdapter(pool /*, { database: "shop" } */));
// SQLite
import Database from "better-sqlite3";
import { createServer, createSqliteAdapter } from "@guardbee/mcp-db-gateway";
const db = new Database("./app.db");
const server = createServer({}, createSqliteAdapter(db));
// MongoDB
import { MongoClient } from "mongodb";
import { createServer, createMongoAdapter } from "@guardbee/mcp-db-gateway";
const client = new MongoClient(process.env.DATABASE_URL!);
await client.connect();
const server = createServer({}, createMongoAdapter(client.db("mydb")));
セキュリティに関する注意: Prisma アダプターとは異なり、
pg/mysql2/better-sqlite3アダプターは生の SQL を生成します。テーブル名とカラム名はパラメーター化できないため、クエリーごとにライブスキーマ(information_schema、SQLite の場合はPRAGMA table_info)と照合して検証します。スキーマに存在しないテーブル名/カラム名(インジェクションの試みなど)は、SQL に渡される前に拒否されます。MongoDB アダプターは別のリスク(SQL ではなく「オペレーターインジェクション」)を防ぎます。詳しくは最近の変更をご覧ください。
MCP ツール
ゲートウェイは、常に以下の 5 つの読み取りツールを Claude に公開します。
| ツール | 説明 |
|---|---|
query_table | テーブルの行をクエリーします(PII は自動的にマスキングされます) |
list_tables | アクセス可能なテーブルを一覧表示します(ロールの制限が適用されます) |
describe_table | テーブルのスキーマとマスキングポリシーを表示します |
query_audit_log | ゲートウェイ自身の監査履歴をクエリーします(テーブル/ツール/操作/deniedOnly/since でフィルター可能)。メモリ内に保持され、audit.bufferSize が上限です。プロセスの再起動時にリセットされます |
gateway_status | 有効な設定、ロール、レート制限の状態を表示します |
writesEnabled: true の場合(書き込みのサポートを参照)、さらに 3 つの書き込みツールが追加されます。
| ツール | 説明 |
|---|---|
insert_row | 新しい行を挿入します |
update_row | フィルターに一致する行を更新します(空のフィルターは拒否されます) |
delete_row | フィルターに一致する行を削除します(空のフィルターは拒否されます) |
設定
createServer({
// PII field rules (the first match applies)
fieldRules: [
{ field: "tcKimlik", strategy: "redact" }, // [REDACTED]
{ field: "iban", strategy: "mask" }, // TR32***890
{ field: "email", strategy: "mask" }, // ah***@example.com
{ field: "passwordHash", strategy: "redact" },
{ field: "*Token*", strategy: "redact" }, // glob pattern
],
// Table access rules
tableRules: [
{ table: "audit_logs", access: "deny" },
{ table: "users", access: "allow", maxRows: 25 },
// write: if unspecified, that table has no write permission at all (off by default)
{ table: "orders", access: "allow", write: { insert: true, update: true, delete: false } },
],
// Turn on the write tools (insert_row/update_row/delete_row) — false by default.
// While false, these tools are never visible to Claude.
writesEnabled: true,
// How many rows update_row/delete_row may affect via one filter.
// If exceeded, the operation is rejected before touching the database ("narrow your filter").
maxAffectedRowsPerWrite: 10,
// Default max rows
defaultMaxRows: 50,
// Rate limiting
rateLimit: {
enabled: true,
windowMs: 60_000, // 1 minute
maxRequests: 100, // global limit
maxRequestsPerTable: 20, // per table
},
// Audit log
audit: {
enabled: true,
sink: "file", // "console" | "file" | "http"
filePath: "./audit.jsonl",
// webhookUrl: "https://..." (for sink: "http")
bufferSize: 200, // size of the in-memory history the `query_audit_log` tool reads
},
// Roles
roles: [
{
name: "ai-agent",
allowTables: ["products", "orders"], // only these tables
maxRows: 10,
// If a role doesn't define write (undefined), write is COMPLETELY off for that role,
// even if the table allows it. To permit writes, state it explicitly on the role too:
write: { insert: true, update: true, delete: false },
},
{
name: "analyst",
denyTables: ["audit_logs"], // this table is blocked
fieldRules: [
{ field: "email", strategy: "allow" }, // email unmasked
],
// write not defined → analyst can write nothing
},
],
// Active role (can also be set via the GATEWAY_ROLE env var)
activeRole: "ai-agent",
});
マスキング戦略
| 戦略 | 説明 | 例 |
|---|---|---|
redact | フィールド全体を削除します | [REDACTED] |
mask | 値の中央部分をアスタリスクで置き換えます | ah***@example.com / 530***67 |
hash | SHA-256(先頭16文字) | a665a45920422f9d |
allow | 変更せずにそのまま通します | [email protected] |
Glob パターンに対応しています:*Password*、*Token*、*Secret*
テキスト列内の PII(piiScan)
フィールドルールは列名に基づいて適用されるため、自由記述のテキスト列(notes、description)にメールアドレス、TC kimlik、API キーが含まれることがあります。デフォルトでオフの piiScan は、フィールドルールが適用されないすべてのテキストフィールドで、値に基づいてこれらをマスキングします。ネストされたオブジェクトや配列も対象です。allow ルールを設定すると、そのフィールドでは無効になります。preset / enable / disable で検出器を選択します。セキュリティプロキシと同じプリセットを使用できます:ALL(デフォルト)、KVKK、IDENTITY、IDENTIFIERS、SECRETS。
createServer({ piiScan: { enabled: true, preset: "KVKK", disable: ["address"] } }, adapter);
CLI からは、GATEWAY_PII_SCAN=true(デフォルトのすべての検出器)または GATEWAY_PII_SCAN=KVKK(プリセット)を指定します。不明なプリセット名または検出器名を指定すると、起動時に失敗します。
piiScan.blockPatterns と piiScan.allowPatterns を使うと、セキュリティプロキシと同様に独自のパターンを追加できます。block は ID を <CATEGORY_n> としてマスキングし、allow は検出された値のテキスト全体が一致する場合にそのまま通します。block パターンが100 msの制限時間を超えると、マスキングされていない可能性のある行を返さず、クエリが失敗します。
createServer({ piiScan: { enabled: true, blockPatterns: [{ pattern: "CL-\\d{6}", category: "CLIENT_NO" }], allowPatterns: ["destek@acme\\.com\\.tr"] } }, adapter);
ロールベースアクセス制御(RBAC)
ロールはサーバーの起動時に、GATEWAY_ROLE 環境変数または config.activeRole を使って設定します。
Claude Desktop の各プロファイルまたはデプロイメントは、異なるロールで実行できます。
GATEWAY_ROLE=analyst node dist/cli.js
ルールの優先順位(高い順):
- グローバル
tableRulesの deny - ロールの
denyTables - ロールの
allowTables(ホワイトリスト。設定されている場合、テーブルはこのリストに含まれている必要があります) - ロールの
fieldRules→ グローバルfieldRules
書き込みサポート(書き込み/挿入/更新/削除)
ゲートウェイはデフォルトで完全な読み取り専用です。LLM にデータの変更を許可するには、いくつかのゲートを意図的に解除する必要があります。
writesEnabled: true— グローバルなキルスイッチです。false(デフォルト)の場合、insert_row/update_row/delete_rowは Claude に一切表示されません。- テーブル権限 —
tableRules[].write.{insert,update,delete}— テーブルごとに設定します。すべてのテーブルでデフォルトはオフです。 - ロール権限(ロールが有効な場合)—
roles[].write.{insert,update,delete}。ロールでwriteが一度も定義されていない(未定義)場合、そのロールでは書き込みが完全にオフになります。テーブルで許可されていても同様です。書き込みを許可するには、テーブルとロールの両方で明示的にtrueを指定する必要があります(AND ロジック。マスキングルールで使われる「ロールによる上書き」ロジックより意図的に厳格です)。
この3つのゲートに加えて、無効化できない保護機能が2つあります。
- 保護フィールドのガード — LLM は
fieldRulesでredact/mask/hashに指定されたフィールド(例:tcKimlik、passwordHash)に値を書き込めません。insert_row/update_rowのdataにそのようなフィールドが含まれている場合、リクエスト全体が拒否されます。 maxAffectedRowsPerWrite—update_row/delete_rowの実行前に、まずフィルターを読み取りクエリとして試します。該当する行数がこの上限(デフォルトは10)を超える場合、何も変更する前に操作が拒否されます。update_row/delete_rowは空のフィルターも常に拒否します。このゲートウェイを通して「テーブル全体を更新/削除」することはできません。
すべての書き込み試行(許可・拒否を問わず)は監査ログに記録されます。ログには書き込まれたフィールドのみが記録され、data 自体は記録されません(監査ログ自体が PII の漏えい箇所になることはありません)。
createServer({
writesEnabled: true,
maxAffectedRowsPerWrite: 10,
tableRules: [
{ table: "orders", access: "allow", write: { insert: true, update: true, delete: false } },
],
roles: [
{ name: "ai-agent", allowTables: ["orders"], write: { insert: true, update: true, delete: false } },
],
activeRole: "ai-agent",
});
Prisma アダプター
PrismaClient を直接渡すと、テーブル名からモデルへのマッピングが自動的に行われます。
| クエリのテーブル | Prisma モデル |
|---|---|
"users" | prisma.user |
"audit_logs" | prisma.auditLog |
"orders" | prisma.order |
"orderItems" | prisma.orderItem |
開発
npm run dev # dev mode via tsx
npm run build # TypeScript compile
npm test # 195 unit tests
npm run test:watch # watch mode
npm run type-check # type-check only
ライセンス
MIT — GuardBee
フィードバック
ご質問やアイデア、誤検知がありましたら、GitHub Discussionsでスレッドを開始するか、issue を作成してください。GuardBee が役に立った場合は、リポジトリに ⭐ を付けていただくと、ほかの方にも見つけてもらいやすくなります。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。