mcpField
D
db-gateway

db-gateway

本地服务
github.com/GuardBee数据库11 天前更新

关于 db-gateway

db-gateway 是位于大模型与数据库之间的 MCP 服务安全层。它会屏蔽敏感字段、按角色控制表访问、限制请求频率并记录查询;适配器支持 Prisma、Postgres、MySQL、SQLite 和 MongoDB。

主要功能

  1. 01屏蔽或隐藏敏感字段
  2. 02按角色控制表和字段访问
  3. 03设置全局及单表速率限制
  4. 04记录并查询审计历史
  5. 05支持 Prisma、Postgres、MySQL、SQLite 和 MongoDB 适配器
  6. 06可选写入并执行权限检查

适用场景

  1. 01让大模型在 PII 屏蔽下查询数据
  2. 02按角色和数据表限制数据库访问
  3. 03查看查询历史和被拒操作
  4. 04为大模型启用受控数据库写入

MCP 相关

提供数据库读取工具,用于查询数据表、列出和描述表、查看网关状态及审计历史。启用写入后,还会提供插入、更新和删除工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"guardbee-db-gateway": {
"command": "npx",
"args": [
"-y",
"@guardbee/mcp-db-gateway"
]
}
}
}
启动命令npx -y @guardbee/mcp-db-gateway

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@guardbee/mcp-db-gateway0.6.2

工具

5

收录的工具列表 · 更新于 1 天前

参数类型必填说明
limitinteger否应用网关限制前要获取的最大行数(默认 50)
tablestring是要查询的表名
filterobject否键值筛选条件对,例如 { status: 'active' }

详细介绍

@guardbee/mcp-db-gateway

🇬🇧 英语 | 🇹🇷 土耳其语 | 🇨🇳 中文 | 🇯🇵 日语 | 🇰🇷 韩语 | 🇧🇷 葡萄牙语 | 🇪🇸 西班牙语 | 🇩🇪 德语

npm version npm downloads License: MIT Smithery

一个符合 KVKK / GDPR 要求的 MCP(模型上下文协议)服务——在大模型与数据库之间增加一道安全防护层。

Claude(或其他任何大模型)不会直接查询数据库,而是通过此网关进行查询。敏感字段会自动屏蔽,表访问权限由角色控制,每次查询都会写入审计日志。

默认情况下,遥测处于关闭状态。设置 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 webhook
  • 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 增长工作中的三个新增步骤:

1. query_audit_log 工具

此前,网关的审计日志是只写的——它会写入 console/file/http sink 之一,但 Claude 本身无法回看并询问“刚才发生了什么,哪些调用被拒绝了”。现在它可以了:

// Tool called from the Claude side:
query_audit_log({ table: "orders", deniedOnly: true, limit: 20 })
  • 工作原理: AuditLogger 新增了一个始终启用的内存环形缓冲区,它完全独立于已配置的 sink(audit.bufferSize,默认值为 200)。即使 sink 是 "http"(一种即发即弃的 webhook),也仍可通过此缓冲区查询历史记录。进程重启时缓冲区会重置,并且在 audit.enabled: false 时不会写入任何内容。
  • 筛选条件: table、tool(MCP 工具名称,例如 "delete_row")、operation(read/insert/update/delete)、deniedOnly(仅限被拒绝的调用)、since(ISO 8601 时间戳)、limit(默认值为 50,最大值为 200)。结果按时间从新到旧排列。
  • 顺带修复的一个实际 Bug: 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 前进行验证——这里使用 SQLite 的 PRAGMA table_info(table),而不是 information_schema。格式检查未通过(例如 users"; DROP TABLE users;--)或不在实时架构中的名称,会在任何查询到达 SQLite 之前被拒绝。
  • better-sqlite3 只是可选的 peerDependency——它未被添加到包自身的 devDependencies 中,因为它需要原生绑定;测试(与 pg/mysql 测试类似)使用符合 SqliteQueryable 接口的简单模拟对象编写,无需导入实际的包。
  • 插入时使用 lastInsertRowid,而不是 RETURNING: 由于 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 项测试)——集合列表、带筛选/无筛选查询、限制、三种操作符注入场景(以 $ 开头的键、带点号的键、操作符对象值)、插入/更新/删除。

快速开始

1. 通过 Smithery 一键连接

你可以通过 Smithery 一键将其添加到 Claude Desktop。

2. 通过全局安装连接到 Claude Desktop
npm install -g @guardbee/mcp-db-gateway

将以下内容添加到 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS):

{
  "mcpServers": {
    "guardbee-db-gateway": {
      "command": "guardbee-gateway",
      "env": {
        "DATABASE_URL": "postgresql://user:pass@localhost:5432/mydb"
      }
    }
  }
}

Windows: %APPDATA%\Claude\claude_desktop_config.json Linux: ~/.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 工具

网关始终会向 Claude 暴露以下 5 个只读工具:

工具描述
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
hashSHA-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

规则优先级(从高到低):

  1. 全局 tableRules 拒绝规则
  2. 角色 denyTables
  3. 角色 allowTables(白名单——若已设置,表必须在此列表中)
  4. 角色 fieldRules → 全局 fieldRules

写入支持(写入/插入/更新/删除)

默认情况下,网关为完全只读。允许大模型修改数据需要主动解锁几道限制:

  1. writesEnabled: true —— 全局紧急开关。设为 false(默认值)时,Claude 永远看不到 insert_row/update_row/delete_row。
  2. 表权限 —— tableRules[].write.{insert,update,delete} —— 每张表单独设置,默认全部关闭。
  3. 角色权限(启用角色时)—— roles[].write.{insert,update,delete}。若角色从未定义 write(未定义),则该角色完全不能写入,即使表允许写入也不例外。要允许写入,表和角色都必须明确设为 true(AND 逻辑——比脱敏规则使用的“角色覆盖”逻辑更严格)。

除这三道限制外,还有两项无法禁用的保护:

  • 受保护字段防护 —— 大模型永远不能向 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 讨论区中发起讨论,或提交问题。如果 GuardBee 对你有帮助,可以在代码仓库点个 ⭐,帮助其他人找到它。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。