feat(mcp): respond to / resolve Operator Queue items over MCP (#1104, #1101 follow-up)#1125
Merged
Merged
Conversation
…ver MCP (#1104) #1101 shipped the read half of the operator-queue MCP surface and deferred the write/respond half. This is that follow-up: agents and external Claude Code clients can now close the loop — answer questions, approve/deny approval requests — on items they can already read, completing raise → observe → respond and finishing Invariant #13 for OPS-001. - New `respond_to_operator_queue` tool (`tools/operator_queue.ts`): resolves the item's agent_name via get first, applies the SAME MCP-layer checkAgentAccess gate as the read tools ({self} ∪ permitted — the backend resolves an agent key to its owner and does NOT apply agent_permissions), then proxies POST /api/operator-queue/{id}/respond. Backend 400 on a non-pending item is surfaced as a structured { error }, not a throw. - `respondToOperatorQueueItem` client method (`client.ts`). - 4 unit tests: deny-on-non-permitted (and never writes), self-resolve proxies the body, permitted non-self resolve, 400→structured error. - architecture.md operator-queue row: read-only → read + respond (2→3 tools). v1 scope: `respond` only; `cancel` deferred (wider blast radius). No backend changes — thin TS proxy over the existing REST route. Verified: tsc clean; 20/20 mcp-server tests; tool + client method compiled into the running container's dist and auto-registered. Related to #1104 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Author
🔎 Code review (high-effort, recall-biased) — no blocking bugsFaithful mirror of the verified #1101 read-tool pattern; clean. No correctness bugs survived verification. Verified
Non-blocking notes
✅ Ready to merge. Reviewed with the |
|
Resolve by running |
# Conflicts: # docs/memory/architecture.md
vybe
approved these changes
Jun 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
#1101 shipped the read half of the operator-queue MCP surface (
list_operator_queue,get_operator_queue_item) and explicitly deferred respond/resolve to a follow-up. This is that follow-up: agents and external Claude Code clients can now resolve Operating Room items — answer questions, approve/deny approval requests — closing the raise → observe → respond round-trip and finishing Invariant #13 (MCP = third surface in sync) for OPS-001.Changes
tools/operator_queue.ts— newrespond_to_operator_queuetool. Resolves the item'sagent_nameviagetfirst (so the gate has a target + surfaces 404 cleanly), applies the samecheckAgentAccessgate as the read tools, then proxiesPOST /api/operator-queue/{id}/respond. Backend 400 on a non-pendingitem → structured{ error }, not a throw.client.ts—respondToOperatorQueueItem(id, {response, response_text}).server.ts— registration comment (auto-registered viaaddAllTools).operator_queue.test.ts— 4 tests.architecture.md— operator-queue row: read-only → read + respond (2 → 3 tools).Access control (the crux)
The backend resolves an agent-scoped key to its owner and does NOT apply
agent_permissions(architecture §5) — so agent-to-agent gating lives in the MCP layer. The write tool resolvesagent_name, then runs the identicalcheckAgentAccessthe read tools use: an agent-scoped key may resolve items for{self} ∪ permittedonly. On denial the write is never attempted (pinned by a test).Design decisions (per the issue)
respondonly in v1;canceldeferred (wider blast radius).pending-state; type-restricting which items an agent may resolve can be a later refinement if needed.Acceptance criteria
respond_to_operator_queueproxiesPOST /{id}/respondwithresponse(required) + optionalresponse_text.checkAgentAccess({self} ∪ permitted).agent_namebefore gating.{ error }.cancel— intentionally deferred.Verification
npx tsc --noEmitclean.respond_to_operator_queue) + client method (respondToOperatorQueueItem) compiled into the running container'sdistand auto-registered.Related to #1104
🤖 Generated with Claude Code