What pg-readonly-mcp does
The pg-readonly-mcp MCP server gives an AI client one database operation: query. It accepts a SQL statement for PostgreSQL, validates the statement before execution, and returns up to a configured number of rows. The intended use is inspection and analysis of database contents without allowing the agent to modify the database.
SQL safety is based on parsing rather than searching for suspicious text. The validator requires one statement and permits only read-oriented outer forms: SELECT, set operations such as UNION, INTERSECT, and EXCEPT, or a CTE based on those forms. It also walks the complete syntax tree to find data-modifying operations hidden inside nested expressions or CTEs.
How it works
The pg-readonly-mcp MCP server applies two separate controls. First, sqlglot parses the incoming SQL and rejects multiple statements, unsupported shapes, and write operations anywhere in the parsed tree. A statement that is unfamiliar to the validator is rejected instead of being treated as safe.
Second, startup checks inspect the PostgreSQL connection role. The server refuses to start when the role is a superuser, can create databases or roles, can bypass row-level security, or has grants beyond SELECT on tables it can see. These checks address common privilege mistakes but are not a complete PostgreSQL privilege audit.
The query tool also applies a maximum row count and a statement timeout. Their defaults are 1,000 rows and 5,000 milliseconds respectively.
Setup and configuration
Install the package with:
pip install pg-readonly-mcp
A source checkout can be installed in editable mode with pip install -e .. Supply the PostgreSQL connection string through the --dsn option or the PG_READONLY_MCP_DSN environment variable. Using the environment variable keeps the password out of command-line arguments and client configuration files.
A typical stdio client configuration is:
{
"mcpServers": {
"pg-readonly-mcp": {
"command": "pg-readonly-mcp",
"env": {
"PG_READONLY_MCP_DSN": "postgresql://readonly_role:...@host:5432/db"
}
}
}
}
The configured role should have no privileges beyond SELECT; the server checks this condition during startup.
Tools and capabilities
The pg-readonly-mcp MCP server provides one tool:
query: Executes one validated, SELECT-shaped PostgreSQL statement, subject to the row cap and statement timeout.
The project includes unit tests for SQL validation that do not require a database, plus integration tests using a live PostgreSQL instance to check role attributes and grants.
Limitations and notes
Read-only enforcement does not make expensive queries free. A wide result within the row limit or a costly query plan can still consume database resources, although the row cap and timeout limit exposure.
The server controls database queries, not what an AI agent does with returned data. Any data readable by the configured role can be exposed to the agent. The startup privilege check also does not enumerate every possible PostgreSQL privilege path, including ownership, PUBLIC grants, or all row-level security behavior.
Finally, SQL parsing uses sqlglot, while PostgreSQL uses its own parser. A disagreement on an edge case is possible. The database role check provides an independent barrier if the parser and PostgreSQL interpret a statement differently.