"Just make it read-only" is the right instinct and the wrong stopping point. A read-only Postgres role does stop writes — but it doesn't cap an expensive query, doesn't limit which tables the agent sees, doesn't give you a way to cut off one misbehaving agent, and leaves no record of what ran. For an autonomous agent that can generate and execute SQL on its own, you want more than one control.
The layers that make "read-only" real
1. A read-only database role
Start here. Create a dedicated Postgres user with SELECT-only grants — ideally against
a replica. This is your floor, not your ceiling.
2. Statement classification before execution
Parse and classify each statement and reject writes, DDL and dangerous functions before they reach the database. This matters because read-only transactions alone have been bypassed: the archived official Postgres MCP server shipped a documented SQL-injection that escaped its read-only transaction. Classify first, then run — defense in depth.
3. A read-only transaction
Execute inside a read-only transaction as a second wall, so anything the classifier misses still can't mutate data.
4. Resource limits
Cap result size and set a query timeout. "Read-only" doesn't stop a SELECT that scans a
billion rows — limits do.
5. Revocable, per-agent keys
Give each agent its own key so you can revoke one without touching the others, and never expose the database password to the agent at all.
6. An audit trail
Log every query with the key that ran it. When someone asks "what has the AI touched?", you need an answer.
Doing all six without building it yourself
The AI2SQL Gateway is these layers as a hosted service. You add a database, get a revocable key, and your agent connects over MCP — read-only enforced two ways, results bounded, every call logged. No server to run.
$ claude mcp add --transport http ai2sql \
https://builder.ai2sql.io/api/mcp \
--header "x-ai2sql-key: $AI2SQL_KEY" \
--header "x-ai2sql-connection: $CONNECTION_ID" ✓ ai2sql connected — 3 tools available
run_query · describe_schema · list_connections
Get $AI2SQL_KEY
and $CONNECTION_ID
from the AI2SQL Gateway — connect a database and the
setup wizard generates both for you.
If you'd rather run it yourself, self-hosted options like Postgres MCP Pro and DBHub implement several of these layers in open source — the trade-off is that you operate and secure the process. See how the choices compare in AI2SQL Gateway vs a raw Postgres MCP server.