mcp door: extend service-session bearer to per-topic + per-loop spawns
ci / gates (push) Successful in 5s
ci / rust (push) Failing after 9s
ci / frontend (push) Successful in 27s
ci / e2e (push) Skipped
ci / publish (push) Skipped

Per-team runtimes had their MCP bearer swap wired in the prior slice,
but per-topic (research_container::spawn) and per-loop (spawn_loop)
containers still baked the stale template bearer and 401'd every
tools/list. Same fix, extended: mint a workspace-owner service session
via runtime_provision::mint_workspace_service_token and inject via
prewrite_daemon_config_with_risk.

Move mint_workspace_service_token from topology_worker into
runtime_provision so all three spawn call sites share the helper.

Callers updated: routes/research.rs (start_topic), routes/research_setup.rs
(prepare_topic_runtime), routes/loops.rs (ensure_loop_container).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
Omar Sobh
2026-07-18 16:14:38 -07:00
co-authored by Claude Opus 4.7
parent 6504ed6062
commit 657b666219
6 changed files with 82 additions and 24 deletions
+1 -19
View File
@@ -681,7 +681,7 @@ async fn try_team_gateway_url(
// clawmates_door MCP calls pass cm-auth (the static bearer baked
// into the template config isn't a valid auth_sessions row and
// gets 401'd, leaving every agent with 0 tools).
let mcp_bearer = mint_workspace_service_token(pool, workspace_id)
let mcp_bearer = crate::runtime_provision::mint_workspace_service_token(pool, workspace_id)
.await
.map_err(|e| {
eprintln!("try_team_gateway_url: mint MCP bearer failed for team {team_id}: {e}");
@@ -720,21 +720,3 @@ async fn try_team_gateway_url(
Some(spawned.gateway_url)
}
/// Mint a long-lived session token for the workspace owner. Used to
/// authorize internal service callers (e.g. per-team ZeroClaw runtimes
/// hitting our clawmates_door MCP endpoint) without threading a real
/// user session through the runtime template.
async fn mint_workspace_service_token(
pool: &PgPool,
workspace_id: WorkspaceId,
) -> Result<String, String> {
let owner = cm_db::repo::users::owner_of_workspace(pool, workspace_id)
.await
.map_err(|e| format!("owner_of_workspace: {e}"))?;
let auth = cm_auth::AuthService::new(pool.clone());
let token = auth
.mint_service_session(owner, time::Duration::days(30))
.await
.map_err(|e| format!("mint_service_session: {e}"))?;
Ok(token.secret().to_string())
}