Commit graph

25 commits

Author SHA1 Message Date
0dc001bf53 QONTO-WP-0003-T06: MCP smoke script + operator runbook update
Add scripts/smoke_mcp.py, same shape as smoke_rest_api.py (random port,
subprocess-launch against QONTO_FIXTURE_DIR, wait on /v1/health, assert,
clean teardown), but goes further: generates a fresh
QONTO_ASSISTANT_MCP_TOKEN per run and connects through it with the mcp
SDK's streamablehttp_client, so the smoke exercises T03's bearer-token gate
instead of bypassing it. Lists tools, calls all four, and confirms an
out-of-catalog tool name comes back as a normal isError result through the
real wire protocol rather than a crash.

Extend docs/operator-runbook.md with a "One-command MCP smoke" section next
to the REST one; cross-link from docs/mcp-integration.md's manual smoke
walkthrough so the two don't drift.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 11:04:39 +02:00
c1e33decd9 chore(consistency): sync WORK-RECORDS.md for QONTO-WP-0003-T05 [auto]
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 11:01:45 +02:00
custodian-sync
5cd348ffbb chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-23:
  - update .custodian-brief.md for qonto-assistant
2026-07-23 11:01:33 +02:00
c3e69373ca QONTO-WP-0003-T05: pin REST/MCP audit-schema parity with a test
CapabilityService._emit_audit was already the single audit call site for
both transports since T02, but nothing failed if a future change diverged
one transport's shape. Add tests/test_audit_parity.py: same capability
called through protocol="rest" and protocol="mcp" (allow path and deny
path) must produce identical audit events except request_id/timestamp/
latency_ms (expected to vary) and protocol (expected to differ). Also pins
down that no audit event ever contains a secret-shaped field name.

Confirmed via grep: no State Hub coupling anywhere in src/qonto_assistant/
-- the only audit sink is AuditLogger, so there's no per-call hot-path
write to accidentally wire up.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 11:01:16 +02:00
0b268faf05 chore(consistency): sync WORK-RECORDS.md for QONTO-WP-0003-T04 [auto]
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 09:49:05 +02:00
custodian-sync
5fa5c02598 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-23:
  - update .custodian-brief.md for qonto-assistant
2026-07-23 09:48:55 +02:00
1e476309a3 QONTO-WP-0003-T04: document finance-qonto-read tool profile contract
qonto-assistant's side only, per task scope: the contract a profile named
finance-qonto-read must satisfy in agent-harness (~/agent-harness, ADR-001,
ToolProfile) to reach this MCP surface -- lane (green/blue, never red), the
exact mcp__qonto-assistant__* allowed-tools list, and the optional
finance.qonto.read scope.

Checked agent-harness/agent_harness/profiles.py directly: only CLI-only
profiles exist today (green-commit-only, blue-mail-triage), none grant an
MCP server yet. Included a ready-to-paste ToolProfile entry matching its
actual schema, marked as a proposal for agent-harness's own PR -- not
applied here, since registering it is a separate repo/workplan. Added the
end-to-end example: instance manifest -> harness-injected MCP server config
-> the four allowed tool calls.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 09:48:36 +02:00
b96b8cd5b3 chore(consistency): sync WORK-RECORDS.md for QONTO-WP-0003-T03 [auto]
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 09:41:49 +02:00
custodian-sync
eb5ca29ba7 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-23:
  - update .custodian-brief.md for qonto-assistant
2026-07-23 09:41:43 +02:00
d2ffd372b5 QONTO-WP-0003-T03: MCP client auth + shared multi-harness config snippet
Gate /mcp with a shared-secret bearer token (QONTO_ASSISTANT_MCP_TOKEN,
mcp_auth.py::BearerTokenAuthMiddleware, constant-time compare, REST
untouched) since no OIDC issuer exists in this fleet yet -- pointing
FastMCP's OAuth Protected Resource flow at a non-existent issuer would be
worse than not having it. This token is a service credential, never a bank
credential; per-actor identity stays the existing X-Actor-* convention.

Add docs/mcp-integration.md: tool catalog, the two-layer auth model (workload
auth today vs. deferred OIDC target), and one shared {"mcpServers": {...}}
client config snippet (url + headers) usable across Claude Code, Claude
Desktop, Cursor, and Codex/Grok-style harnesses.

