//! Builds a subagent's own filtered `--mcp-config`: only //! `hyperhive.extraMcpServers` entries with `availableToSubagents = true` //! (see `hive_agent_sock::extra_mcp::ExtraMcpServer::available_to_subagents`) ever reach //! a subagent's claude invocation. Everything else — the built-in hyperhive //! surface (todos/messaging), the automatically injected `bash` and `subagent` //! entries — stays unreachable by construction: none of those default to //! opted in, and the built-in surface isn't an `extraMcpServers` entry at //! all, so there's no name for an operator to opt it in under even if they //! wanted to. use std::path::PathBuf; /// Filename the rendered config lives at, under [`crate::paths::harness_dir`]. const CONFIG_FILE: &str = "subagent-mcp-config.json"; /// Render the subagent-eligible extra-MCP servers to a `--mcp-config` file, /// returning its path — or `None` when no entry opts in (or the render/write /// fails), so [`hive_claude::Config::mcp_config`] stays unset and the /// subagent gets literally zero MCP servers, the same default as before this /// toggle existed. Re-rendered on every call (cheap: a filter plus a small /// file write) rather than cached once at daemon startup, so a config change /// takes effect on this subagent's next `start`/`continue` without needing /// the daemon itself restarted. #[must_use] pub fn build() -> Option { let state_dir = crate::paths::state_dir(); let servers: serde_json::Map = hive_agent_sock::extra_mcp::load_extra_mcp() .into_iter() .filter(|(_, spec)| spec.available_to_subagents()) .map(|(name, spec)| (name, spec.to_json_entry(&state_dir))) .collect(); if servers.is_empty() { return None; } let body = serde_json::to_string_pretty(&serde_json::json!({ "mcpServers": servers })) .unwrap_or_else(|_| "{}".into()); let dir = crate::paths::harness_dir(); if let Err(e) = std::fs::create_dir_all(&dir) { tracing::warn!( error = ?e, dir = %dir.display(), "subagent mcp-config: harness dir create failed; subagent gets zero extra MCP servers this turn", ); return None; } let path = dir.join(CONFIG_FILE); if let Err(e) = std::fs::write(&path, body) { tracing::warn!( error = ?e, path = %path.display(), "subagent mcp-config: write failed; subagent gets zero extra MCP servers this turn", ); return None; } Some(path) }