Documentation

Agent Access (MCP)

Give an AI agent — Claude Code, Cursor, or your own scripts — access to your databases through QueryGlow's safety layer instead of handing it a raw connection string. QueryGlow exposes a Model Context Protocol (MCP) endpoint at /api/mcp. The agent gets scoped, read-only-by-default access through 5 tools, and every query it runs is logged.

Read-only is enforced by the database, not a text filter

A read-only token runs inside a database-enforced read-only transaction, and every agent statement goes through the driver's single-statement (prepared/extended) path — so an agent cannot smuggle a second statement or slip a write past the guard.

1. Create a Token

  1. 1Open QueryGlow and click the robot icon in the sidebar footer (Agent Access).
  2. 2Give the token a name, e.g. Claude Code.
  3. 3Tick the connections the agent may use. Each connection shows its environment, and production connections are only reachable if you explicitly select them.
  4. 4Tokens are read-only by default (recommended) — SELECT/read only. Tick Allow writes to also permit INSERT/UPDATE/DELETE; you then set the max rows a single write may affect (default 1000). Even a write token cannot run DROP/TRUNCATE/DDL, and any single write over that limit is rolled back at the database — a missing-WHERE mistake can't wipe a table.
  5. 5Optionally set an expirationNo expiration (default), 30, 90, or 365 days. After it expires the token stops authenticating and you issue a new one.
  6. 6Click Create Token. The raw token (qg_...) is shown once — copy it now.

Revoke a token any time from the same dialog; the agent loses access immediately.

2. Connect a Client

The Agent Access dialog gives you a ready-to-paste MCP client config. For Claude Code, Cursor, Claude Desktop, and most MCP clients it looks like:

{
  "mcpServers": {
    "queryglow": {
      "url": "https://your-domain.com/api/mcp",
      "headers": { "Authorization": "Bearer qg_your_token_here" }
    }
  }
}

The endpoint speaks the MCP Streamable HTTP transport (JSON-RPC over HTTP). It is stateless — no session setup, one request per call. Replace your-domain.com with your QueryGlow domain and qg_your_token_here with the token you copied.

Tools the agent gets

ToolWhat it does
list_connectionsThe connections this token may use — names, types, environments. Never hosts or credentials.
get_schemaTables and columns of a connection, so the agent writes correct SQL.
run_queryRuns a SQL query and returns rows. Read-only tokens: SELECT/read only. Write tokens: also INSERT/UPDATE/DELETE. Results are row-capped; over-limit writes are rolled back. Pass dry_run: true to preview a write's affected-row count without committing.
explain_queryReturns the query plan (EXPLAIN) without executing.
get_query_historyRecent queries (human and agent) for the allowed connections.

3. The Safety Model

Enforcement is layered, and the authoritative guarantees live at the driver and database — not in a regex:

Read-only transactions, enforced by the database

Read-only tokens execute inside a TRANSACTION READ ONLY (PostgreSQL/MySQL) or with PRAGMA query_only (SQLite). The database rejects writes no matter how the SQL is phrased — even a write hidden inside a function call (SELECT wipe_and_reload()) is rejected.

Single statement, at the driver

Every agent statement runs through the driver's prepared/extended protocol, which rejects any string containing more than one command. A benign leading read cannot carry a second statement (SELECT 1; DROP ...).

Never DDL

Agents can never run DROP/TRUNCATE/DDL, GRANT/REVOKE, filesystem or command-execution SQL, or server-side file/network functions (pg_read_file, dblink, ...) — even on a write token.

Write row-cap with rollback, plus dry-run

A write token may run only a single INSERT/UPDATE/DELETE. Any write whose real affected-row count exceeds the token's limit is rolled back at the database — a missing-WHERE whole-table wipe changes nothing — and dry_run previews the impact first. On PostgreSQL and SQLite the cap counts cascade and trigger rows too; on MySQL/MariaDB only the statement's own direct affected rows are measured.

Audit trail, including blocked attempts

Every run_query/explain_query is written to Query History tagged with the token's name — guard rejections are logged too — so you can review exactly what the agent tried. Filter to agent runs with the robot toggle in the History tab.

Error redaction

Driver errors returned to the agent are redacted (no host/IP/port/username/path/values), and get_query_history masks all string literals and comments of human queries — an agent can't harvest secrets a human typed.

Rate limits and timeouts

The endpoint is rate-limited in-app: per IP (default 240 req/min, QUERYGLOW_MCP_RATE_MAX) plus a global ceiling (default 2000 req/min, QUERYGLOW_MCP_GLOBAL_RATE_MAX). Every statement is bounded by a per-statement timeout (default 30s, QUERYGLOW_AGENT_STATEMENT_TIMEOUT_MS), and result sets are hard-capped at 50,000 rows in the driver layer.

Good to Know

  • Agent Access is disabled entirely in demo mode (DEMO_MODE=true).
  • Production connections must be explicitly allowlisted — the token dialog shows each connection's environment so you don't grant production access by accident.
  • The nginx config from deploy.sh exempts /api/mcp (exact match) from Basic Auth, because agents authenticate with the Bearer token instead of the Basic Auth password. Tokens are stored only as SHA-256 hashes.
  • The token-management API (/api/agent-tokens) is a human-only, browser endpoint that stays behind Basic Auth. Keep QueryGlow behind its reverse proxy; do not expose the app port (:3000) directly.
  • The safest setup is a read-only token scoped to a staging database or read replica. Give an agent production write access only with a clear reason.

Troubleshooting

401 Unauthorized

The Bearer token is missing, mistyped, revoked, or expired. Check that the Authorization header is exactly Bearer qg_.... If the token expired or was revoked, create a new one in the Agent Access dialog. If your reverse proxy does not exempt /api/mcp from Basic Auth, the proxy rejects the request before it reaches QueryGlow.

"Connection is not available to this token"

The agent asked for a connection that is not on the token's allowlist. Have the agent call list_connections to see what it may use, or update the token's connection selection in the Agent Access dialog.

Statement blocked by the guard

A read-only token attempted a write, the statement contained more than one command, or a read could not be row-bounded (a placeholder or expression LIMIT, LIMIT ALL, FETCH FIRST/NEXT, or FOR UPDATE/SHARE — use a numeric LIMIT instead). Blocked attempts are logged in Query History, so you can see exactly what was rejected and why.

Endpoint not responding in demo mode

Agent Access is disabled when DEMO_MODE=true. Run a regular (non-demo) deployment to use MCP tokens.