mcpField
W
Warehouse Context

Warehouse Context

本地服务
github.com/AndreMuraro数据库05 天前更新

关于 Warehouse Context

Warehouse Context 是一款 MCP 服务,为分析和编码 Agent 提供受治理的数据仓库文档、血缘、时效信息及受限查询方式。它支持 DuckDB、Snowflake 和 Databricks,并以只读 SELECT、行数限制和个人信息保护约束查询。

主要功能

  1. 01列出并描述已记录的数据表
  2. 02追踪上游来源和下游使用方
  3. 03按预期检查数据表时效
  4. 04查看已屏蔽个人信息的样例行
  5. 05执行受限制的只读 SELECT 查询
  6. 06支持 DuckDB、Snowflake 和 Databricks

适用场景

  1. 01查找分析指标的受治理数据源
  2. 02检查数据表是否符合时效要求
  3. 03查看样例行而不暴露个人信息
  4. 04在只读限制下查询仓库数据

MCP 相关

MCP 服务提供六种只读工具,用于发现数据表、查看描述和血缘、检查时效、读取脱敏样例及执行受限制的 SQL 查询。支持 stdio 和 Streamable HTTP 传输。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"andremuraro-warehouse-context": {
"command": "uvx",
"args": [
"warehouse-context-mcp"
]
}
}
}
启动命令uvx warehouse-context-mcp

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

安装包
pypiwarehouse-context-mcp0.5.1

工具

6

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

此工具无需参数。

详细介绍

warehouse-context-mcp

一个 MCP 服务,为 AI Agent 提供可信且受治理的数据仓库上下文:每张表的含义、来源、数据新鲜度,以及一种无法写入、无法失控运行、也无法泄露个人数据的查询方式。

编码和分析 Agent 擅长编写 SQL,却不擅长判断该信任哪张表。仅凭架构信息,它们无法知道 fct_voyage_economics 是计算 TCE 的受治理数据源、stg_voyages 是暂存表、contact_email 属于个人数据,也无法知道某张表已经两天没有更新。这个服务让 Agent 只需调用一次工具即可获取这些上下文,并为其他操作设置防护措施。

工具

工具Agent 可获取的信息
list_tables每张表及其文档记录的用途和负责人
describe_table列、类型、说明、PII 标记、粒度、行数、未记录的列
table_lineage上游来源和下游使用者,避免循环并限制深度
table_freshness最近更新时间、数据年龄,以及是否符合文档记录的预期
sample_rows若干示例行,PII 已脱敏
run_query一条只读 SELECT 查询,限制返回行数,并保护 PII

后端

后端状态读取的原生上下文只读连接层
DuckDBv0.1无(仅 YAML 目录)以 read_only 模式打开文件
Snowflakev0.2表和列注释、pii 对象标签仅允许 SELECT 的角色(演示脚本中的 WCM_READER)
Databricksv0.2Unity Catalog 注释、pii 列标签仅获得 USE 和 SELECT 授权的主体

数据仓库中存储的注释和标签会与经过整理的 YAML 目录合并:经过整理的值优先,原生值用于补充缺失信息,任一来源标记的 PII 标记都会保留。

防护措施

Agent 发送的每条查询都视为攻击者编写的,因为 Agent 可能会被所读取的内容注入提示词。防护分为相互独立的多个层面,每个层面都单独测试:

  1. 查询采用允许列表策略。 使用 sqlglot 解析 SQL,且查询必须恰好是一个 SELECT,只能由经过审核的结构和函数构成。其他任何内容都会被拒绝,无需事先逐一预料:表函数、LATERAL、SUMMARIZE、递归 CTE,以及所有供应商函数,例如 SYSTEM$…、READ_FILES、SECRET、HTTP_REQUEST 或 GETENV。
  2. 根据真实架构解析。 * 会展开,且每个列都必须解析为已知表中的真实列,包括通过别名、CTE 和子查询解析;将整行用作值也会被拒绝。
  3. 在 SQL 内屏蔽 PII。 查询发出前,任何选择列表中的 PII 列都会变成 '***',因此其值永远不会离开数据仓库。可以对其计数(COUNT(DISTINCT email)),但不允许基于它筛选、排序、分组或计算,因此无法通过一次次测试猜出其值。
  4. 锁定连接权限。 DuckDB 以只读模式打开,并禁用外部文件和网络访问,同时锁定其配置。Snowflake 使用仅允许 SELECT 的角色,并移除次要角色;管理员角色会被拒绝。Databricks 使用仅获授 USE 和 SELECT 权限的主体。
  5. 限制执行和结果。 每条查询都有行数上限、超时限制、单个值的大小上限和总字节数上限。对于包含 PII 的表,会隐藏数据仓库错误消息,因为其中可能包含具体值。

