QONTO-WP-0003-T07: close out Phase 2 MCP workplan
T01-T06 all done. Final end-to-end confirmation before closing: pytest -> 31 passed; both scripts/smoke_rest_api.py and scripts/smoke_mcp.py exit 0 against fixtures in the same run; compileall clean. REST/MCP policy-outcome parity is proven by test, not just asserted: test_policy_decision_identical_across_protocols (decide() never branches on transport) plus test_audit_parity.py (identical audit shape for the same capability call over both transports, allow and deny paths). Workplan status -> finished. Closure note records what shipped, the three known gaps carried forward (OIDC federation, header-based actor identity, unregistered agent-harness profile), and the Phase 3 seed. README updated to match. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
09300bd779
commit
ad500121f4
2 changed files with 73 additions and 15 deletions
36
README.md
36
README.md
|
|
@ -14,7 +14,8 @@ no spend, no volume-cost actions.**
|
|||
| [`INTENT.md`](INTENT.md) | Why this exists; boundaries |
|
||||
| [`specs/ArchitectureBlueprint.md`](specs/ArchitectureBlueprint.md) | Architecture, phases, policy model |
|
||||
| [`research/2026-07-21-mcp-gateway-and-governed-domain-assistant.md`](research/2026-07-21-mcp-gateway-and-governed-domain-assistant.md) | External + internal research |
|
||||
| [`docs/operator-runbook.md`](docs/operator-runbook.md) | How to run and verify Phase 1 |
|
||||
| [`docs/operator-runbook.md`](docs/operator-runbook.md) | How to run and verify Phase 1 (REST) |
|
||||
| [`docs/mcp-integration.md`](docs/mcp-integration.md) | How to run and verify Phase 2 (MCP) |
|
||||
|
||||
## Status
|
||||
|
||||
|
|
@ -26,24 +27,35 @@ Phase 1 runtime is implemented:
|
|||
- REST endpoints: `/v1/health`, `/v1/accounts`, `/v1/transactions`, `/v1/snapshot`
|
||||
- audit metadata, rate limiting, concurrency bounds, tests
|
||||
|
||||
Phase 2 (MCP surface, `workplans/QONTO-WP-0003-mcp-surface.md`) is in
|
||||
progress: a streamable-HTTP MCP adapter is mounted at `/mcp` on the same
|
||||
capability core and policy kernel as REST, with tools `qonto_org_summary`,
|
||||
`qonto_list_transactions`, and `qonto_cost_run_rate_hints`. The endpoint is
|
||||
gated by a shared-secret bearer token (`QONTO_ASSISTANT_MCP_TOKEN`) — see
|
||||
`docs/mcp-integration.md` for the auth model, its gap vs. the OIDC/workload
|
||||
target, and the shared multi-harness client config snippet. The
|
||||
`finance-qonto-read` tool profile is not yet implemented.
|
||||
Phase 2 (MCP surface, `workplans/QONTO-WP-0003-mcp-surface.md`) is
|
||||
**finished**: a streamable-HTTP MCP adapter is mounted at `/mcp` on the same
|
||||
capability core and policy kernel as REST — proven identical by test, not
|
||||
just by construction (`tests/test_policy.py`, `tests/test_audit_parity.py`)
|
||||
— with tools `qonto_org_summary`, `qonto_list_transactions`, and
|
||||
`qonto_cost_run_rate_hints`. The endpoint is gated by a shared-secret bearer
|
||||
token (`QONTO_ASSISTANT_MCP_TOKEN`); see `docs/mcp-integration.md` for the
|
||||
auth model, its explicit gap vs. the OIDC/workload target (no issuer exists
|
||||
in this fleet yet), and the shared multi-harness client config snippet. The
|
||||
`finance-qonto-read` agent-harness tool profile is documented (qonto-assistant
|
||||
side) but not yet registered in `agent-harness` itself — separate repo,
|
||||
separate workplan.
|
||||
|
||||
Current verification:
|
||||
|
||||
- `PYTHONPATH=src ../state-hub/.venv/bin/python -m pytest` → `16 passed`
|
||||
- `PYTHONPATH=src ../state-hub/.venv/bin/python -m pytest` → `31 passed`
|
||||
- `python3 -m compileall src tests scripts`
|
||||
- `../state-hub/.venv/bin/python scripts/smoke_rest_api.py --python ../state-hub/.venv/bin/python`
|
||||
- `../state-hub/.venv/bin/python scripts/smoke_mcp.py --python ../state-hub/.venv/bin/python`
|
||||
|
||||
Local fixture-backed smoke mode is available through `QONTO_FIXTURE_DIR`, so the
|
||||
service can be exercised without real Qonto credentials. The smoke path checks
|
||||
both a `31`-day recent snapshot and a `90`-day recurring-cost snapshot.
|
||||
service can be exercised without real Qonto credentials. The REST smoke checks
|
||||
both a `31`-day recent snapshot and a `90`-day recurring-cost snapshot; the MCP
|
||||
smoke additionally exercises the bearer-token auth gate and an out-of-catalog
|
||||
tool deny path.
|
||||
|
||||
Phase 3 (flex-auth resource `finance.qonto.read`, graduated quotas,
|
||||
redaction profiles) is not started — see `workplans/QONTO-WP-0003-mcp-surface.md`
|
||||
closure notes for the seed.
|
||||
|
||||
Normal local workflow, when toolchain support exists:
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ type: workplan
|
|||
title: "Phase 2 — MCP surface for all harnesses"
|
||||
domain: infotech
|
||||
repo: qonto-assistant
|
||||
status: active
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: the-custodian
|
||||
created: "2026-07-22"
|
||||
updated: "2026-07-22"
|
||||
updated: "2026-07-23"
|
||||
state_hub_workstream_id: "6ad0e906-5fbe-4b9e-8307-0abfc5c4a60a"
|
||||
---
|
||||
|
||||
|
|
@ -299,7 +299,7 @@ exits `0` against fixtures, no real Qonto credentials. `pytest` → `31 passed`
|
|||
|
||||
```task
|
||||
id: QONTO-WP-0003-T07
|
||||
status: todo
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "1dc90a1e-0dcc-40c1-80c9-c7403a348db0"
|
||||
```
|
||||
|
|
@ -308,3 +308,49 @@ Mark workplan finished when T01–T06 are done; confirm REST and MCP surfaces
|
|||
enforce identical policy outcomes end to end. Note Phase 3 seed (flex-auth
|
||||
resource `finance.qonto.read`, graduated quotas, redaction profiles) in
|
||||
closure. Run `statehub fix-consistency`.
|
||||
|
||||
**Closed 2026-07-23.** T01–T06 all done. Final end-to-end confirmation
|
||||
before closing: `pytest` → `31 passed`; `scripts/smoke_rest_api.py` and
|
||||
`scripts/smoke_mcp.py` both exit `0` against fixtures in the same run;
|
||||
`python3 -m compileall src tests scripts` clean.
|
||||
|
||||
**Identical policy outcomes, confirmed two ways, not asserted:**
|
||||
`tests/test_policy.py::test_policy_decision_identical_across_protocols`
|
||||
(T01) proves `PolicyEngine.decide()` never branches on `protocol` at the
|
||||
unit level, and `tests/test_audit_parity.py` (T05) proves the resulting
|
||||
audit events are schema-identical for the same capability call over both
|
||||
transports, for both an allow and a deny path. Both REST and MCP call
|
||||
through the same `CapabilityService._execute` → `PolicyEngine.decide()`
|
||||
path — there is structurally no second policy implementation to drift.
|
||||
|
||||
**What Phase 2 shipped:** streamable-HTTP MCP adapter mounted at `/mcp`
|
||||
(T01); three capability tools — `qonto_org_summary`,
|
||||
`qonto_list_transactions`, `qonto_cost_run_rate_hints` — mapped 1:1 to the
|
||||
existing REST-allowed capabilities, `snapshot_bundle` deliberately not
|
||||
mirrored as it isn't a separate privilege (T02); shared-secret bearer-token
|
||||
workload auth (`QONTO_ASSISTANT_MCP_TOKEN`) plus one client config snippet
|
||||
covering Claude Code/Desktop/Cursor/Codex-style harnesses, with the real
|
||||
OIDC/workload-identity gap called out explicitly rather than faked (T03);
|
||||
the qonto-assistant-side contract for agent-harness's `finance-qonto-read`
|
||||
tool profile, checked against the real `agent_harness/profiles.py` schema
|
||||
(T04); REST/MCP audit-schema parity pinned by test (T05); an MCP smoke
|
||||
script exercising the full tool catalog, the auth gate, and the
|
||||
out-of-catalog deny path against fixtures with no real credentials (T06).
|
||||
|
||||
**Known gaps carried forward, not closed by this workplan:**
|
||||
- Real OIDC/workload-identity federation (no issuer exists in this fleet —
|
||||
see `docs/mcp-integration.md`'s auth model section). The bearer token is
|
||||
a deployable interim, not the blueprint's target state.
|
||||
- Per-actor identity (`X-Actor-*` headers) is still self-asserted, not
|
||||
cryptographically bound to the workload-auth token.
|
||||
- `finance-qonto-read` is documented but not registered in
|
||||
`agent-harness/agent_harness/profiles.py` — that's agent-harness's own
|
||||
repo/workplan to pick up.
|
||||
|
||||
**Phase 3 seed** (`specs/ArchitectureBlueprint.md` §6 Phase 3, not started):
|
||||
a flex-auth resource `finance.qonto.read` (+ later `.export`) to bind actor
|
||||
identity to the workload-auth layer instead of self-asserted headers;
|
||||
graduated quotas and differentiated response-redaction profiles; optional
|
||||
Envoy/gateway mesh in front for multi-assistant deployments. The
|
||||
`QONTO_ASSISTANT_REQUIRED_SCOPE`/`QONTO_ASSISTANT_ENFORCE_SCOPE` settings
|
||||
already exist in `config.py` as the landing spot for that scope name.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue