binky-control/integrations/qonto-mcp.md
tegwick 892c174b7a
Some checks failed
Work Records / validate (push) Has been cancelled
BINKY-WP-0005: OH/T05 runbook and lane-scaffold notes for Qonto MCP
Prepare first-pull path after DEC-2026-004: copy-paste founder provision,
CCR apply, catalog promote, and CostRunRate update steps. T05 still waits
on Red-lane API key provision.
2026-07-21 21:26:25 +02:00

8 KiB

Qonto MCP Integration — Design

Status: design v1 — 2026-07-19 (BINKY-WP-0005, from AWQ-010).
Goal: the company Qonto account becomes an agent-readable finance source (balance, transactions, statements) through the sanctioned harness/MCP lane. Read scopes first; payments/transfers are Red lane forever. Credential provisioning is a single founder Red-lane step (DEC-2026-004).

Variant decision (T01)

Two Qonto MCP options exist as of 2026-07:

Hosted connector Self-hosted server
Endpoint https://mcp.qonto.com/mcp qonto/qonto-mcp-server (GitHub), Docker image qonto/qonto-mcp-server:latest
Auth OAuth (user identity, Business-API scopes) QONTO_API_KEY + QONTO_ORGANIZATION_ID env vars (from Qonto /settings/integrations)
Transport remote streamable-HTTP only stdio (default) or --transport streamable-http
Tool surface curated subset incl. write tools (cards, invoicing, requests); no transfers organization info, accounts, transaction history, business operations
Custody fit credentials live in the AI client's connector settings env-name pattern — identical to email-connect

Chosen: self-hosted qonto/qonto-mcp-server. The hosted connector is exactly the "native integration" the corporate access policy forbids (OAuth grant held by claude.ai/the client, outside OpenBao custody, write tools bundled in). The self-hosted server consumes credentials only via env names, runs inside the harness, and rides the existing warden delivery path unchanged.

Read-only enforcement: Qonto API keys are not scope-limited server-side, so read-only is enforced at harness level: tool allow-list restricted to read tools (organization, accounts, transactions, statements, attachments, labels). Card, invoicing, request and any future transfer tools are never allow-listed. This mirrors the Green/Blue tool allow-list of scripts/rhythm-session.sh. Any payment initiation stays founder-only in the Qonto app — Red lane forever, not an automation target.

Prerequisite check (founder, while in the dashboard — OH-2026-003): confirm the current Qonto plan exposes API keys under /settings/integrations; note plan tier + monthly cost for finance/CostRunRate.md row 4.

Credential lane (T02) — ops-warden/OpenBao custody

Same pattern as integrations/company-email-openbao.md (WARDEN-WP-0028 tenants custody):

Item Value
Mount tenants
Path tenants/binky/qonto/api
Fields QONTO_API_KEY, QONTO_ORGANIZATION_ID
Policy workload-kv-read-binky-qonto-api (to be created, warden playbook)
Catalog binky-qonto-api (draft until provision)
Risk high (full-scope bank API key — read-only is harness-enforced)
founder (Red lane, once)
   └─ bao kv put tenants/binky/qonto/api QONTO_API_KEY=@file QONTO_ORGANIZATION_ID=@file
        └─ OpenBao: tenants/binky/qonto/api
             └─ warden access binky-qonto-api --exec
                  └─ qonto-mcp-server (env names only) → harness read tools
                       └─ finance/CostRunRate.md + rhythm session feeds

Founder provision (Red lane — interactive human shell)

# In the Qonto dashboard: /settings/integrations → create API key, note org ID
umask 077
# key into /tmp/qonto.key, org id into /tmp/qonto.org — private terminal only
bao kv put tenants/binky/qonto/api \
  QONTO_API_KEY=@/tmp/qonto.key \
  QONTO_ORGANIZATION_ID=@/tmp/qonto.org
shred -u /tmp/qonto.key /tmp/qonto.org

The organization ID is low-secrecy but lives with the key so consumers get one fetch surface (same rule as IMAP username). Key never in git/chat.

Consumer design (T03)

