关于 Postgres (read-only transactions)
postgres-mcp-safe 是面向 AI 工具的 Postgres MCP 服务,可查询数据库、读取结构并解释查询。它以数据库强制的只读事务和调用限制,替代已弃用的 server-postgres。
主要功能
- 01只读 SQL 查询
- 02浏览表与视图
- 03查看列、约束和索引
- 04解释查询计划
- 05限制超时、行数和字节数
适用场景
- 01安全地检查生产数据库
- 02查找表结构与索引信息
- 03分析查询执行计划
MCP 相关
它向 MCP 客户端提供 query、list_tables、describe_table 和 explain 工具,以及 schema 资源。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
postgres-mcp-safe
已弃用的 @modelcontextprotocol/server-postgres 的即插即用替代品,但它真正只读。
让 AI 工具(Claude、Cursor、Zed 等)查询 Postgres 数据库、读取其架构并解释查询。只需在 MCP 配置中替换包名,其他内容保持不变。
从 server-postgres 迁移
{
"mcpServers": {
"postgres": {
"command": "npx",
- "args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"]
+ "args": ["-y", "postgres-mcp-safe", "postgresql://localhost/mydb"]
}
}
}
Docker:docker run -i --rm ghcr.io/poudel0/postgres-mcp-safe postgresql://host.docker.internal:5432/mydb。
Linux、macOS 和 Windows 的二进制文件可在发布页面获取。
**有一点需要注意:**如果你的 URL 使用超级用户登录(例如 Docker 默认的 postgres 用户),每次调用都会被拒绝,除非你创建只读角色(推荐),或在 URL 前添加 --allow-superuser。超级用户可以绕过只读事务,因此我们不会声称它能保证只读。
旧服务的 query 工具和 postgres://.../<table>/schema 资源用法保持不变。小幅且有意的变更请参阅差异。
原因
旧服务的“只读”模式可以通过 COMMIT; DROP TABLE ... 绕过
(Datadog Security Labs,2025-08-21)。
上游已合并修复,但从未发布;该软件包已弃用,也没有官方继任者。
标志
标志必须放在 URL 之前。
| 标志 | 默认值 | |
|---|---|---|
--timeout | 30s | 每次调用的时间限制。 |
--max-rows | 1000 | 每次调用返回的行数。超出的行会被截断,并附带说明。 |
--max-bytes | 262144 | 每次调用返回的 JSON 字节数上限,也是单行的最大大小。 |
--allow-explain-analyze | 关闭 | 允许 explain 执行 EXPLAIN ANALYZE,这会执行查询。 |
--allow-superuser | 关闭 | 允许使用超级用户角色或其成员身份。此时无法保证只读。 |
每次调用都会建立一个新连接(这是安全模型的一部分)。通过 TLS 连接远程数据库时,这需要几次往返:在 50 ms 延迟下,每次调用约需 0.5 s。在 Postgres 17+ 上,可在 URL 中添加 sslnegotiation=direct,减少一次往返。
限制无法关闭;0 会报错。URL 也可以使用关键字 DSN(host=db dbname=app),并且会像 libpq 一样读取标准的 PG* 环境变量(PGPASSWORD 等)。
工具
| 工具 | 输入 | |
|---|---|---|
query | sql | 一条只读语句。返回 JSON 行数组。 |
list_tables | schema? | 包含架构和类型的表及视图。 |
describe_table | table、schema?(public) | 列、约束和索引。 |
explain | sql、analyze? | 查询计划。analyze 需要 --allow-explain-analyze。 |
如何强制实施只读
由 Postgres 强制实施,而不是由 SQL 解析器。每次调用都会:
- 打开一个全新连接(调用之间不会保留会话状态),并启动一个
READ ONLY事务。 - 将你的 SQL 作为单条协议级 Parse 消息发送。Postgres 会在此处拒绝多条语句,因此
COMMIT; ...会在执行任何操作前失败。 - 仅在 Postgres 确认语句会返回行时才执行。
COMMIT、SET、DO、COPY、CALL、PREPARE等 都会被拒绝,不会执行。 - 应用
statement_timeout、客户端截止时间,以及行数和字节数上限。 - 关闭连接,从而结束事务。
bypass suite 会针对真实数据库运行所有已知负载,并在每次运行后检查金丝雀表:
| 负载 | 结果 |
|---|---|
COMMIT; DROP SCHEMA public CASCADE; | 已拒绝:多条语句 |
COMMIT / SET TRANSACTION READ WRITE / DO $$...$$ / CALL p() | 已拒绝:不会返回行 |
COPY (SELECT 1) TO PROGRAM '...'(以超级用户身份) | 已拒绝:不会返回行 |
DELETE ... RETURNING * / WITH d AS (DELETE ...) SELECT ... | 只读事务错误 |
SELECT nextval('s') | 只读事务错误 |
SELECT set_config('transaction_read_only','off',true) | 错误 |
SELECT pg_sleep(600),即使在其后调用 set_config('statement_timeout','0') | 在 --timeout 时取消 |
SELECT pg_advisory_lock(1) | 调用结束时释放 |
SELECT generate_series(1,10000000) / repeat('x', 10000000) | 达到上限/被拒绝,内存占用保持有界 |
带有 ANALYZE SELECT ... 的 explain | 语法错误:无法夹带 ANALYZE |
发现绕过方式?请提交 issue。修复前,它会先成为一条测试用例。
同时使用只读角色
此服务会在事务级别让每次调用保持只读。有些操作不受事务限制,只有数据库角色才能阻止它们:
dblink_exec(...)会打开一个独立会话,该会话不是只读的。pg_terminate_backend(...)会终止其他连接。- 超级用户可以读取服务器文件(
pg_read_file、pg_ls_dir):只读会阻止写入,不会阻止读取。 - 即使在只读事务中,超级用户也可以使用
lo_export写入服务器文件。
因此,请使用仅具备读取权限的角色连接:
CREATE ROLE mcp_ro LOGIN PASSWORD '...';
GRANT pg_read_all_data TO mcp_ro; -- PG 14+; or GRANT SELECT on what it needs
ALTER ROLE mcp_ro SET default_transaction_read_only = on;
由于上述最后两项,除非传入 --allow-superuser,否则服务会拒绝超级用户角色及其成员。
与 server-postgres 的差异
- 工具调用中的错误会作为工具结果返回,并带有
isError: true、Postgres 消息和 SQLSTATE,以便模型修正 SQL。旧版服务返回的是 JSON-RPC 错误。 resources/read只会按列顺序显示public表的列。旧版会混入其他 schema 中同名表的列。- 资源 URI 中经过百分号编码的表名会被解码(旧版服务不会匹配它们)。
- 值采用 Postgres 的打印形式,并在类型明确时保留类型:布尔值、数字(包括
bigint和numeric)及json都是 JSON 值;其他所有值都是字符串,例如"2026-01-02 03:04:05+00"、"\\x0102"或"{x,y}"。NaN会表示为"NaN"(旧版服务返回null)。 - 不返回行的语句(
SET、DO、COPY等)会被拒绝。旧版服务会执行这些语句并返回[]。
开发
docker run -d --name pg-mcp-test -e POSTGRES_PASSWORD=postgres -p 127.0.0.1:5434:5432 postgres:17-alpine
export DATABASE_URL='postgresql://postgres:[email protected]:5434/postgres?sslmode=disable'
make test # all tests, including the bypass suite
make golden # re-record the old server's output (needs npx)
DATABASE_URL 必须是超级用户:测试装置会重置 public schema 并创建 mcp_ro 角色。请使用临时数据库。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。