**范围:**仅限配置架构中的表;表名按照对应方言自身的大小写规则进行比较,实际执行的 SQL 中每个表都使用完全限定名。

数据仓库中存储的 PII 标签(Snowflake 标签、Unity Catalog 列标签)会与整理后的目录合并,且启动时必须可读取(否则拒绝启动),并每 10 分钟刷新一次。对于生产数据,还应使用数据仓库原生的屏蔽功能(屏蔽策略或列屏蔽):服务端屏蔽是纵深防御的一环。

独立审查中用于攻破早期版本的查询位于 tests/attacks/,每次提交都会运行。请参阅威胁模型、ADR 0004 和 SECURITY.md。

快速开始

无需克隆即可试用(需要 uv);--demo 会启动随附的完全合成的运输数据仓库,并在首次运行时构建:

uvx warehouse-context-mcp --demo

也可通过 PyPI、容器镜像(ghcr.io/andremuraro/warehouse-context-mcp)以及 MCP Registry 获取,注册名称为 io.github.AndreMuraro/warehouse-context-mcp。每个版本都附带构建来源证明;请参阅 SECURITY.md。

在 MCP 客户端中使用

克隆仓库后即可直接使用:.mcp.json(Claude Code)、.vscode/mcp.json(VS Code)和 .codex/config.toml(Codex)都会启动演示服务。每个客户端都会在信任项目的服务前征求确认。

若要改为在所有客户端中添加:

客户端命令或配置
Claude Codeclaude mcp add --scope user warehouse -- uvx warehouse-context-mcp --demo
Claude Desktop在 mcpServers 下的 claude_desktop_config.json 中添加:"warehouse": {"command": "uvx", "args": ["warehouse-context-mcp", "--demo"]}
VS Code在 servers 下的用户级 mcp.json 中添加:"warehouse": {"type": "stdio", "command": "uvx", "args": ["warehouse-context-mcp", "--demo"]}
Codexcodex mcp add warehouse -- uvx warehouse-context-mcp --demo
任意客户端,通过 HTTP运行 docker compose up,然后将客户端指向 http://127.0.0.1:8000/mcp
Claude Code 插件和 Agent 技能

该代码库也是 Claude Code 插件市场。该插件打包了服务和一个 warehouse-context 技能,用于教会 Agent 工作流(查找、描述、检查新鲜度、查询、引用已执行的 SQL),以及如何回应拒绝请求:

/plugin install warehouse-context --marketplace AndreMuraro/warehouse-context-mcp

同一技能也已纳入项目:.claude/skills/(Claude Code)、.agents/skills/(Codex),且 VS Code 会读取这两个目录。或者,将 plugins/warehouse-context/skills/warehouse-context/ 复制到你的个人技能文件夹。

将 --demo 替换为 --backend snowflake 或 --backend databricks(并使用下方的设置),即可连接真实数据仓库。

然后提问:“上个季度,哪个船舶类别的平均 TCE 最佳?该表的数据是否新鲜?”

开发

需要 uv;如果缺少 Python 3.14,uv 会安装它。

