subagents: add availableToSubagents opt-in toggle for extraMcpServers
This commit is contained in:
parent
33aa2bdbc8
commit
16eec3c314
14 changed files with 356 additions and 84 deletions
56
hive-subagent-mcp/src/mcp_config.rs
Normal file
56
hive-subagent-mcp/src/mcp_config.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
//! Builds a subagent's own filtered `--mcp-config`: only
|
||||
//! `hyperhive.extraMcpServers` entries with `availableToSubagents = true`
|
||||
//! (see `hive_extra_mcp::ExtraMcpServer::available_to_subagents`) ever reach
|
||||
//! a subagent's claude invocation. Everything else — the built-in hyperhive
|
||||
//! surface (todos/messaging), the auto-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<PathBuf> {
|
||||
let state_dir = crate::paths::state_dir();
|
||||
let servers: serde_json::Map<String, serde_json::Value> = hive_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)
|
||||
}
|
||||
Loading…
Reference in a new issue