Consumer Use Cadence
Finance Steward rhythm session balance snapshot + new-transaction triage → finance/ metadata weekly (harness-scheduled, after cutover)
finance/CostRunRate.md resolve TBC rows: desk rent (HUB31 debit), Qonto plan fee; verify DATEV pass-through, railiance01 debit first pull, then on statement events
OH-2026-003 package real cost-vs-usage numbers; the working MCP is itself an argument FOR keeping Qonto once, next office hour
Runway view (CostRunRate finding 2) month-end balance series → liquidity awareness monthly

Rules:

  • Transaction metadata (dates, counterparties, amounts) may land in finance/ evidence tables; no bulk statement exports into git.
  • Read-only tool allow-list per above; sessions run Green/Blue.
  • DUO boundary: main accounting stays DATEV Unternehmen Online via the StB lane. Qonto MCP complements it (operational awareness, run-rate, runway); it does not replace Belegablage or bookkeeping.

Execution checklist

  1. Variant + read-only enforcement decided (this doc)
  2. OpenBao lane designed (tenants/binky/qonto/api)
  3. DecisionQueue package prepared (DEC-2026-004)
  4. DEC-2026-004 approved (founder, 2026-07-19)
  5. CCR-2026-0008 + policy HCL + agent-high-risk-boundary deny (railiance-platform)
  6. ops-warden catalog binky-qonto-api draft + playbook (ops-warden/wiki/playbooks/binky-qonto-api.md)
  7. Red lane — founder (OH-2026-003): create API key; bao kv put via @file (see founder block below and officehour/2026-08-command-day-runbook.md)
  8. Apply CCR-2026-0008 metadata (policy + OIDC role) — platform-operator
  9. Capabilities-safe verify; promote catalog draft → active
  10. First read-only pull; update CostRunRate TBC rows (BINKY-WP-0005-T05)
  11. Wire Finance Steward recurring session (post-cutover, harness lane — out of scope for BINKY-WP-0005 close; follow-on after T05)

OH-2026-003 / T05 runbook (copy-paste)

A. Founder Red lane (interactive human shell only)

# 1) Qonto dashboard (browser):
#    - /settings/integrations → create API key
#    - copy organization ID
#    - note plan tier + monthly fee (CostRunRate row 4)
#    - optional while there: recent HUB31 / desk-rent debit amount (row 1)

# 2) OpenBao (private terminal — never paste key into chat/agent):
bao login -method=oidc -path=netkingdom   # platform-admin or write-capable role
umask 077
# put key into /tmp/qonto.key and org id into /tmp/qonto.org (editor / paste)
bao kv put tenants/binky/qonto/api \
  QONTO_API_KEY=@/tmp/qonto.key \
  QONTO_ORGANIZATION_ID=@/tmp/qonto.org
shred -u /tmp/qonto.key /tmp/qonto.org

B. Platform apply (after or before A — metadata only, no secret write)

cd ~/railiance-platform
# after platform-operator approval recorded on CCR-2026-0008:
python3 scripts/credential-change.py applier-dry-run CCR-2026-0008
python3 scripts/credential-change.py applier-apply CCR-2026-0008
# re-apply agent-high-risk-boundary if that policy is live-managed separately

C. Promote + first pull (agent or human, Blue lane)

# capabilities-safe (never bao kv get for deny tests)
LANE=$(bao token create -policy=workload-kv-read-binky-qonto-api -ttl=2m -field=token)
bao token capabilities "$LANE" tenants/data/binky/qonto/api   # expect read
bao token revoke "$LANE"

# promote ops-warden catalog entry status: draft → active (see playbook)
# then:
warden access binky-qonto-api --all --exec -- \
  qonto-mcp-server   # read tools only: org, accounts, transactions

# Update finance/CostRunRate.md rows 1 + 4 with verified amounts;
# log evidence metadata (dates, counterparties, amounts) — no bulk statements in git.

Harness read-only allow-list (enforce at session wire-up): organization, accounts, transactions, statements metadata, attachments metadata, labels. Never: cards, invoicing, payment requests, transfers.

See also