Verified live using only that snippet: unauthenticated and wrong-token
requests get 401 before reaching any tool; a request built from the
snippet's URL + headers lists tools and calls qonto_org_summary
successfully against the fixture-backed server.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 09:41:25 +02:00
e1e47ae304 chore(consistency): sync WORK-RECORDS.md for QONTO-WP-0003-T02 [auto]
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 21:48:40 +02:00
custodian-sync
35b68290aa chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-22:
  - update .custodian-brief.md for qonto-assistant
2026-07-22 21:48:26 +02:00
b4b1dc1c7b QONTO-WP-0003-T02: MCP tool catalog on the shared capability core
Add qonto_org_summary, qonto_list_transactions, and qonto_cost_run_rate_hints
MCP tools, all routed through CapabilityService with protocol="mcp" -- same
PolicyEngine.decide() path as REST, same deny-reason vocabulary. Skip
snapshot_bundle as an MCP tool (REST already covers the composite read; not
a separate privilege).

CapabilityService now threads protocol through _execute/_emit_audit instead
of hardcoding "rest". cost_run_rate_hints gets its own service method since
it's an independent policy capability, not only a snapshot sub-field.

Actor identity reuses REST's X-Actor-* header convention via a shared
auth.actor_claims_from_headers(), read from the MCP Context's request when
present. Fixed streamable_http_path defaulting to "/mcp", which doubled to
"/mcp/mcp" once mounted under the "/mcp" prefix.

Verified end-to-end with the mcp SDK's streamablehttp_client against the
live fixture-backed server: tool list, allow/deny paths, and X-Actor-ID
flowing through to the audit log exactly like REST.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 21:48:09 +02:00
ba2612682f chore(consistency): sync WORK-RECORDS.md for QONTO-WP-0003-T01 [auto]
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 21:41:54 +02:00
custodian-sync
3827cb722c chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-22:
  - update .custodian-brief.md for qonto-assistant
2026-07-22 21:41:42 +02:00
d4656be310 QONTO-WP-0003-T01: MCP adapter skeleton on shared capability core
Add a streamable-HTTP MCP adapter (mcp_server.py, official FastMCP SDK)
mounted at /mcp in the existing FastAPI app, with a combined lifespan so
the MCP session manager starts/stops with the service. Ships one smoke
tool (qonto_ping, no bank call) — real capability tools land in T02.

Prove REST and MCP hit the identical policy path: PolicyEngine.decide()
never branches on request.protocol, verified by a parametrized test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 21:41:24 +02:00
dc3431cda0 chore(consistency): register QONTO-WP-0003 in State Hub [auto]
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 21:37:10 +02:00
custodian-sync
49e3b657a1 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-22:
  - update .custodian-brief.md for qonto-assistant
2026-07-22 21:37:00 +02:00
d643e552f4 Draft QONTO-WP-0003: Phase 2 MCP surface workplan
Streamable-HTTP MCP adapter on the same capability core and policy kernel
as Phase 1's REST surface, per specs/ArchitectureBlueprint.md Phase 2.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 21:36:38 +02:00
ca12843013 Complete Phase 1: policy kernel, REST service, and local smoke tooling
Implements QONTO-WP-0002 (policy-gated Qonto REST service with audit
logging, rate limiting, and credential handling) and the ADHOC-2026-07-21
follow-up (fixture-backed local smoke mode, repo classification metadata).
Marks QONTO-WP-0001/0002 and the ad-hoc workplan finished, and regenerates
WORK-RECORDS.md and the ADHOC workplan's state_hub_workstream_id via
fix-consistency.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 21:21:05 +02:00
custodian-sync
eef408bb19 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-22:
  - update .custodian-brief.md for qonto-assistant
2026-07-22 01:08:02 +02:00
67a5b01e08 Seeded intent and initial workplan 2026-07-22 00:31:50 +02:00
e1ab23f83e Bootstrap qonto-assistant: intent, blueprint, research, workplans
Author INTENT and SCOPE; persist ArchitectureBlueprint under specs/ and MCP
gateway research under research/. Register with State Hub (QONTO-WP- prefix);
seed QONTO-WP-0001 (bootstrap, finished) and QONTO-WP-0002 (Phase 1 REST
policy kernel, ready).
2026-07-21 23:32:24 +02:00
custodian-sync
bae0734564 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-21:
  - update .custodian-brief.md for qonto-assistant
2026-07-21 23:31:46 +02:00
1b98395160 Initial commit 2026-07-21 21:19:44 +00:00