SuperAPI AI Directory

postgres-mcp-hardened

Read-only PostgreSQL access: AST-validated queries in read-only transactions, schema inspection, column redaction, EXPLAIN cost guard and audit log.

Open website

About this tool

postgres-mcp-hardened is a Model Context Protocol (MCP) server written in Rust that lets AI agents query PostgreSQL in a read-only manner. It is positioned as a hardened replacement for the deprecated @modelcontextprotocol/server-postgres, employing a defense-in-depth strategy.

Purpose and Positioning The official Postgres MCP server was deprecated in 2024, but it still has a large number of downloads. Its entire defense consists of a single database-level read-only transaction, and the project documentation notes that this does not prevent all writes. postgres-mcp-hardened retains the rollback mechanism and adds AST validation in front of it, while supplementing it with an operational layer the original never had.

Main Capabilities

  • Read-only access: enforces read-only at the database level, layered with real SQL validation.
  • AST validation: performs abstract syntax tree validation on statements, rejecting non-read-only statements (for example, DROP TABLE returns -32602 non-read-only statement).
  • Timeouts and cost limits: provides statement timeouts and an EXPLAIN cost guard to prevent a single query from running indefinitely.
  • Schema inspection and column redaction: supports schema inspection and column redaction.
  • Authentication and auditing: supports OAuth 2.1 and provides audit logs.
  • Transport protocols: supports Streamable HTTP and stdio, and negotiates MCP revisions 2026-07-28 (current default), 2025-11-25, and 2025-06-18.
  • TLS: encrypts when connecting to PostgreSQL if the server supports it; accepts sslmode=require, verify-ca, and verify-full, with the certificate chain and hostname always verified, so require behaves equivalently to verify-full. A private CA can be pointed to via MCP_SSLROOTCERT to a PEM bundle.

Usage Five access paths are offered:

  1. One-click install: download the .mcpb package for the corresponding platform and open it; the connection string is stored in the operating system keychain rather than a plaintext configuration file.
  2. Via npm: the package itself is a launcher that at runtime fetches the native binary for the corresponding platform and verifies the checksum; at runtime it does not involve the Node runtime. The connection string is placed in env rather than args, to avoid appearing in ps output and shell history.
  3. Release page binaries: single file, suitable for machines without Node; these are not static binaries, and the -gnu and macOS targets link against the system C library.
  4. Containers: distroless image, runs as a non-root user, likewise with signature coverage. Note that MCP_ADDR must bind to 0.0.0.0 rather than 127.0.0.1; localhost in DATABASE_URL refers to the container itself, and PostgreSQL on the host machine requires using host.docker.internal or a bridged address.
  5. Building from source: run cargo build --release in the cloned directory; this crate is not on crates.io, so cargo install is not used.

Verification and Security Each release binary uses keyless Sigstore signing, accompanied by .sig and .pem; it is recommended to pin the identity rather than only verify the signature, using --certificate-identity-regexp and --certificate-oidc-issuer. Public releases also come with SLSA build provenance, verifiable with gh attestation verify.

Applicable Scenarios Suitable for development and operations scenarios that need to let AI agents safely query PostgreSQL, especially deployments that wish to connect with a least-privilege read-only role and require auditing and cost control. The project provides an offline read-only guard mode that can produce a verdict on statements without a database or configuration.

Limitations and Known Risks

  • The project is at the 0.1.x stage, and the author explicitly states that no external users have run it on their own data yet.
  • THREAT_MODEL.md documents an unresolved resource limit: 49 bytes of SQL can cause PostgreSQL to fold constants into 5.9 GB of backend memory during the planning stage, and a five-second statement_timeout cannot prevent it; it is recommended to set memory limits (such as --memory or systemd's MemoryMax).
  • The server uses 7.7 MB when idle, and normal requests are in the single-digit MB range, but malicious calls can push peak memory to 400 MB.
  • When the given role is writable, the server refusesNever start in network listening mode; however, it cannot control the connection string that users paste into the client configuration.
  • 0.1.8 and 0.1.9 fixed six bypasses found in 0.1.7 by four independent reviewers; 0.1.10 fixed the remaining three findings.
  • The official documentation does not provide commercial information beyond pricing, charges, or platform support.