mcpField
W
Warehouse MCP

Warehouse MCP

本地服务
github.com/tantn89数据库01 周前更新

关于 Warehouse MCP

Warehouse MCP 是供 Agent 查询 DuckDB、Postgres 和 BigQuery 的只读 MCP 服务,结合业务指标查询、角色行策略、源端假名化、SQL 防护与审计日志。

主要功能

  1. 01只读访问 DuckDB、Postgres 和 BigQuery
  2. 02业务指标查询与受控 SQL
  3. 03基于角色的行过滤
  4. 04源端个人信息假名化
  5. 05扫描上限与结果脱敏
  6. 06不记录数据值的审计日志

适用场景

  1. 01查询数仓数据以回答业务问题
  2. 02向合作方提供行级过滤数据
  3. 03分析个人数据指标而不暴露姓名
  4. 04限制高成本查询并审查访问记录

MCP 相关

向 MCP 客户端提供四种只读工具:列出和描述数据集、查询指标及执行受控 SQL。支持 stdio 和带有角色映射的 bearer key HTTP 访问。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"tantn89-warehouse": {
"command": "uvx",
"args": [
"warehouse-mcp"
],
"env": {
"WAREHOUSE_MCP_POSTGRES_DSN": "<WAREHOUSE_MCP_POSTGRES_DSN>",
"WAREHOUSE_MCP_PII_SALT": "<WAREHOUSE_MCP_PII_SALT>",
"WAREHOUSE_MCP_AUDIT_LOG": "<WAREHOUSE_MCP_AUDIT_LOG>"
}
}
}
}
启动命令uvx warehouse-mcp
需要配置的环境变量
WAREHOUSE_MCP_POSTGRES_DSN密钥Postgres connection string of a read-only role (Postgres configs only).
WAREHOUSE_MCP_PII_SALT密钥Fixed salt for stable pseudonyms across restarts (16-128 letters or digits).
WAREHOUSE_MCP_AUDIT_LOGPath of the JSONL audit log; stderr when unset.

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

安装包
pypiwarehouse-mcp0.1.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

warehouse-mcp

让 AI Agent 使用你的数据仓库,但不把数据仓库交给它们。

一个 MCP 服务,让 Claude、Cursor 或任何 MCP 客户端通过受管控的只读层查询 DuckDB、Postgres 或 BigQuery:

  • 语义模型,让 Agent 能用业务术语提问;
  • SQL 防护机制,Agent 无法诱使它执行写入、读取文件或越权操作;
  • 按角色设置的行策略;
  • 个人数据假名化;
  • 审计日志;
  • 成本上限。

以下每项声明都有测试或实测结果佐证。

文章:一个别名绕过了我的 SQL 防护机制:对用于数据仓库访问的 MCP 服务进行红队测试

ci pypi mcp registry python mcp license

检查项结果证据
104 次绕过尝试(数据外泄、行过滤绕过、PII 探测、文件和系统访问、语句夹带、资源滥用)DuckDB 和 Postgres 均无数据泄漏tests/test_red_team.py,在 CI 中运行
在三个引擎上运行相同的 15 条查询DuckDB、Postgres 和 BigQuery 的结果完全一致一致性测试、BigQuery 运行结果
绕过 SQL 防护机制执行写入引擎自身拒绝:先由只读事务拦截,再由授权规则拦截test_postgres_parity.py
Agent 在多 TB 表上执行了不谨慎的查询计费前即被拒绝:“将扫描 4.65 GB,超过 1.00 GB 上限”BigQuery 运行结果
Claude Haiku 5.5 Agent 通过 MCP 作答,并根据 SQL 真实结果评分(26 个案例,每个案例试验 3 次)78/78 答对,包括 6 个治理案例,每个问题 $0.0016,p95 为 6.3 秒。由 regressgate 执行门禁evals/cases.jsonl

一行命令即可试用

