Read-only PostgreSQL over MCP. Writes refused at the parsed SQL, plus a READ ONLY transaction.
MCPpedia last refreshed this data
io.github.Eszetael/postgres-mcp-hardened is an MCP server that read-only PostgreSQL over MCP. Writes refused at the parsed SQL, plus a READ ONLY transaction. Its tool list has not been published yet over stdio and http, requires no API key, and scores 89/100 on MCPpedia's security, maintenance and efficiency rubric.
Config is the same across clients — only the file and path differ.
{
"mcpServers": {
"postgres": {
"env": {
"DATABASE_URL": "postgres://readonly_user:YOUR_PASSWORD@localhost:5432/mydb"
},
"args": [
"--stdio"
],
"command": "postgres-mcp-hardened"
}
}
}Are you the author?
Add this badge to your README to show your security score and help users find safe servers.
The official Postgres MCP server was deprecated in 2024 and still gets ~440k downloads a month. Its entire defence is one database-level read-only transaction — and that alone does not stop every write. This is a maintained Rust replacement with defence in depth.
Run this in your terminal to verify the server starts. Then let us know if it worked — your result helps other developers.
npx -y 'postgres-mcp-hardened' 2>&1 | head -1 && echo "✓ Server started successfully"
After testing, let us know if it worked:
Five weighted categories — click any category to see the underlying evidence.
No known CVEs.
Checked postgres-mcp-hardened against OSV.dev.
Click any tool to inspect its schema.
Be the first to review
Have you used this server?
Share your experience — it helps other developers decide.
Sign in to write a review.
Others in data / finance
Manage Supabase projects — databases, auth, storage, and edge functions
🔥 Official Firecrawl MCP Server - Adds powerful web scraping and search to Cursor, Claude and any other LLM clients.
An official Qdrant Model Context Protocol (MCP) server implementation
DataForSEO API modelcontextprotocol server
MCP Security Weekly
Get CVE alerts and security updates for io.github.Eszetael/postgres-mcp-hardened and similar servers.
Start a conversation
Ask a question, share a tip, or report an issue.
Sign in to join the discussion.
🚧 Version 0.1.9 — a security release, and how it was found
Published: binaries for five platforms with checksums, Sigstore signatures and build provenance;
.mcpbbundles for one-click install; an image onghcr.iofor amd64 and arm64; a package on npm; and an entry in the official MCP registry.0.1.8 closes six bypasses that were present in 0.1.7, and none of them were found by us. They came from four independent reviewers reading a draft article about this project. Two days of our own adversarial work across every axis we could think of had come back mostly clean the day before. Passing the tests you thought to write is not the same as looking.
The one that matters most needs no privileges at all: with a column redacted, a join on it through
USINGanswered whether a given value was present, which is a complete equality oracle against the least-privilege reader this project tells you to configure. The others: a substring comparison that let a remote database pass as loopback and skip TLS; two routes to an oracle over the structure of a schema the caller was refused;X-Forwarded-Forread from the wrong end, so a header the client writes reset both rate limits; a memory bound that doubled as a rate-limit reset; and the cost guard failing open when it could not read a plan. Each was reproduced against a running server before being fixed, and each is inCHANGELOG.mdwith the query.One thing an existing unit test had been doing since it was written: asserting the vulnerable behaviour. It was green for exactly as long as the hole existed.
A resource limit is documented and not solved, in
THREAT_MODEL.md: 49 bytes of SQL make PostgreSQL fold a constant into 5.9 GB of backend memory during planning, and a five secondstatement_timeoutdoes not stop it. 0.1.8 refuses the obvious shapes; the general problem is upstream of anything this server can do.0.1.9 exists because the 0.1.8 fix had a one-word bypass:
chr(120)instead of'x'produced the same gigabyte plan, because the size estimate could not read a function call and gave up, and giving up meant allowing. It was caught within the hour by running the published build throughnpxfrom a clean container rather than trusting the local one. The rule now is the one PostgreSQL uses to decide whether to fold at all: is the expression constant.Everything here is 0.1.x because nobody outside this project has run it against their own data.
The official Postgres MCP server was deprecated in 2024 and still gets 437k downloads a month. Its entire defence is one database-level read-only transaction — and that alone does not stop every write. This is a maintained Rust replacement with defence in depth.
A drop-in Model Context Protocol server that lets an AI agent query PostgreSQL — read-only, enforced at the database level, with real SQL validation, timeouts, cost limits, OAuth 2.1, and an audit trail. Speaks Streamable HTTP and stdio, and negotiates the MCP revision: 2026-07-28 (current, and the default since upstream released it on 2026-08-03), 2025-11-25, and 2025-06-18 — what most shipping clients still speak today. A client asks for what it knows; it is not negotiated down.
The read-only guard has an offline mode. Hand it a statement and it says what it decided: no database, no configuration, nothing installed permanently.
npx postgres-mcp-hardened --validate "/* comment */ DROP TABLE users"
# REJECT: non-read-only statement: Drop
npx postgres-mcp-hardened --validate "SELECT 1; DROP TABLE users"
# REJECT: multiple statements are forbidden
npx postgres-mcp-hardened --validate "WITH d AS (DELETE FROM t RETURNING *) SELECT * FROM d"
# REJECT: non-read-only statement: non-read-only query (CTE / SELECT INTO / FOR UPD
... [View full README on GitHub](https://github.com/eszetael/postgres-mcp-hardened#readme)