Endpoint
The server is mounted on the running pgconsole instance over Streamable HTTP:401.
Identity
Each token belongs to an[[agents]] entry — a non-human principal that is not a user (no UI login). There are two kinds:
If no [[iam]] rules are defined, IAM is off and agents have full access to all connections; define at least one rule to enforce least privilege.
- Pure agent — a standalone service account (e.g. a CI bot). When IAM is active, authorized by IAM rules whose
membersincludeagent:<id>. Audited asagent:<id>. - Delegated agent — acts
on_behalf_ofa user, inheriting that user’s permissions narrowed by optionalpermissions/connectionscaps. It can never exceed the user and loses access automatically when the user does. Audited as the user, tagged with the agent.
pgconsole.toml
Connecting a client
Point any MCP client that supports remote (Streamable HTTP) servers at the endpoint. For example, with Claude Code:Tools
The advertised tool list is filtered per agent — an agent only sees the tools its permissions unlock.Discovery
Available whenever the agent can access at least one connection.list_objects is paginated (pass the response’s nextCursor back as cursor) and filterable (nameFilter), so agents navigate large schemas top-down instead of pulling a full dump.
Execution
One tool per IAM permission. Each appears only if the agent holds that permission on at least one connection.Enforcement
Every execution tool runs the submitted SQL through pgconsole’s parser-based permission detection before touching the database:- The SQL is parsed; each statement’s required permission must match the tool’s permission. A
DROPsent toquery, or a mixed-class batch, is rejected — there is no smuggling a privileged statement through a lower-privileged tool. - The full set of permissions the SQL requires (including ones implied by function calls, e.g.
pg_terminate_backendrequiresadmin) must be a subset of the agent’s grants. - The query is executed and recorded in the audit log, tagged with
source: "mcp", the tool name, and the agent.
explain_query only accepts a single SELECT (Postgres EXPLAIN rejects other statement kinds); with analyze (which actually executes the statement) it additionally requires every permission running the statement would require.
Least privilege: a pure agent gets only what its
agent: IAM rules grant; a delegated agent can never exceed the user it acts for, and is further narrowed by its permissions/connections caps. Give each agent the narrowest grant it needs.