- Install vendor MCP (or raw API keys) into Claude Desktop, Claude Code,
Codex, Cursor, Grok, agent-harness, executor-worker, etc. **separately**.
- Rely on each harness’s local tool allow-list as the only spend control.
- Hope every client remembers “read-only forever.”
Why that fails:
| Failure mode | Effect |
| --- | --- |
| **Policy drift** | One harness allows a write tool; another forbids it. Same company key, different blast radius. |
| **Credential sprawl** | Keys appear in N configs, Docker args, session env dumps. |
| **Audit fragmentation** | No single log of “which agent did what to the bank.” |
| **Qonto cannot help** | Business API keys are **not** scope-limited server-side (confirmed in design). There is no “read-only API key” or MCP-side spend ACL from Qonto. |
| **Volume-cost tools** | Cards, invoicing, payment requests, transfers, and some “create” operations may incur fees or move money — must be blocked **before** the vendor sees them. |
**Founder policy for now (normative intent):**
> Agents may inspect balances, transactions, and statements for control-plane
> and finance awareness. Agents must **not** initiate spending, transfers,
> card operations, or any action with volume/transaction cost. Payments stay
> Red lane (human in Qonto app).
That is stronger than “read-only MCP tools” in the abstract: it is a **business
policy** that must be enforced at a choke point, not a client preference.
---
## 2. What industry patterns say
Research (2025–2026 MCP ecosystem) converges on the same shape your proxy
intuition already points at.
### 2.1 MCP gateway / proxy as the control plane
Production patterns treat MCP **clients** (agent harnesses) as untrusted for
tool policy, and put a **gateway** between them and tools:
- **Envoy AI Gateway MCPRoute** — multiplex backends, **toolSelector**
allow/deny, OAuth on the gateway, upstream API-key injection so clients
never hold vendor secrets, CEL rules on `tools/call` params.
of every tool call, policy evaluated **on each call**, not only at
connect time.
- **Harness’s own MCP guidance** — gateways for centralized credentials,
governance, audit, single endpoint vs N direct MCP connections.
Common lesson: **clients connect to one governed endpoint; the gateway owns
credentials, tool inventory, and policy.**
### 2.2 MCP security best practices (protocol-level)
From MCP security guidance and industry write-ups:
| Practice | Application to Qonto |
| --- | --- |
| **No token passthrough** | Clients must not present the Qonto bank key. The assistant service is the only OAuth/API client to Qonto. |
| **Tool-level scopes, not server-level** | “Access to Qonto MCP” is too coarse; allow `list_transactions`, deny `create_transfer`. |
| **Default deny** | Unknown tools fail closed. |
| **JIT escalation for high privilege** | Any future spend path is Yellow/Orange/Red with explicit re-authorization — never session-global “write mode.” |
| **Confused-deputy / static client ID** | If the service ever OAuth-proxies, consent and audience binding matter; for API-key custody we avoid OAuth to Qonto entirely. |
| **Audit end-to-end** | Actor (harness/agent id) + tool + args hash + decision + latency; no secrets in logs. |
### 2.3 Domain capability service (not “another harness”)
A second pattern, older than MCP: **BFF / capability API** for a domain
(banking, email, CRM). Agents call a **narrow, policy-shaped interface**
(“get runway snapshot”) rather than the full vendor surface. That is how
email-connect already behaves for IMAP: consumer never holds IMAP secrets
in the product path; it goes through custody + a purpose-built reader.
**llm-connect is the wrong home** for this: it is multi-provider **LLM**
abstraction (adapters, routing, cost models). Putting bank tools there
blurs the layer map (ARCHITECTURE-LAYERS.md) and couples finance policy to
model routing.
**agent-harness is the wrong home for Qonto policy itself**, but the right
home for *session* binding: harness ADR-001 already says the harness is the
credential holder and policy enforcement point **for agent sessions**. That
must not mean “each harness reimplements bank policy.” It means the harness
only grants agents a **named tool profile** that talks to **already-governed**
domain services. Domain policy lives **below** the harness.
### 2.4 Synthesis
| Pattern | Use for Qonto? |
| --- | --- |
| Wire vendor MCP into every harness | **No** — policy drift, key sprawl |
| Generic MCP gateway only (Envoy/Kong in front of vendor MCP) | **Partial** — good transport + tool filter; weak on **semantic** spend rules and finance-shaped tools |
| **A (preferred dogfood)** | New small service under Coulomb, e.g. `qonto-assistant` or generalize later to `finance-connect` | Clean boundary, productizable |
| **B** | Module inside a future `domain-connectors` monorepo | If many thin connectors share skeleton |
| **C** | Package under `binky-control` only | Too tenant-specific; resists reuse |
Start as **tenant-backed dogfood** with a clear INTENT that it may graduate
to a multi-tenant “governed bank connector” offer. Keep binky-control as
*consumer + policy source of business truth* (CostRunRate, AutonomyPolicy),
not as the runtime host long-term.
---
## 5. Alternatives considered
### 5.1 “Anchor policy at Qonto”
**Unavailable for our custody model.** Self-hosted MCP + API keys are not
fine-scoped. Hosted OAuth MCP is the corporate **anti-pattern** we already
rejected (credentials outside OpenBao, write tools bundled). Even with
OAuth, spend prevention would still need our gateway for defense in depth.
### 5.2 Generic MCP gateway only
**Good complement, insufficient alone.** Use later for fleet aggregation.
v1 needs **semantic** finance policy and a stable REST face for non-MCP
clients — easier as our service.
### 5.3 agent-harness-only enforcement
Harness tool profiles remain necessary (don’t hand agents unrestricted
network). But **bank policy must not live only there**: interactive Claude
on a laptop would bypass harness profiles unless it also only sees the
assistant endpoint. **Network/policy gravity toward the assistant.**
### 5.4 llm-connect as tool hub
Reject for layering reasons (LLM vs domain tools). Route models through
llm-connect; route **bank actions** through qonto-assistant.
each harness → auth to qonto-assistant → policy → Qonto
↑
single tool catalog + single deny rules
```
Checklist for any new harness:
1. Does **not** get `binky-qonto-api` bank secret.
2. Gets only assistant base URL + client credentials for `finance.qonto.read`.
3. Tool profile names assistant tools, not vendor tool names.
4. Offline/dev: point at assistant mock, not a copy of production key.
---
## 8. Risk register (architecture-level)
| Risk | Mitigation |
| --- | --- |
| Assistant is a high-value target | High-risk path already in agent-high-risk-boundary; no raw stream to coding agents; short-lived OpenBao tokens; network policy |
| Model jailbreak asks for transfer | Tool not registered + deny classes; never implement spend in v1 |
| Vendor adds new MCP write tools | We do not auto-mirror vendor catalog; allow-list is ours |
| Bypass via direct thirdparty from laptop | Platform policy + founder discipline; optional egress controls later; secrets not on laptops |
| Over-filtering legitimate finance work | Explicit allow tools + CostRunRate helpers; expand by policy PR with tests |