Execute read-only SQL queries against a PostgreSQL database using psycopg2, with parameterized execution and structured tabular results.
- Read-Only Enforcement: Rejects write/DDL statements (
INSERT,UPDATE,DELETE,DROP,ALTER, etc.) at the query-text level, and additionally opens the database session itself in read-only mode viapsycopg2'sset_session(readonly=True). - Parameterized Queries: Prevents SQL injection by passing a list of positional parameters instead of interpolating values into the query string.
- Structured JSON Output: Returns a list of key-value row mappings alongside column names and execution time telemetry.
- Configurable Limits: Caps returned rows via
max_rows(default100) and enforces a server-sidestatement_timeout_ms(default5000) to protect against runaway queries. - Flexible Connection Config: Accepts an explicit
connection_string, or falls back toPOSTGRES_DSN/DATABASE_URL/POSTGRES_HOST,POSTGRES_PORT,POSTGRES_DB,POSTGRES_USER,POSTGRES_PASSWORDenvironment variables — never hardcode credentials.
pip install -r requirements.txtConfigure database access via environment variables (recommended):
export POSTGRES_DSN="postgresql://user:password@host:5432/dbname"
# or individually:
export POSTGRES_HOST="localhost"
export POSTGRES_PORT="5432"
export POSTGRES_DB="mydb"
export POSTGRES_USER="myuser"
export POSTGRES_PASSWORD="mypassword"| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query |
string |
Yes | — | SQL query string. Must start with SELECT, WITH, EXPLAIN, SHOW, or TABLE |
params |
array |
No | [] |
Positional parameter values for parameterized SQL execution |
connection_string |
string |
No | env vars | PostgreSQL DSN, e.g. postgresql://user:pass@host:5432/dbname |
max_rows |
integer |
No | 100 |
Maximum number of rows to retrieve |
statement_timeout_ms |
integer |
No | 5000 |
Server-side statement timeout in milliseconds |
{
"query": "SELECT id, username, email FROM users WHERE status = %s LIMIT 10",
"params": ["active"]
}{
"query": "SHOW server_version"
}{
"status": "success",
"columns": ["id", "username", "email"],
"rows": [
{ "id": 1, "username": "alice", "email": "alice@example.com" },
{ "id": 2, "username": "bob", "email": "bob@example.com" }
],
"row_count": 2,
"has_more": false,
"execution_time_ms": 4.87
}{
"status": "error",
"error": "Only read-only statements (SELECT, WITH, EXPLAIN, SHOW, TABLE) are permitted.",
"columns": [],
"rows": [],
"row_count": 0,
"execution_time_ms": 0.0
}