An AI agent shops across PostgreSQL and MongoDB through one gateway β and cannot read another user's data, see a credential, or run raw SQL. The agent lives outside the trust boundary; every guarantee is enforced by MCP Toolbox and the database.
toolbox_app (least-priv).toolbox_ro.The signed-in user's JWT is attached server-side. The user never handles raw tokens.
The LLM calls list_my_orders(). Its schema has no username β it cannot ask "as whom".
Verifies JWT signature, issuer & audience against the OIDC provider; extracts preferred_username; binds it into the SQL parameter. The token header is keycloak_token.
Runs β¦ WHERE u.username = $1 as toolbox_app. A forged body value is ignored β the claim wins. No token β 401.
Rows return; an OpenTelemetry span records the tool, source, duration & outcome. Another user's data is simply unreachable.
scripts/verify_security.sh β 11/11execute_sqlThe agent gets 8 purpose-built tools, never arbitrary query power. Vector index/path are hardcoded.
username is bound from the OIDC claim & stripped from the model's schema. It can't be supplied or forged.
Admin tools need a grocery-admin audience only carol holds (role-driven in Keycloak).
store_region is fixed by the app, absent from the model signature. (App-layer trust β the confused-deputy line.)
Every statement uses $1β¦$n; tool args are values, never SQL. Injection β treated as a literal.
toolbox_app can't UPDATE the catalog, DELETE orders, or DROP. One role per source.
On GKE, Cloud SQL via IAM β no DB password exists in the cluster.
Credentials live only in Toolbox via ${ENV} β never reach the model; Secret Manager in prod.
Every tool call is a traced, audited event. A blocked read is a logged 0-row call, not a silent drop.
Only agentβToolboxβDB. The agent can't reach the database directly.
username, no store_region. The agent cannot pass what isn't there.