Make the supervise MCP non-blocking (async approval + proposal polling) #412

Closed
opened 2026-07-18 13:20:10 -04:00 by didericis-claude · 0 comments
Collaborator

Problem

The per-bottle supervise MCP server (supervise_server.py) handles tools/call synchronously: it writes the proposal to the queue and blocks the agent's tool call polling for the operator's response (handle_tools_call -> wait_for_response, default 30s grace via SUPERVISE_RESPONSE_TIMEOUT_SECONDS). On timeout it returns status: pending and leaves the proposal queued -- but the agent gets no proposal id back and there is no way to poll a specific pending proposal, so its only option is to re-propose, creating duplicates.

This blocks two things:

  • The planned web-console human-review flow (RBAC, audit, mobile) where a reviewer may take minutes-to-hours -- far longer than any connection should stay open.
  • General robustness: a long-blocking tool call ties up the agent, risks tripping the MCP client's own tool-call timeout, and couples review latency to an HTTP request's lifetime.

Enforcement is unaffected either way -- the MCP tools only propose policy; the egress proxy / git-gate still enforce -- so returning early opens no hole.

Proposal (this issue)

Make the supervise MCP non-blocking and pollable:

  1. Include the proposal_id in the pending response so the agent can reference it.
  2. Add a check-proposal MCP tool: non-blocking status lookup by proposal id (pending | approved | modified | rejected), so the agent resumes after an async decision instead of re-proposing.
  3. Keep the short synchronous grace window for the "operator is right there" fast path.

Follow-ups (tracked, not in this PR)

  • git-gate pre-receive path: reject-fast + re-push instead of holding the push open (it cannot poll).
  • Backpressure: per-bottle in-flight-proposal cap to replace the halt that blocking gave for free.
  • MCP server->client notifications to drop polling entirely.

PRD to follow in the implementing PR.

## Problem The per-bottle supervise MCP server (`supervise_server.py`) handles `tools/call` **synchronously**: it writes the proposal to the queue and blocks the agent's tool call polling for the operator's response (`handle_tools_call` -> `wait_for_response`, default 30s grace via `SUPERVISE_RESPONSE_TIMEOUT_SECONDS`). On timeout it returns `status: pending` and leaves the proposal queued -- but the agent gets **no proposal id** back and there is **no way to poll a specific pending proposal**, so its only option is to re-propose, creating duplicates. This blocks two things: - The planned **web-console human-review flow** (RBAC, audit, mobile) where a reviewer may take minutes-to-hours -- far longer than any connection should stay open. - General robustness: a long-blocking tool call ties up the agent, risks tripping the MCP client's own tool-call timeout, and couples review latency to an HTTP request's lifetime. Enforcement is unaffected either way -- the MCP tools only *propose* policy; the egress proxy / git-gate still enforce -- so returning early opens no hole. ## Proposal (this issue) Make the supervise MCP non-blocking and pollable: 1. Include the `proposal_id` in the `pending` response so the agent can reference it. 2. Add a `check-proposal` MCP tool: non-blocking status lookup by proposal id (pending | approved | modified | rejected), so the agent resumes after an async decision instead of re-proposing. 3. Keep the short synchronous grace window for the "operator is right there" fast path. ## Follow-ups (tracked, not in this PR) - git-gate `pre-receive` path: reject-fast + re-push instead of holding the push open (it cannot poll). - Backpressure: per-bottle in-flight-proposal cap to replace the halt that blocking gave for free. - MCP server->client notifications to drop polling entirely. PRD to follow in the implementing PR.
didericis-claude added the Kind/Enhancement label 2026-07-18 13:20:10 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: didericis/bot-bottle#412