That last line is the honest one. The server enforces read-only at the transaction level, rejects internal semicolons, blocks write keywords by regex and caps rows — and the README still says to give it a PostgreSQL role that cannot write anyway. That is the correct posture for a tool an assistant drives. The four prompts are the underrated part: a table audit or a slow-query profile is a slash command rather than a sequence of calls you have to assemble.
A PostgreSQL MCP server built to feed a model context without any risk of writing. Read-only is not a convention here but a stack of enforcement: `SET TRANSACTION READ ONLY`, a statement timeout, a row cap, single-statement rejection and a write-keyword check by regex.
- Introspection across the allowed schemas: schemas, tables with column counts, a table's columns, constraints and indexes, functions with signature and language, triggers with table and timing, views regular and materialised, and a column search by name pattern — `postgres_list_schemas`, `postgres_list_tables`, `postgres_describe_table`, `postgres_list_functions`, `postgres_list_triggers`, `postgres_list_views`, `postgres_search_columns`
- Definitions read in full — a function's source, with overload support, and a trigger's complete definition — `postgres_get_function_definition`, `postgres_get_trigger_definition`
- Querying two ways: a structured single-table SELECT that uses SQL parameters and never concatenates strings, and an advanced SELECT or WITH for joins, CTEs and aggregations — `postgres_query_table`, `postgres_execute_query`
- Plan analysis and storage stats: EXPLAIN and EXPLAIN ANALYZE before you run something expensive, plus total, table, index and toast sizes, vacuum and analyze timings, and indexes sitting at zero scans — `postgres_explain_query`, `postgres_get_table_stats`
- Two browsable resources — `postgres://schema/{schema}` and `postgres://table/{schema}/{table}` — and 4 slash-command prompts: `audit-table`, `find-tables`, `explain-foreign-keys`, `profile-slow-query`
- Pagination that tells you there is more: the list tools take limit and offset and return `has_more` and `next_offset`
A PostgreSQL database and Node >= 18 with `pnpm`. Build from a clone with `pnpm run build`, then register with `claude mcp add` passing the connection variables, or point a JSON config at `dist/index.js`. Connection settings are `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`, with `DB_SSL` for managed hosts and `DB_SSL_REJECT_UNAUTHORIZED` kept true in production. `DB_SCHEMAS` is the allow-list — empty means every non-system schema. `DEFAULT_LIMIT` sets the default row limit; the hard cap is 100 rows per query, with 10 s to connect and 30 s per statement. The README recommends a read-only PostgreSQL role on top of all this. It also packages as an MCPB bundle for Claude Desktop, where the password field is marked sensitive in the install form. The README is written in Spanish.
Build from source — clone the repository and build it, then point your client at the binary
