From 305c764cf1412518151c54acfeeec94bead951be Mon Sep 17 00:00:00 2001 From: arpan Date: Tue, 15 Sep 2026 05:28:41 +0530 Subject: [PATCH] The gateway's 41002 example was stale, and understated what the client does The documented error said `mcp.ops.delete_namespace: a human must approve`. The gateway actually emitted the decorator's wording, telling an MCP client to retry inside `ctrlrun.with_approval(...)`, a Python context manager it has no access to. The kernel PR fixes the message; this fixes the example, and adds the `data` fields the gateway really sends. The prose already said the right thing, that the agent's next identical call runs. It now says explicitly that there is nothing for the client to do differently, because that is the sentence whose absence let the wrong error text look plausible for four milestones. Signed-off-by: arpan --- docs/mcp/gateway-in-5-minutes.mdx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/mcp/gateway-in-5-minutes.mdx b/docs/mcp/gateway-in-5-minutes.mdx index 2e960a4..bbe28aa 100644 --- a/docs/mcp/gateway-in-5-minutes.mdx +++ b/docs/mcp/gateway-in-5-minutes.mdx @@ -73,14 +73,23 @@ accepts `2025-11-25`, `2025-06-18` and `2025-03-26`. ```json {"jsonrpc": "2.0", "id": 13, - "error": {"code": -41002, "message": "mcp.ops.delete_namespace: a human must approve", - "data": {"error": "ctrlrun.approval_required", "request_id": "apr_…"}}} + "error": {"code": -41002, + "message": "mcp.ops.delete_namespace requires approval: a human runs + 'ctrlrun approve apr_…', then this same call runs", + "data": {"error": "ctrlrun.approval_required", "request_id": "apr_…", + "action_hash": "sha256:…", "expires_at": "…"}}} ``` A human runs `ctrlrun approve apr_…`, or answers in Slack through the webhook, and the agent's next identical call runs. A different call, a different namespace, a different cluster, does not: the approval is bound to the hash of what the human saw. + **There is nothing for the client to do differently on the retry.** It re-sends the same + `tools/call`. The decorator has a second step here -- `ctrlrun.with_approval(...)` -- and + this path does not, because the gateway finds the granted approval by the action's hash. + Until v0.12 the error text said otherwise: it carried the decorator's wording verbatim and + sent clients, in any language, looking for a Python context manager. + | Code | Token | HTTP | Meaning | |---|---|---|---| | `-41001` | `ctrlrun.denied` | 403 | the policy denies this action for everyone |