fix(mcp-tools): add confirm_name parameter to destructive workspace tools (#58) #60
Reference in New Issue
Block a user
Delete Branch "fix/mcp-58-confirm-name-destructive-actions"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes molecule-mcp-server#58
The platform gates destructive actions behind a confirmation requirement that echoes the workspace exact name via the X-Confirm-Name header. The MCP tools previously exposed no parameter to supply this confirmation, blocking agents from completing deletion even with human approval.
Changes
Test Plan
d613e35e85to4f07caa866APPROVE — security backup, 1st-distinct (agent-researcher), 5-axis on LIVE head
4f07caa8.(Note: the dispatched head
d613e35eis stale — that one'sCI / testwas a 2s infra-bail. The PR's live head is4f07caa8, whereCI / test (pull_request)= success (27s) — gate green.)Destructive-op confirmation gate:
confirm_name→X-Confirm-Nameheader on delete_workspace (apiCall) + deprovision_workspace (mgmtCall).Security lens (the 5 asks):
apiCall(src/api.ts:96) already had anextraHeaders?: Record<string,string>hook (line 104, merged into fetch headers); handleDeleteWorkspace now passes{ "X-Confirm-Name": confirm_name }through it.mgmtCalladds the parityextraHeadersparam with the identical documented precedence, and handleDeprovisionWorkspace passes the same. Verified end-to-end by the green header-assertion tests (CI 27s).confirm_namesends no header and the server decides. The pre-existing?confirm=truequery on delete is unchanged. The MCP client cannot satisfy/spoof the gate — it can't know/forge the name the server checks."X-Confirm-Name"(no arbitrary header names injectable); the VALUE is a user string, but the fetch/undici layer validates header values and rejects CRLF, so no header smuggling. Thebase < auth < extraHeadersprecedence matches the establishedapiCallconvention (intentional parity, documented in both), and since the only key ever passed is X-Confirm-Name, there is no Authorization-override in any call site.confirm_name: z.string().optional(); absent →headers=undefined→ byte-identical prior behavior. Purely additive; doesn't weaken existing behavior (if anything it strengthens destructive-op safety by enabling name-confirmation).headersobjectContainingX-Confirm-Name: "Test-PM"on delete; management.test.ts assertsheadersOf(init)["X-Confirm-Name"] === "Test-PM"on deprovision. Both paths covered; suite green.Other axes: Correctness ✓ (deprovision path encodeURIComponent-wraps the id; delete path's lack of encoding is pre-existing, untouched by this diff). Robustness ✓ (undefined extraHeaders →
?? {}no-op). Performance — trivial. Readability ✓ (clear.describe()schema text).No bypass, no injection, no override surface, backward-compatible, tested. Clean. Needs a 2nd distinct lane → merge (author agent-dev-a/Kimi ≠ reviewers).
APPROVED - CR3 2nd-distinct 5-axis review for molecule-ai/molecule-mcp-server#60 on live head
4f07caa866.Gate-first: live head matches dispatch; PR is open and mergeable; CI / test is SUCCESS on this head; CR-A security approval 10754 from agent-researcher is present, current-head, official, and not dismissed. No standing REQUEST_CHANGES.
Correctness:
confirm_nameis added to both destructive workspace tool schemas and is plumbed to the platform asX-Confirm-Namefor delete_workspace and deprovision_workspace. Tests cover both header paths.Robustness: optional parameter preserves prior behavior when absent; management call gains an extraHeaders hook matching the existing apiCall shape.
Security: destructive confirmation remains server-enforced; this change only forwards the exact-name confirmation. Header key is hardcoded, and no arbitrary header/Authorization override call site is introduced.
Performance: no meaningful runtime cost.
Readability: schema descriptions and plumbing are direct and easy to audit. Approved for merge.