
Postgres (read-only transactions)
io.github.Poudel0由 GitHub 账号 Poudel0 发布v0.1.3更新于 Nov 3, 2026
Drop-in replacement for @modelcontextprotocol/server-postgres that is actually read-only.
概览
Postgres (read-only transactions) 的本地 MCP 服务;无需登录;STDIO。
暂无 AI 概览:以下信息来自注册中心条目和服务本身。
安装
在 SourceWeft 中
- 打开 控制台中的 Postgres (read-only transactions),将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
postgres-mcp-safe
A drop-in replacement for the deprecated @modelcontextprotocol/server-postgres, but actually read-only.
Lets AI tools (Claude, Cursor, Zed, ...) query a Postgres database, read its schema and explain queries. Swap the package name in your MCP config and keep everything else.
[Postgres (read-only transactions) MCP server]
Migrating from server-postgres
Docker: docker run -i --rm ghcr.io/poudel0/postgres-mcp-safe postgresql://host.docker.internal:5432/mydb.
Binaries for Linux, macOS and Windows are on the releases page.
One catch: if your URL logs in as a superuser (like Docker's default postgres user), every call is refused
until you either create a read-only role (recommended) or add --allow-superuser
before the URL. A superuser can get around a read-only transaction, so we won't pretend otherwise.
The old server's query tool and postgres://.../<table>/schema resources work the same. See
Differences for the small, deliberate changes.
Why
The old server's "read-only" mode can be broken with COMMIT; DROP TABLE ...
(Datadog Security Labs, 2025-08-21).
A fix was merged upstream but never published, and the package is deprecated with no official successor.
Flags
Flags go before the URL.
Each call opens a fresh connection (that's part of the safety model). Against a remote database over TLS that costs a
few round trips: about 0.5 s per call at 50 ms latency. On Postgres 17+ you can save one round trip by adding
sslnegotiation=direct to the URL.
Limits can't be turned off; 0 is an error. The URL can also be a keyword DSN (host=db dbname=app), and the
standard PG* environment variables (PGPASSWORD, ...) are read as libpq would.
Tools
How read-only is enforced
Postgres enforces it, not a SQL parser. Every call:
- Opens a fresh connection (no session state survives a call) and starts a
READ ONLYtransaction. - Sends your SQL as a single protocol-level Parse message. Postgres rejects more than one statement there, so
COMMIT; ...fails before anything runs. - Runs it only if Postgres says it returns rows.
COMMIT,SET,DO,COPY,CALL,PREPAREand friends are rejected without running. - Applies
statement_timeout, a client deadline, and row and byte caps. - Closes the connection, which ends the transaction.
The bypass suite runs every known payload against a real database and checks a canary table after each one:
Found a bypass? Open an issue. It becomes a test row before the fix.
Use a read-only role too
This server makes each call read-only at the transaction level. Some things are out of a transaction's reach, and only the database role stops them:
dblink_exec(...)opens a separate session that isn't read-only.pg_terminate_backend(...)kills other connections.- A superuser can read server files (
pg_read_file,pg_ls_dir): read-only stops writes, not reads. - A superuser can write server files with
lo_export, even inside a read-only transaction.
So connect as a role that can only read:
Because of the last two, the server refuses superuser roles (and members of them) unless you pass --allow-superuser.
Differences from server-postgres
- Errors in a tool call come back as a tool result with
isError: trueand the Postgres message and SQLSTATE, so the model can fix its SQL. The old server sent a JSON-RPC error. resources/readonly shows columns of thepublictable, in column order. The old one mixed in columns from same-named tables in other schemas.- Percent-encoded table names in resource URIs are decoded (the old server never matched them).
- Values are what Postgres prints, typed where it's clear: booleans, numbers (including
bigintandnumeric) andjsonare JSON values; everything else is a string such as"2026-01-02 03:04:05+00","\\x0102"or"{x,y}".NaNis"NaN"(the old server gavenull). - Statements that return no rows (
SET,DO,COPY, ...) are rejected. The old server ran them and returned[].
Development
DATABASE_URL must be a superuser: the fixture resets the public schema and creates the mcp_ro role. Use a
throwaway database.
来源:README.md,提交 b7e7ce5
工具
0版本历史
2- v0.1.3最新Nov 3, 2026
- v0.1.2Nov 1, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分
