binky-control/integrations/qonto-mcp.md
tegwick 143eef2f0d
All checks were successful
Work Records / validate (push) Successful in 13s
BINKY-WP-0005 finished: first Qonto pull and CostRunRate v2
Live custody path tenants/binky/qonto-api (API_KEY/API_USER). First read-only
thirdparty pull (122 txs): desk 297.50 €/mo, Qonto plan 70.80 €/mo, main
balance 2185.94 €. Evidence under finance/; workplan status finished.
2026-07-21 21:42:10 +02:00

148 lines
6.9 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Qonto MCP Integration — Design
> Status: **lane active** — 2026-07-21 (BINKY-WP-0005 finished).
> Goal: the company Qonto account becomes an agent-readable finance source
> (balance, transactions, statements) through the sanctioned harness/MCP /
> thirdparty API lane. **Read scopes first; payments/transfers are Red lane forever.**
> Credentials live at `tenants/binky/qonto-api` (CCR-2026-0008 / 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`** (live) |
| Fields | **`API_KEY`**, **`API_USER`** (login/org slug) |
| MCP env map | `API_KEY``QONTO_API_KEY`, `API_USER``QONTO_ORGANIZATION_ID` |
| Policy | `workload-kv-read-binky-qonto-api` |
| OIDC role | `binky-qonto-api-workload-kv-read` |
| Catalog | `binky-qonto-api` (**active**, resolvable) |
| Risk | high (full-scope bank API key — read-only is harness-enforced) |
Auth to Qonto thirdparty API: `Authorization: <API_USER>:<API_KEY>`.
```text
founder (Red lane, once)
└─ bao kv put tenants/binky/qonto-api API_KEY=@file API_USER=@file
└─ OpenBao: tenants/binky/qonto-api
└─ warden access binky-qonto-api --exec
└─ map fields → QONTO_* env → qonto-mcp-server / curl thirdparty
└─ finance/CostRunRate.md + rhythm session feeds
```
### Founder provision (Red lane — interactive human shell)
```bash
# In the Qonto dashboard: /settings/integrations → create API key, note login/org slug
umask 077
bao kv put tenants/binky/qonto-api \
API_KEY=@/tmp/qonto.key \
API_USER=@/tmp/qonto.user
shred -u /tmp/qonto.key /tmp/qonto.user
```
`API_USER` 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. [x] Variant + read-only enforcement decided (this doc)
2. [x] OpenBao lane designed → **live path `tenants/binky/qonto-api`**
3. [x] DecisionQueue package prepared (DEC-2026-004)
4. [x] DEC-2026-004 **approved** (founder, 2026-07-19)
5. [x] CCR-2026-0008 **active** (policy + OIDC role + agent-high-risk-boundary)
6. [x] ops-warden catalog `binky-qonto-api` **active** + playbook
7. [x] Red-lane secret present (`API_KEY` + `API_USER`)
8. [x] Capabilities-safe verify (lane-policy → `read` on data+metadata paths)
9. [x] First read-only pull 2026-07-21 (122 txs); CostRunRate v2
(`finance/qonto-first-pull-2026-07-21.json`)
10. [ ] Wire Finance Steward recurring session (post-cutover, harness lane —
**follow-on**, out of scope for BINKY-WP-0005)
## First-pull results (T05, 2026-07-21)
| Item | Value |
| --- | --- |
| Org | Binky Hedgehog GmbH |
| Main balance | 2185,94 € |
| Desk (HUB31) | **297,50 €/mo** |
| Qonto plan fee | **70,80 €/mo** (since 2025-10; was 22,80 / 35,40 earlier) |
| Evidence | `finance/qonto-first-pull-2026-07-21.json` |
**Harness read-only allow-list (enforce at session wire-up):** organization,
accounts, transactions, statements metadata, attachments metadata, labels.
Never: cards, invoicing, payment requests, transfers.
### Consumer fetch (after active)
```bash
bao login -method=oidc -path=netkingdom role=binky-qonto-api-workload-kv-read
umask 077
bao kv get -field=API_KEY tenants/binky/qonto-api > /tmp/qonto.key
bao kv get -field=API_USER tenants/binky/qonto-api > /tmp/qonto.user
export QONTO_API_KEY="$(cat /tmp/qonto.key)"
export QONTO_ORGANIZATION_ID="$(cat /tmp/qonto.user)"
shred -u /tmp/qonto.key /tmp/qonto.user
# Authorization for thirdparty API: "$QONTO_ORGANIZATION_ID:$QONTO_API_KEY"
```
## See also
- `integrations/company-email-openbao.md` — custody pattern being mirrored
- `AutopilotWorkQueue.md` AWQ-010 (origin), `OfficeHourQueue.md` OH-2026-003
- `railiance-platform` CCR-2026-0008 · `ops-warden` catalog `binky-qonto-api`
- Qonto docs: <https://docs.qonto.com/mcp/overview>,
<https://github.com/qonto/qonto-mcp-server>