On this page

Query firewall

Every statement an agent sends through the API or MCP is parsed with the Postgres parser and checked against its key before it runs.

The firewall is the second layer: the first is the agent's own Postgres role, so anything the firewall would miss still fails with "permission denied" in Postgres.

#Always refused

  • Transaction control (BEGIN, COMMIT, savepoints): each request runs in one transaction.
  • SET / RESET (including SET ROLE and set_config()).
  • DO blocks, COPY, PREPARE / EXECUTE, CALL, LOCK, LISTEN / NOTIFY, rules, roles, ownership changes, VACUUM.
  • SQL from strings (query_to_xml and friends), file and large-object functions, dblink, HTTP from SQL, backend control functions.
  • Platform schemas (auth unless allowed, vault, cron, net, pgmq, the undo log), and denied or not-allowed tables.
  • Schema changes, unless the key has the migrations preset; disabling triggers and StitchDB's own triggers, even for migrations keys.

#Checked per key

  • Operations: SELECT / INSERT / UPDATE / DELETE, including writes hidden in a WITH clause and EXPLAIN ANALYZE.
  • UPDATE / DELETE without a real WHERE (also WHERE true and WHERE 1 = 1).
  • Rows changed per statement (counted by the database, including rows changed by triggers).
  • Calls to your own functions.

#What the agent sees

JSON
HTTP 403
{ "error": "Table public.payments is denied for this agent key",
  "code": "agent_firewall", "rule": "table_denied", "statement_index": 0 }

Clear reasons let an agent correct itself instead of retrying blindly.

Was this helpful?