feat(workspaces): fail-closed provision_workspace MCP tool [carried from molecule-mcp-server#19] #1
Reference in New Issue
Block a user
Delete Branch "mcp-server-pr19/provision-workspace-tool-failclosed"
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?
Carried from molecule-mcp-server#19 as part of task #325 monorepo consolidation (CTO directive 2026-05-20).
Original author: hongming.
Source-side PR will be closed pointing here once this lands.
Files land under
server/via -X subtree=server merge strategy. Author history preserved.Adds a `provision_workspace` MCP tool so an agent can provision a workspace with a GUARANTEED runtime (claude-code/codex/hermes/openclaw/ langgraph/autogen/crewai/deepagents) via the correct PRODUCT create path (POST /workspaces with template+runtime) — not the CP-direct /cp/workspaces/provision path the orchestrator was forced to use. Enforces the same fail-closed contract as molecule-controlplane#188 on the agent-facing surface: 1. Validate runtime against the supported set BEFORE any side effect. 2. Create via the product path (template drives config/image). 3. Read the workspace back and assert resolved runtime == requested; return a structured RUNTIME_MISMATCH/PROVISION_UNVERIFIED error (NOT a success) if the platform silently fell back to langgraph. This makes the agent surface honest now; it does NOT replace the required platform-side hard-gate (controlplane#188 + its workspace- server sibling — each adapter stays runtime-specific, the platform is the unified SSOT that must error+notify, never silent-advisory). Refs: molecule-controlplane#188, #184 (CP-direct vs product-create fidelity gap). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Extends the fail-closed provision_workspace tool with an optional role_config { model, config_yaml } block so "create + apply-role-config + read-back-assert" is ONE fail-closed operation instead of two separate, skippable steps. Motivation (#218 prod-team defect): the 5 prod-team workspaces were provisioned with the correct runtime but template-default role config (generic name, Sonnet instead of the role's model, empty charter) because per-role config was never applied as part of provisioning. Mechanism (source-verified against molecule-core workspace-server): - model -> PUT /workspaces/:id/model (writes MODEL_PROVIDER workspace_secret; authoritative over config.yaml runtime_config.model per the claude-code adapter resolution order; auto-restarts). The effective model is read back via GET /workspaces/:id/model and ASSERTED == requested; a write-ack is never trusted as success. - config.yaml -> PUT /workspaces/:id/files/config.yaml (name, description/charter, runtime_config.model, required_env; written via EIC to the workspace EC2 + auto-restarts). NOT read-back-asserted due to the documented PUT/GET path asymmetry (molecule-core tests/e2e/test_staging_full_saas.sh) — the model read-back is the authoritative effective-config gate. Fail-closed surface: ROLE_CONFIG_FAILED (write error, with phase), ROLE_CONFIG_MODEL_MISMATCH (effective model != requested after read-back). role_config_applied is always present in the result so a caller cannot mistake a runtime-only provision for a fully-configured role. Tests: +3 (success path, model-mismatch fail-closed, role_config absent). Full suite green: 136 passed, 1 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>REQUEST_CHANGES
5-axis review:
Correctness: The core fail-closed guarantee is bypassed for
external,kimi, andkimi-cli. After read-back,requestedIsByodisables the mismatch check entirely, so a request forkimi/kimi-cli/externalthat is silently provisioned aslanggraphwill still return{ ok: true, provisioned: true }. That is the exact class of silent fallback this tool is meant to prevent. Please only allow documented/intentional normalization values for BYO runtimes, and still fail when the resolved runtime is unrelated, especiallylanggraph.Robustness: Unsupported runtime validation before side effects is good, and the role-config model read-back is a useful guard. The BYO mismatch skip makes the most important verification non-idempotently misleading because the wrong workspace already exists.
Security: No new auth or secret handling issue found.
Performance: One create plus bounded read-back/config calls is acceptable for provisioning.
Readability: The handler is well documented, but the BYO comment does not justify accepting any resolved runtime as success.
Approved. Verified CI / all-required is green. The provision_workspace tool validates supported runtimes before side effects, creates through the product workspace path, read-back asserts the resolved runtime, and read-back asserts role_config model application; tests cover unsupported runtime, fallback mismatch, unverifiable runtime, BYO runtime, and model mismatch paths.
REQUEST_CHANGES on head
34aa762f. The fail-closed runtime guarantee is still bypassed for BYO-labeled runtimes: requestedIsByo skips the resolvedRuntime !== runtime check for external/kimi/kimi-cli. That allows a request for kimi or kimi-cli to read back langgraph (or any other non-empty runtime) and still return ok=true/provisioned=true, which is the same silent-fallback class this tool is meant to prevent. Please keep any deliberate external normalization narrowly scoped and add regression coverage that kimi/kimi-cli mismatches fail closed.New commits pushed, approval review dismissed automatically according to repository settings
APPROVED fixed head
fce9b035. The prior fail-closed blocker is resolved: runtime matching now uses a narrow allowedResolvedRuntimes map, with empty-string normalization scoped only to external, and kimi/kimi-cli requiring exact resolved runtime. Regression tests assert kimi, kimi-cli, and external return RUNTIME_MISMATCH/provisioned=false on langgraph fallback. No additional correctness/security/perf/readability blockers found.