关于 sql-steward
sql-steward 是面向需要治理数据库访问的团队的 MCP SQL 网关。它依据运维方定义的语义层编译只读查询,并在读取前拦截带有 PII 标记的字段。
主要功能
- 01实体、记录和指标的类型化工具
- 02仅编译 SELECT 查询
- 03读取前执行 PII 策略检查
- 04防篡改审计验证
- 05支持 SQL Server、Postgres 和 SQLite
适用场景
- 01向 AI Agent 提供获准的指标
- 02让 Agent 读取记录而不接触原始 SQL
- 03阻止读取受限的 PII 字段
- 04验证 Agent 调用的审计链
MCP 相关
它向 MCP 客户端提供类型化数据库工具,不提供原始 SQL 执行工具。查询由配置的语义层编译,策略禁止的 PII 会在执行前被拒绝。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
9收录的工具列表 · 更新于 2 周前
此工具无需参数。
详细介绍
重要
此仓库已迁移至 Governed Agent Stack monorepo。
当前开发工作已转移至
packages/sql-steward/。 此仓库已归档并设为只读。这里保留了完整的提交历史; 新功能、问题和版本发布均在 monorepo 中进行。
sql-steward
属于 Governed Agent Stack 的一部分:为可连接真实数据库并可审计的 AI Agent 提供免费、可本地部署的构建模块。
通过 Model Context Protocol 向 AI Agent 提供受治理的 SQL 网关。Agent 永远不会获得连接字符串,也不会编写 SQL。它会调用类型化工具;sql-steward 根据你控制的语义层编译每个查询,在查询运行前拒绝涉及受限 PII 的请求,并返回行数据。SQL Server、Postgres 和 SQLite 使用同一套工具。
大多数 SQL MCP 服务会向模型提供 run_sql 工具,然后试图拦截执行过程中出现的恶意查询。sql-steward 则移除了这个工具。提示词无法通过任何路径让你的数据库执行原始 SQL,因为 Agent 唯一能做的就是指定实体或指标,并从你编写的允许列表中进行选择。
实时观看它保护数据库。受治理与不受治理的演示会将同一个请求分别交给一个简单的 run_sql Agent(它会泄露客户 PII 并清空一张表)和 sql-steward(它会在编译时拒绝该请求)。
三项保证
- **从设计上只读。**这里没有
run_sql、query或execute工具。编译器只能构建SELECT,因此写入操作不是被拦截,而是根本无法表达。 - **检索前拒绝 PII。**每个字段都可以附带 PII 标签。如果请求涉及你的策略所禁止的类别,sql-steward 会在编译或运行任何 SQL 之前,以结构化原因拒绝请求。
- **可审计。**每次调用、拒绝和错误都可以通过 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 是 Agent 与你的数据库之间的完整契约。请像审查代码一样审查它。
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。拼错指标或字段时,错误会列出实际存在的名称及最接近的拼写,因此 Agent 可以在一轮内自行纠正,无需再发起一次发现调用。
向 Agent 暴露的工具
| 工具 | 用途 |
|---|---|
list_entities() | 可读取的内容,以及可用的指标 |
describe_entity(entity) | 字段、类型和 PII 标签(会标出被阻止的字段) |
list_metrics() | 指标及每个指标允许使用的维度/筛选条件 |
get_records(entity, fields, filters, order_by, limit) | 从一个实体读取行 |
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。值始终作为绑定参数传入,绝不会内联。
将其接入 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)。使用 extras 安装相应的驱动: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 区块,Agent 就会获得一个 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]
查询文本在本地生成嵌入(将 SQL_STEWARD_EMBED_URL 设置为本地 Ollama 端点,这样数据就不会离开内部环境),并使用 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是配置项,不是经过验证的身份;sql-steward 会信任传入的角色是正确的。 - 它不会解析每位用户的权限。如果不同用户应当看到不同数据,调用方必须将用户映射到角色,并在调用前设置该角色。角色检查负责执行策略,而不负责判定你的身份。
- 它不会保护传输安全。通过 stdio 在本地主机上运行,或将它置于能够终止 TLS 的组件之后。
- 它不会管理密钥。它从环境中读取
SQL_STEWARD_DB_URL和审计密钥AGENT_BLACKBOX_KEY;请从密钥存储中提供这些值,而不要将其写入受版本控制的文件。
你需要提供什么。 sql-steward 专为部署在可信调用方之后而设计,无论调用方是同一台机器上的 MCP 主机,还是已经完成用户身份验证的网关。
- 从可信进程调用它:由你控制的 MCP 主机通过 stdio 启动的子进程,或由网关后的服务;该网关会验证请求,并在调用前将已验证的身份映射到角色。
- 为它提供权限遵循最小权限原则的只读数据库账户。编译器无法表示写入操作,但只读授权可作为纵深防御;如果某个依赖项出错,它也能将影响范围控制在合理限度内。
- 将数据库和任何本地嵌入端点留在专用网络中。不要将服务暴露给不可信的调用方。
- 将连接字符串和审计密钥视为机密信息。
它针对的威胁。 该设计假定模型能力强且可能已遭入侵,而操作者可信。它会限制 Agent 对数据库的操作范围。它不能取代你的身份提供商,也不适合单独暴露在不可信网络中。从你信任的主机或网关后面连接到真实数据库,模型所能做的就只有这三项保证所允许的范围。
有何不同
典型的 SQL MCP 会验证模型编写的任意 SQL(黑名单:拦截不安全的内容)。sql-steward 则根据你编写的定义编译 SQL(允许列表:只允许访问定义中描述的内容)。只读和 PII 保证由设计本身实现,而非通过检查来保证;并且三个引擎上的查询接口保持一致。
与语义层对比(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。 被屏蔽的字段会在编译时对所有调用方拒绝,因此模型无法读取策略禁止的内容,甚至不能据此进行推理。语义层会管理你可以查询哪些指标,但它们并非旨在保证带标签的列永远不会到达模型。
- 为整个 Agent 提供一份防篡改审计记录,而不只是 SQL。 在组合式技术栈中,同一关卡模式还会用于 KQL、文档检索和 Agent 记忆,并由同一份哈希链式账本记录。数据仓库语义层管理数据仓库,但不会管理 Agent 的其他工具。
简而言之:语义层让平台上的查询安全;sql-steward 则让 Agent 在你的基础设施上安全运行,并覆盖它能访问的所有界面。
这并不意味着要与世隔绝。整个行业正逐渐采用 Apache Ossie(Open Semantic Interchange 格式,目前由 ASF 孵化,源自 Snowflake、dbt 和 Salesforce 工作组),将其作为在工具间迁移语义模型的中立方式,而 sql-steward 支持该格式:
sql-steward export semantic.yaml --out model.osi.yaml
实体、联接和指标分别映射到 OSI 数据集、关系和指标。
OSI 目前还没有治理方面的词汇,因此让语义层成为契约而非目录的部分,包括 PII 标签、策略屏蔽、指标允许列表和检查项,都会放在
custom_extensions 下,使用
vendor_name: SQL_STEWARD;无法表示的内容会作为说明报告到 stderr,而不是被悄然丢弃。输出可通过 Ossie
自带的验证器,因此为 sql-steward 编写的语义层可以交给任何能够读取该标准的工具使用。
扩展到实际规模的架构
语义层刻意采用手动编写,以便像代码一样阅读和审查。这对于几十张表来说是恰当的默认方式,对于几千张表来说则不合适:没人会为包含 10,000 张表的 ERP 手写语义层,而且在一次 list_entities 调用中返回整个语义层也不适合 Agent 的上下文。扩展方式如下:
-
先生成初稿,再进行审查。
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 -
范围比规模更重要。 受治理的语义层应该只暴露 Agent 实际需要的少数实体,而不是整个数据库。即使架构包含 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 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。