捆绑的演示程序通过本地 DuckDB 文件,提供约 10 万条实时 Wikipedia 编辑记录,这些数据由 realtime-lakehouse 捕获。 无需密钥。

{
  "mcpServers": {
    "warehouse": { "command": "uvx", "args": ["warehouse-mcp", "--demo"] }
  }
}

将其放入 Claude Desktop 的配置中,或者运行 claude mcp add warehouse -- uvx warehouse-mcp --demo。 然后询问 “哪些 wiki 的机器人活动最多?每个 wiki 有多少位不同的编辑者?”

以下是 Agent 实际看到的内容,摘自演示中的真实工具调用:

warehouse_query_metrics(dataset="edits", metrics=["edits","editors","bot_share"], dimensions=["wiki"])
  wiki          edits   editors  bot_share
  enwiktionary  41594   46       0.994
  commonswiki   16053   224      0.849
  enwiki         9576   1401     0.489

warehouse_run_sql("SELECT editor, count(*) AS edits FROM edits GROUP BY editor ORDER BY edits DESC")
  pii_6b19c4a15ccf  41335        <- a pseudonym: counts and joins are exact, the name never leaves
  pii_6a8d5fd6c44b   9638

warehouse_run_sql("SELECT * FROM edits; DROP TABLE edits")
  Error: Send exactly one statement; multiple statements are not allowed.
warehouse_run_sql("SELECT pg_read_file('/etc/passwd') FROM edits")
  Error: Function pg_read_file() is not allowed. Use standard SQL functions (...)

工作原理

flowchart LR
    A[Agent] -->|MCP: stdio, or HTTP + bearer key| T[4 read-only tools]
    T --> R[Role<br/>from the key]
    R --> G[SQL guard<br/>sqlglot, backend dialect]
    G -->|rewrite each dataset into| P[Policy subquery<br/>declared columns only<br/>salted pseudonyms<br/>role row filter]
    P --> B[(Backend safeguards<br/>DuckDB: read-only, no file access<br/>Postgres: read-only txn + grants<br/>BigQuery: dry run + byte cap)]
    B --> X[Cell cap + email/phone redaction]
    X --> L[Audit log<br/>no values, no salt]
    L --> A

在源头进行假名化,而不是在输出中处理。 防护层会在数据仓库内,将每个数据集引用重写为子查询,并用加盐哈希替换个人信息列。因此:

  • count(DISTINCT editor) 仍然准确;
  • 跨数据集使用假名进行联接仍然有效;
  • 类似 WHERE editor = 'Alice' 的探测查询不会匹配任何内容,因为比较操作针对的是哈希值;
  • 名称永远不会离开数据仓库。

在血缘分析后对输出进行掩码处理,可能会被别名、表达式或函数绕过。而在这里,原始列根本无法访问。

每一层的设计都确保即使前一层失效,也能发挥作用。 防护层是第一层:

  • 仅允许单条语句;
  • 仅允许 SELECT;
  • 仅允许已声明的数据集;
  • 函数允许列表;
  • 按作用域解析 CTE 引用,因此 WITH t AS (SELECT * FROM t) 无法访问真实表 t;
  • 限制 LIMIT 上限。

在此之后,每个引擎都经过独立锁定,测试也证明了即使绕过防护层,安全措施仍然有效。

这些工具:

工具用途
warehouse_list_datasets调用者角色可查询的内容,以及每个数据集的粒度和指标
warehouse_describe_dataset列、经过假名化的列、行策略和 3 个示例行
warehouse_query_metrics首选方式。 按维度和时间桶查询命名指标。SQL 以语法树构建,因此筛选值永远不会成为 SQL 的一部分
warehouse_run_sql执行一条受防护的 SELECT,用于回答指标无法表达的问题

红队发现的问题

