Skip to main content

QTG CLI & MCP — Reference

QTG ships 3 entry points for the control plane: All 3 binaries share the existing environment-variable HMAC signing path. Role enforcement happens server-side (HMAC middleware ROLE_ALLOWED_ROUTES). The protected connection-file mode below is a bounded preparation surface, not onboarding, issuance, or activation.

Env vars (single set, all 3 binaries)

The shared HMAC client emits both X-MG-* and X-QTG-* headers (v3 nonce + timestamp), matching qtg.interfaces.api.middleware.auth.hmac.sign_request_headers.

Agent CLI (qtg-agent, 8 commands, read + propose only)

qtg-agent balances

→ GET /v3/balances. Returns the balance view this agent can see.

qtg-agent movements list / get / timeline

→ GET /v3/movements?limit=20, GET /v3/movements/{id}, GET /v3/movements/{id}/timeline.

qtg-agent authority describe

→ GET /v3/agent-authorities/{authority_key}. The authority_key is derived from QTG_AGENT_NAMESPACE (strip agent/ prefix), or QTG_AUTHORITY_KEY if set, or fetched from /v3/whoami as fallback.

qtg-agent template-proposals get

→ GET /v3/template-proposals/{id}. Poll this after template-propose until status == "auto_promoted" (or admin promotes manually) to learn the resulting template_key.

qtg-agent template-propose

→ POST /v3/agent-authorities/{authority_key}/template-proposals. Side-effect free until promoted. Returns {proposal_id, status, ...}.

qtg-agent bridge-attempt

Same field set as template-propose plus optional --callback-url. D10 rule applies — propose only, no auto-execute.
No movement-run. The agent CLI is read + propose only — it cannot execute a movement. A movement an agent originates (via the API) always parks at PENDING_APPROVAL with agent_auto_approve_skipped, regardless of the operator’s auto_approve_enabled setting; a human promotes + approves.

Admin CLI (qtg)

qtg exposes all 8 agent commands plus the Free admin surface below. Venue checks (qtg venue probe/smoke) are implemented and wired today. Key/role provisioning (qtg admin keys / admin role) is still deferred to v0.2.0+ — use legacy seed_auth_client.py / bootstrap_admin_cli_key.py for that.

qtg init

Interactive local setup: can bring up PostgreSQL via compose, run the Alembic chain for public plus the selected network bucket, and render a .env from .env.example. It does not provision an inbound administrator credential, local signer, or agent authority. Walkthrough: Local Setup.
qtg init renders .env from .env.example, not from your live .env. Running it again after you have added keys by hand overwrites them.

Protected connection file (bounded preparation)

A protected POSIX connection file is supported only at the root of these commands:
The metadata is an exact, data-only schema: required keys are schema_version, api_url, network, key_id, and secret_file; namespace and authority_key are optional for CLI and namespace is required for MCP. secret_file is a raw-secret filename, not secret JSON or a path; it must name a direct sibling in the same protected directory. For example, these synthetic values are structurally complete:
The URL must be HTTPS (except exact loopback HTTP) and carries no query, fragment, or userinfo. network is exactly mainnet or testnet. When both namespace and authority_key are supplied, agent/<key> normalization must make them the same identity; contradictions fail before HTTP. The directory and both files must be owned by the invoking user, with directory mode 0700 and file mode 0600; symlinks, symlinked traversal, broad permissions, raw secrets in JSON, unknown fields, and ambient QTG_* fallback are rejected. The selected network becomes X-QTG-Network; a different process network fails closed. No other --connection-file command is supported: local, venue, top-up, Pro, help, and ordinary agent paths fail before file loading or command execution. auth check only reads authenticated identity and, for a matching agent namespace, its existing authority record. It does not evaluate policy, approval, provider, or live readiness. An omitted or mismatching agent namespace is non-success. File-selected revoke requires literal --yes; it still uses the server’s exact-current-credential revoke rules. The legacy env-only revoke command remains compatible without --yes. File-selected CLI failures with --json return only {"operation":"...","code":"..."} on stdout and the code on stderr. MCP rejects invalid file/role/namespace/network startup contexts with only a stable code and returns bounded operation/code errors from existing tools; it neither adds tools nor grants permissions. This does not bootstrap an administrator, issue a credential, authenticate pending keys, activate policy, or make a process movement-ready. Existing stored-secret-at-rest risks and legacy secret-output surfaces remain outside this preparation slice.

qtg whoami

→ GET /v3/whoami. Returns {client_id, key_id, role, namespace?}. Useful sanity check for key/secret setup.

qtg audit query

→ GET /v3/audit/events. Supported filters mirror src/qtg/interfaces/api/routes/audit.py (:59-98) exactly: --time-range-start, --time-range-end, --actor-client-id, --actor-key-id, --entity-type, --entity-key, --action, --request-id, --outcome, --namespace, --cursor, --limit.

