When the user connects an MCP server (filesystem, GitHub, database, etc.) and the AI calls a tool with side effects, kestrel today relies on the user's Claude Desktop-compatible config to decide what's allowed. There's no central trail of which tools were invoked, no habit-learning, no cross-device policy.
Platform's `approvals` service (`evalops/platform/internal/approvals/`) already solves this for every other consumer — `ensemble` routes through it, `chat` uses the ConnectRPC external client, and even `maestro` has an open issue (`evalops/maestro-internal#1350`) to stop using its local service and route through platform.
Ask
When `KESTREL_APPROVALS_BASE` + `KESTREL_APPROVALS_TOKEN` are set, gate MCP tool calls through `approvals.v1.ApprovalService/RequestApproval`:
- Request carries `agent_id = "kestrel-mcp-client"`, `action = <tool_name>`, `risk_level` inferred from tool schema (read → LOW, write → MEDIUM, destructive → HIGH)
- Blocking wait for decision; surface in the Electron UI as a modal with full context (tool name, arguments, server name)
- Habit-learning on the platform side means repeat-approved patterns auto-approve after N observations
Offline fallback: when platform is unreachable, fall back to today's prompt-on-first-use flow with an `approvals_offline_total` metric so ops see when it happens.
Related
- evalops/maestro-internal#1350 — same exact ask; kestrel + maestro should share the pattern
- evalops/platform#618 — habit Bayesian upgrade; kestrel approvals would flow into it
- evalops/platform#547 — governance flywheel; dev-tool approvals are the richest training signal
Scope
~3 days if written in parallel with the maestro-internal PR (shared client pattern).
When the user connects an MCP server (filesystem, GitHub, database, etc.) and the AI calls a tool with side effects, kestrel today relies on the user's Claude Desktop-compatible config to decide what's allowed. There's no central trail of which tools were invoked, no habit-learning, no cross-device policy.
Platform's `approvals` service (`evalops/platform/internal/approvals/`) already solves this for every other consumer — `ensemble` routes through it, `chat` uses the ConnectRPC external client, and even `maestro` has an open issue (`evalops/maestro-internal#1350`) to stop using its local service and route through platform.
Ask
When `KESTREL_APPROVALS_BASE` + `KESTREL_APPROVALS_TOKEN` are set, gate MCP tool calls through `approvals.v1.ApprovalService/RequestApproval`:
Offline fallback: when platform is unreachable, fall back to today's prompt-on-first-use flow with an `approvals_offline_total` metric so ops see when it happens.
Related
Scope
~3 days if written in parallel with the maestro-internal PR (shared client pattern).