对抗性测试套件在 SQL 防护层之外发现了三个真实漏洞。它们都已修复,并保留为回归测试:

  1. 超时后仍会受到 ReDoS 攻击。 电子邮件脱敏正则表达式存在二次回溯问题,repeat('x', 1000000) 生成的 1 MB 字符串会让服务停滞约 12 分钟。该操作在数据仓库超时之后运行,因此没有任何机制能阻止它。修复方案是限制正则表达式的重复次数,并在脱敏前截断单元格。
  2. 单个超大行绕过了结果大小上限。 修复方案是在行符合大小限制前,不断缩短最长的文本单元格。
  3. 假名可能被反向关联到名称。 编辑自己的 User: 页面时,会将一个假名与含有其名称的标题关联起来。在发现这一问题的快照中,有 5.7% 的编辑者因此被重新识别。修复方案是为用户页面标题添加条件式 PII(pii_when: "namespace IN (2, 3)"),并对编辑摘要进行假名化。

随后,另一个模型进行了独立审查,发现了测试套件漏掉的一个漏洞,这次问题出在防护层中:

  1. 别名可以将真实表伪装成 CTE。 在 WITH x AS (...) SELECT * FROM edits_raw x, x 中,防护层按别名匹配 CTE 引用,导致物理表绕过了策略重写。现在,CTE 引用会在各自作用域内按表名解析,并且会拒绝将真实表别名为可见的 CTE 名称。
  2. 引擎错误信息泄露了数据。 类似 Could not convert string '<value>' 的消息绕过了结果脱敏,并传给了 Agent 和审计日志。现在,错误消息中的带引号值会被移除,随后进行脱敏和截断。

在 BigQuery 上运行一致性测试用例时,又发现了一个问题。这是正确性错误,而不是数据泄露:针对 TIMESTAMP 列的时间字面量被转换为 DATETIME。现已修复。

配置你自己的数据仓库

extends: demo:wikipedia            # or write datasets/roles from scratch
connection: {kind: postgres, dsn_env: WAREHOUSE_MCP_POSTGRES_DSN}

roles:
  - {name: analyst, datasets: "*", api_key_env: KEY_ANALYST}
  - name: enwiki_partner             # an external partner sees one wiki only
    datasets: [edits, edits_per_minute]
    row_filters: {edits: "wiki = 'enwiki'", edits_per_minute: "wiki = 'enwiki'"}
    api_key_env: KEY_PARTNER
  - {name: trust_and_safety, datasets: "*", pii_clearance: true, api_key_env: KEY_TS}

数据集会声明其列、其中哪些列属于 pii 或 pii_when、哪些列属于 free_text,以及命名指标。未声明的列对 Agent 不存在。通过 HTTP 使用时(warehouse-mcp --config my.yaml --transport http),每个 bearer key 都会选择一个角色。密钥来自环境变量;配置文件不包含机密信息。

各后端的设置说明、Claude Desktop 配置片段和评估工作流见 docs/deployment-guide.md。有关在公司内部推广(发现、访问模型、分阶段推广、成功指标、事件运行手册),请参阅 docs/deployment-playbook.md。

开发

pip install -e ".[dev]"
pytest                                    # DuckDB; Postgres/BigQuery suites skip without a DSN
docker compose up -d && python scripts/load_snapshot.py --target postgres
WAREHOUSE_MCP_POSTGRES_DSN=postgresql://mcp_reader:[email protected]:55432/warehouse pytest

架构和威胁模型 · 代码库概览 · 路线图

限制

  • 电话号码脱敏适用于标记为 free_text 的列。像 comment AS c 这样的别名 会失去电话脱敏功能;它仍会进行电子邮件脱敏,该功能适用于所有位置。
  • HTTP 使用静态 bearer 密钥和纯 HTTP。请在其前面配置 TLS。OAuth 资源服务器 模式已列入路线图。
  • Snowflake 已列入路线图。

数据

演示数据来自 Wikimedia 的公开近期更改流,采用 CC BY-SA 4.0 许可。 代码采用 MIT 许可。

评论

支持 Markdown

第一次接触 MCP?

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

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