remove the get_host_journal MCP tool and its capability
swarm-logs covers every host-tier unit this tool could reach, so the second, capability-gated path into host journald earns nothing and is removed outright rather than disabled behind a flag. Removed end to end: the MCP tool definition + handler, the GetHostJournal/HostJournal wire variants, hive-c0re's dispatch_host_journal handler, the ReadHostJournal capability, and the harness-side capability->--allowedTools gate. get_host_journal was the only capability that mapped to an MCP tool, so allowed_capability_tools could only ever return an empty vec; it goes too rather than linger as a function that provably does nothing. capabilities::has_cap/caps_for stay: #4624 gave ManageRootAgent's bind-mount enforcement (hive-c0re/src/lifecycle/host_config.rs) a second caller of has_cap, so they're no longer callerless once this lands on top of it. hive-sh4re's journal module (JournalPriority) had no consumer outside this tool and is deleted. An existing capabilities.json still naming read_host_journal does not error: capabilities::prune_unknown drops unrecognised names with a warn!, and an agent left with no capabilities has its entry removed. No migration step is needed. Untouched: hive-c0re/src/dashboard/journal.rs's read_host_journal_response, which matches the name but is the private helper behind the operator-only GET /api/journal-host dashboard route and carries no capability check.
This commit is contained in:
parent
eec908bdb7
commit
11097ed336
18 changed files with 21 additions and 401 deletions
|
|
@ -30,37 +30,6 @@ pub const DEFAULT_MCP_HTTP_PORT: u16 = 8790;
|
|||
/// drift.
|
||||
pub use hive_sh4re::permissions::{builtin_tools_arg, effective_tool_groups};
|
||||
|
||||
/// `HIVE_CAPABILITIES` env var injected by `meta::render_flake` when the
|
||||
/// operator grants capabilities to this agent. Comma-separated
|
||||
/// `hive_sh4re::permissions::Capability` `snake_case` names. Absent = no extra capabilities.
|
||||
const CAPABILITIES_ENV: &str = "HIVE_CAPABILITIES";
|
||||
|
||||
/// Returns the MCP tool names (without `mcp__hyperhive__` prefix) that are
|
||||
/// unlocked by the agent's current capability set. These are added to the
|
||||
/// `--allowedTools` list so claude can call them without prompting, and
|
||||
/// hive-c0re performs a second server-side capability check before executing.
|
||||
fn allowed_capability_tools() -> Vec<String> {
|
||||
let raw = match std::env::var(CAPABILITIES_ENV) {
|
||||
Ok(v) if !v.trim().is_empty() => v,
|
||||
_ => return vec![],
|
||||
};
|
||||
let mut tools = Vec::new();
|
||||
for token in raw.split(',') {
|
||||
let t = token.trim().to_ascii_lowercase();
|
||||
match t.as_str() {
|
||||
"read_host_journal" => tools.push("get_host_journal".to_owned()),
|
||||
// manage_root_agent exposes no MCP tool at all: it is a
|
||||
// host-side grant, enforced by hive-c0re when it computes the
|
||||
// container's bind mounts. Nothing for the harness to register.
|
||||
"manage_root_agent" => {}
|
||||
unknown => {
|
||||
tracing::warn!(capability = %unknown, "unrecognised capability in HIVE_CAPABILITIES — skipped");
|
||||
}
|
||||
}
|
||||
}
|
||||
tools
|
||||
}
|
||||
|
||||
/// Tool group an extra (out-of-process) MCP server is gated behind, if any.
|
||||
///
|
||||
/// Most `services.hyperhive.agent.extraMcpServers` entries are ungated — available whenever
|
||||
|
|
@ -161,13 +130,6 @@ pub fn allowed_tools_arg() -> String {
|
|||
.map(ToOwned::to_owned)
|
||||
.collect();
|
||||
all.extend(allowed_mcp_tools(&groups));
|
||||
// Capability-gated MCP tools: added to --allowedTools when HIVE_CAPABILITIES
|
||||
// includes the corresponding capability. hive-c0re performs a second
|
||||
// server-side check, so this is a usability gate (no annoying prompts),
|
||||
// not the security boundary.
|
||||
for tool in allowed_capability_tools() {
|
||||
all.push(format!("mcp__{SERVER_NAME}__{tool}"));
|
||||
}
|
||||
all.join(",")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -501,7 +501,6 @@ fn tool_icon(name: &str) -> &'static str {
|
|||
"mcp__matrix__list_rooms"
|
||||
| "mcp__matrix__list_room_members"
|
||||
| "mcp__matrix__list_invites" => "📋",
|
||||
"mcp__hyperhive__get_host_journal" => "📜",
|
||||
"mcp__matrix__read_room" | "Read" => "📖",
|
||||
"mcp__matrix__mark_read" => "👁️",
|
||||
"mcp__bash__kill" => "🛑",
|
||||
|
|
@ -645,25 +644,6 @@ fn fmt_hyperhive_tool(name: &str, short: &str, input: &Value) -> String {
|
|||
.map_or_else(|| "?".to_owned(), |n| n.to_string());
|
||||
format!("{short} ≤{up_to}")
|
||||
}
|
||||
"mcp__hyperhive__get_host_journal" => {
|
||||
let mut parts = Vec::new();
|
||||
if let Some(c) = input.get("container").and_then(Value::as_str) {
|
||||
parts.push(c.to_owned());
|
||||
} else if let Some(u) = input.get("unit").and_then(Value::as_str) {
|
||||
parts.push(u.to_owned());
|
||||
}
|
||||
if let Some(g) = input.get("grep").and_then(Value::as_str) {
|
||||
parts.push(format!("/{g}/"));
|
||||
}
|
||||
if let Some(l) = input.get("lines").and_then(Value::as_u64) {
|
||||
parts.push(format!("{l}L"));
|
||||
}
|
||||
if parts.is_empty() {
|
||||
format!("{short}()")
|
||||
} else {
|
||||
format!("{short} {}", parts.join(" · "))
|
||||
}
|
||||
}
|
||||
"mcp__hyperhive__remind" => fmt_hyperhive_remind(short, input),
|
||||
"mcp__hyperhive__list_schedules"
|
||||
| "mcp__hyperhive__cancel_schedule"
|
||||
|
|
|
|||
Loading…
Reference in a new issue