qtg template promote

→ POST /v3/template-proposals/{proposal_id}/promote. Admin-only. Promotion is governed: the route returns 409 CONFIG_PROPOSAL_REQUIRED; promote through an agent_authority_proposal.promote configuration proposal applied by a second admin.

qtg template patch

→ PATCH /v3/plan-templates/{template_key}. --namespace is the only field this command sends. The auto-approve toggle and caps are governed — the raw HTTP route returns 409 CONFIG_PROPOSAL_REQUIRED for them — so change them through a route_template.auto_approve configuration proposal (see Auto-Approve).

qtg allowlist list

→ GET /dashboard/allowed-addresses. Read-only view of the address allowlist that guards fund movement. Filters: --chain-family (evm | cex), --chain-id, --include-inactive (adds revoked rows). A row with "chain_id": null is an any-chain wildcard — it authorises the address on every chain of its family. Review those first when auditing. The group is read-only by design. Registering and revoking stay on the audited write surfaces — python -m qtg.interfaces.tools.seed_allowed_address / ... .revoke_allowed_address, or the dashboard writer-HMAC routes — because a convenience CLI mutation on a fund-safety gate is an open security decision. See Runbook — Address Allowlist Management.

qtg chain probe

Reports whether a chain’s CCTP and Gateway lanes are actually open before you route funds through them. Read-only. Each lane also probes a domain that must not exist, so an endpoint that answers everything identically cannot read as GO. Exits non-zero unless every requested lane passes.

qtg agent-wallet topup

The Agent Wallet top-up stage ladder — preflight, env-probe, init-packet, seed-stage1, drill-stage2, live-stage3, validate-packet. init-packet requires an explicit --output-dir; use an operator-private directory outside publishing or shared branches, as an explicit path does not prove privacy. Only live-stage3 can sign or broadcast, and it requires an explicit acknowledgement flag. See Agent Wallet.

qtg testnet-truncate

Truncates every network-scoped table in the testnet schema. Prompts unless --yes is passed. There is no mainnet equivalent.

Human session CLI (qtg human)

JEP-877 protected human action / JEP-919 CLI onboarding surface — a closed, local-only human session plane, separate from the HMAC auth commands and not a credential issuance path:
Registered on both qtg and qtg-agent; browser-wallet opt-in (KMS/SIWE) stays disabled by default.

Venue CLI (qtg venue)

Adapter health check + live smoke test. See guide/venue-smoke-test.md for the end-to-end walkthrough.

qtg venue probe

Read-only adapter health check — verifies credentials and connectivity for the named exchange (e.g. binance, upbit, bybit). Exits non-zero if the probe fails. Runs the probe harness locally; no movement is created.

qtg venue smoke

Live smoke test — sends a small stablecoin transfer (capped at $5) through the full movement lifecycle and observes settlement. --max-source-debit is required and must be ≥ --amount: it is threaded into approval as the operator-approved CEX fee-on-top source-debit authority, so a withdrawal whose gross debit exceeds it is rejected. Prompts for confirmation unless --no-confirm is passed. --timeout bounds the observe phase (default 300s). Exits 0 only when the movement reaches COMPLETED; exit 1 when one or more probes/transfer steps fail, exit 2 for unknown venue or missing credentials.

MCP server — Claude Desktop / Cursor

qtg-mcp is a stdio MCP server exposing 8 read+propose tools to MCP-aware clients (no movement-execution tool).

claude_desktop_config.json

Tool list

Boot-time role probe (fail-fast)

qtg-mcp does a synchronous GET /v3/whoami before opening the stdio handshake. If:
  • the env is incomplete → exit 2 with stderr qtg-mcp: config error: ...
  • whoami HTTP fails → exit 1 with stderr qtg-mcp: whoami probe failed: ...
  • role != agent → exit 1 with stderr qtg-mcp: refusing to start — key role is 'admin', expected 'agent'
  • env namespace != server-reported namespace → exit 1 with stderr qtg-mcp: namespace mismatch — ...
This prevents silent registration in Claude Desktop with a misconfigured key.

e2e smoke runbook


Out of scope (v0.1.0 GA)

  • Template discovery (qtg-agent templates list/search) — v0.2.0
  • Streamable HTTP MCP transport — v0.2.0+ (stdio only for now)
  • qtg admin keys / admin role (key/role provisioning) — server routes pending; use legacy seed_auth_client.py for now.
  • Migration of 55+ legacy admin tools — v0.2.0+ gradual
  • Colored / pretty CLI output (rich) — v0.2.0+
  • Windows shell compatibility — macOS + Linux verified only