uv sync --all-extras                            # creates .venv from uv.lock
uv run pytest
Snowflake 或 Databricks
uv sync --extra snowflake                # or --extra databricks, or --all-extras
cp .env.example .env                     # fill in your own values; .env is git-ignored
# run examples/snowflake_demo.sql (or databricks_demo.sql) once in the warehouse
uv run warehouse-context-mcp --backend snowflake --catalog path/to/catalog.yaml

设置来自 SNOWFLAKE_* / DATABRICKS_* 环境变量或 ./.env;实际环境变量优先,空值视为未设置。Snowflake 的密钥对身份验证:uv run scripts/snowflake_keypair.py 会输出需要执行的唯一一条 ALTER USER 语句。

共享 Snowflake CLI 连接

如果你使用 Snowflake CLI,可以让服务使用其中一个连接,而无需重复填写账户和登录信息:

# connections.toml (~/.snowflake/, or %USERPROFILE%\AppData\Local\snowflake\ on Windows)
[wcm]
account = "orgname-accountname"
user = "you"
authenticator = "SNOWFLAKE_JWT"
private_key_file = "~/.snowflake/snowflake_key.p8"
snow sql -c wcm -f examples/snowflake_demo.sql      # one-time demo setup, as an admin role
SNOWFLAKE_CONNECTION_NAME=wcm SNOWFLAKE_ROLE=WCM_READER uv run warehouse-context-mcp --backend snowflake

连接会提供账户和登录信息;你设置的任何 SNOWFLAKE_* 值都会覆盖连接中的值,而本软件包的默认值不会覆盖它们。连接后,服务会采用会话的实际数据库和架构,并拒绝管理角色(ACCOUNTADMIN、SYSADMIN、……),因此,用于管理工作的 CLI 连接无法绕过仅允许 SELECT 的角色限制。

实时测试会在真实数据仓库中运行演示预期;否则会跳过:

WCM_LIVE=snowflake uv run pytest -m live

在 Windows 上,相同命令可在 PowerShell 中运行;使用 $env:WCM_LIVE = "snowflake" 设置变量。

在 Databricks Free Edition 中,个人访问令牌属于工作区管理员,因此只读连接层在此不可用;查询策略仍然适用。在真实工作区中,请使用仅授予 USE 和 SELECT 权限的服务主体。

Python 版本
3.143.15
核心、DuckDB✓✓
Databricks 附加组件✓✓(lz4 和 thrift 从源代码构建)
Snowflake 附加组件✓尚不可用:没有 3.15 轮子,且源代码构建失败;该附加组件会通过环境标记跳过

HTTP 传输和容器

默认情况下,服务通过 stdio 使用 MCP:由客户端启动。使用 --transport http 时,服务会改为作为长期运行的 Streamable HTTP 服务运行,返回无状态 JSON 响应,并提供 /healthz 端点:

uv run warehouse-context-mcp --demo --transport http --port 8000
claude mcp add --transport http warehouse http://127.0.0.1:8000/mcp

HTTP 传输没有身份验证。即使绑定到所有接口,DNS 重绑定防护仍会保持启用:只会处理 Host 标头中名称为 localhost 或通过 --allowed-host 传入的请求。请将其发布到 loopback,或在前面部署身份验证代理。

Docker
docker compose up --build                        # demo warehouse at http://127.0.0.1:8000/mcp
docker run --rm -i warehouse-context-mcp:local   # or stdio, for clients that launch a command

该镜像基于 uv.lock 构建,以非 root 用户身份运行,并包含所有后端以及合成演示数据仓库。Compose 使用只读文件系统、禁用所有 Linux 功能并启用 no-new-privileges 运行该镜像,且仅在 127.0.0.1 上发布端口。

要连接真实数据仓库,请填写 .env 并启动一个配置档。凭据会以机密文件的形式传入容器,存放在 /run/secrets 下,而非作为环境变量传入:

docker compose --profile snowflake up --build    # :8001, key-pair sign-in (no browser in a container)
docker compose --profile databricks up --build   # :8002, token from DATABRICKS_TOKEN
  • Snowflake 使用 SNOWFLAKE_ACCOUNT、SNOWFLAKE_USER 和 SNOWFLAKE_PRIVATE_KEY_PATH 指定的密钥文件;Snowflake CLI 连接名称仅为主机端提供便利。
  • **Linux 主机:**如果只有你自己能读取密钥文件,请以自己的用户身份运行:WCM_UID=$(id -u) WCM_GID=$(id -g) docker compose ...。
  • 版本标签会将镜像发布到 ghcr.io/andremuraro/warehouse-context-mcp。

CI 会构建镜像、检查 stdio 传输、启动 Compose 服务直至其健康就绪、通过 HTTP 调用一个工具、确认拒绝外部 Host 标头,并验证容器以非 root 用户身份运行且文件系统为只读。

目录

语义存放在 YAML 文件中,并像代码一样在 Git 中审核(演示项目的目录):

tables:
  fct_voyage_economics:
    description: Time-charter-equivalent economics per voyage.
    owner: freight-analytics
    grain: voyage_id
    upstream: [stg_voyages]
    freshness_column: computed_at
    expected_freshness_hours: 12
    columns:
      tce_usd_per_day: { description: TCE in USD per day. }

在生产环境中,它可以由 dbt 文档、Unity Catalog 注释或数据目录生成。

架构

src/warehouse_context_mcp/
├── demo/          the bundled synthetic warehouse and its catalog
├── domain/        catalog, result models, namespace, errors (no I/O beyond YAML)
├── guardrails/    QueryPolicy: parse, scope, PII rules, row limit; result masking
├── warehouses/    Warehouse protocol + DuckDB, Snowflake, Databricks adapters
├── service.py     WarehouseContext: combines the three; no MCP dependency
├── server.py      MCP transport: six read-only tools, stdio or Streamable HTTP
├── settings.py    pydantic-settings for connection config and secrets
└── cli.py         entry point

依赖关系由外向内:传输层了解服务层,服务层了解领域层、护栏和 Warehouse 协议,而领域层中的任何内容都不依赖 MCP 或任何驱动程序。

  • **端到端类型化。**工具结果是冻结的 pydantic 模型,因此 MCP 客户端能为每种输出接收 JSON schema。工具参数的限制(depth 为 1–5,max_rows ≤ 1000)会写入输入 schema。DB-API 驱动程序通过 Cursor[P] 协议访问,该协议针对驱动程序的 paramstyle 进行泛型化,因此将位置参数绑定到命名参数风格的驱动程序会导致类型错误。
  • **将错误作为数据处理。**护栏拒绝会以 {"ok": false, "error": ...} 的形式返回,供 Agent 修正查询;编程错误和未知表则会引发异常。
  • **与数据仓库无关的核心。**适配器只描述元数据的位置;数据获取、缓存、允许列表和目录组装均由 DbApiWarehouse 统一处理。

请参阅 docs/adr,了解护栏和工具链背后的决策。

开发

uv run ruff format          # format
uv run ruff check           # lint: every ruff rule, with a short documented ignore list
uv run ty check             # type check, strict rules
uv run pytest --cov         # tests with branch coverage

CI 会在 Python 3.14 和 3.15(Linux)以及 Python 3.14(Windows)上运行相同的检查,并构建和冒烟测试 wheel。

路线图

  • v0.1:DuckDB 适配器、目录、六个工具、三层护栏、测试、CI
  • v0.2:Snowflake 和 Databricks Unity Catalog 适配器、原生注释和 PII 标签、schema 范围限定
  • v0.3:Python 3.14+、uv、ruff 和 ty;分层软件包;类型化工具输入和输出;表名由策略限定
  • v0.4:Streamable HTTP 传输、强化的容器镜像和 Compose 配置、Snowflake CLI 连接、零配置 --demo、客户端配置、PyPI 和 MCP Registry 发布流水线
  • 从 dbt manifest.json 导入目录
  • 评估:回答 20 个分析师问题,分别比较启用和未启用服务端的情况,并按答案正确性和表选择评分
  • 按工具记录审计日志

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

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

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