# MCP surface The harness ships an embedded MCP server (rmcp 1.7). The built-in `hyperhive` surface is served over streamable HTTP by a persistent `hive-mcp-http` daemon (loopback, `127.0.0.1:`, per-container private netns). Claude connects to its stable URL via `--mcp-config` rather than respawning a stdio child each turn, so the URL survives the per-turn claude re-spawn (and a host-side hive-c0re restart) — there is no per-turn MCP re-registration race for the built-in surface. HTTP is the sole transport for it (no stdio fallback). Extra servers (`hyperhive.extraMcpServers`) pick their own transport per entry (`type = "stdio" | "http"`, default `"stdio"`): `matrix` stays a stdio bridge, `bash` runs its own persistent streamable-http listener (`hive-bash-daemon`) — same reasoning as the built-in surface. The server name is `hyperhive`, so the tools land in claude as `mcp__hyperhive__`. Tool access is gated by tool groups (`HIVE_TOOL_GROUPS`). The default preset (`AGENT_DEFAULT`) includes `messaging`, `meta`, `inbox`, and `execution`. Privileged groups (`lifecycle`, `approvals`, `scheduling`, `diagnostics`) are opt-in via the P3RM1SS10NS tab. ## Core tools (always available) **Messaging** (`messaging` group): `send(to, body, in_reply_to?)`, `recv(wait_seconds?, max?)`, `ask(question, options?, multi?, ttl_seconds?, to?)`, `answer(id, answer)`, `ack_until(up_to)`. - `send` — message a peer (logical name) or the operator (`to: "operator"`). Use `to: ""` to address the topology parent without hardcoding the label; the broker resolves the sentinel at delivery time. Optional `in_reply_to: i64` links the message to a prior id for thread rendering. Per-agent `hyperhive.allowedRecipients` (default: empty = unrestricted) limits which names `send` accepts — useful for sandboxing: set `[ "operator" ]` to restrict a sub-agent to operator messages only (the topology parent is always reachable regardless of this list — that carve-out is structural, keyed on parent relationship, not name). - `recv` — drain inbox. Without `wait_seconds` (or `0`) returns immediately. Positive value parks the turn up to that many seconds (cap 180) — incoming messages wake instantly. `max` (default 1, cap 5) drains up to N rows; `wait_seconds` applies to the first, then drains up to `max` total. Each returned row is prefixed with `[msg #]` (broker row id; note the highest id seen, then pass it to `ack_until` to bulk-triage the batch). **Graceful shutdown**: when the harness receives a stop signal, the inbox becomes fenced and `recv` returns an explicit `from: "graceful-stop"` message instead of an empty inbox. This unmissably directs the agent to flush durable state (`/state` files) and end the turn — the container exits when the turn completes. The graceful-stop turn takes the same post-turn compaction path as any other turn: if the context crossed the watermark the harness runs a notes-checkpoint turn and then `/compact`. Compacting before shutdown keeps a later cold start cheap instead of re-uploading a huge transcript. - `ask` — surface a structured question to the operator (default) or a peer agent (`to: ""`). Non-blocking — returns a question id; the answer arrives as a `question_answered` system event in the asker's inbox. `options` is advisory; `multi=true` renders as checkboxes; `ttl_seconds` auto-cancels with answer `[expired]`. - `answer` — respond to a `question_asked` event routed to this agent. Strict authorisation: only the declared target can answer. - `ack_until(up_to)` — bulk-mark inbox rows handled: every row with broker id `<= up_to` is stamped as acked in a single UPDATE. Recipient-scoped (agents can only ack their own rows). Use when a restart redelivers a large backlog of already-handled messages: read the highest `[msg #N]` from the set you've actually processed, then `ack_until(N)` to prevent re-pop. Acked rows never redeliver. Transient pings (sentinel id 0) have nothing to ack and show no marker. **System messages** (from sender `system`): lifecycle and Q&A events delivered as regular inbox messages (same `recv` path; body is a JSON object with an `event` discriminant field). The **submitting agent** (the root agent for top-level containers; an agent with the `approvals` tool group for its own subtree) receives lifecycle events (`spawned`, `rebuilt`, `killed`, `destroyed`, `container_crash`, `needs_login`, `logged_in`, `config_ready`, `needs_update`, `approval_resolved`). Any agent receives Q&A events when it is the declared target (`question_asked`) or the asker (`question_answered`). Full payload shapes and routing logic in [`docs/approvals.md` § Helper events](../approvals.md#helper-events-to-the-submitting-agent). **Inbox** (`inbox` group): `get_loose_ends(agent?)`, `cancel_loose_end(kind, id)`, `remind(message, delay_seconds? | at_unix_timestamp?)`. - `get_loose_ends(agent?)` — list pending questions (asked/owed), scheduled reminders, and active local tasks published by external MCP daemons (e.g. running bash tasks from `hive-bash-daemon`). Each row carries an id + kind for `cancel_loose_end`. Omit `agent` to list your own threads. Pass `agent: ""` to inspect a direct child agent (always accessible per topology enforcement); non-children require the `query_agent_state` capability. The `"*"` hive-wide query is not available on the agent socket. - `cancel_loose_end` — withdraw a `question` (posts `[cancelled by ]`), hard-delete a `reminder`, or cancel a pending `approval` row. Agents may only cancel rows they own; the `approval` kind is further restricted to the root agent (`ruth`) server-side. - `remind` — schedule a reminder in this agent's own inbox. Large payloads spill to `/agents//state/reminders/`. Pending count capped at 50 per agent (`HIVE_REMIND_MAX_PENDING_PER_AGENT`). There is no same-turn self-continue tool: ending the turn and letting an external wake drive the next one is always the right move — it checkpoints the session and observes wakes that only reach the harness between turns. Multi-step work rides `remind` for a durable self-wake, or an in-container todo wake (bash-task completion, forge notification, matrix activity) for work already in flight. **Meta** (`meta` group): `set_status(text)`, `get_agent_meta(name?)`. - `set_status` — set a free-text status string visible on the dashboard. Single line, ≤ 200 chars. Persisted to `{state_dir}/hyperhive-status`. Pass `""` to clear. - `get_agent_meta` — fetch identity + status metadata for an agent: `{ name, hyperhive_rev, running, status_text, status_set_at, hive_name?, swarm_name?, matrix_accounts? }`. `matrix_accounts` is a list of matrix identities the agent can act as (`name`, `user_id?`, `homeserver`); omitted for agents with no matrix provisioning. Omit `name` to query self. **Always-on, no tool group** (like `set_status`): `compact()`. - `compact` — agent self-service equivalent of the operator dashboard's `/compact` button. No args. Gated server-side on the last completed turn's context usage: refused (with an explanation, no side effect) unless usage is above 66% of the effective context window. On a pass, queues the same deferred `compact_pending` flag the dashboard button sets — consumed at the end of the current turn, so it never races a live claude process, and the usual pre-compaction notes-checkpoint turn still fires first. Dispatched through the in-agent socket (`hive-agent-sock::Request::Compact`), not the broker — see `hive-agent/src/todo_server.rs`. ## Privileged tools (by tool group) - **Bash execution** (`execution`) — background shell tasks. See [`docs/tools/bash.md`](../tools/bash.md). - **Lifecycle + config** (`lifecycle`, `approvals`) — manage child agents, spawn new ones, apply config commits. See [`docs/tools/lifecycle.md`](../tools/lifecycle.md). - **Scheduling + diagnostics** (`scheduling`, `diagnostics`) — scheduled prompts, `get_logs`. See [`docs/tools/scheduling.md`](../tools/scheduling.md). - **Forge repos** (`forge`) — `create_repo` — the only agent path to create a repo under the `agents/` org (direct forge token creation is disabled for agents). The repo is created in the c0re-owned `agents` org; the calling agent gets write collaborator access; the default branch is branch-protected (operator-team must approve merges, so the agent cannot self-merge). Opt-in; not in any default preset. See [`docs/tools/forge.md — Repo management`](../tools/forge.md). - **Web egress** (`web_tools`) — enables Claude's built-in `WebFetch` and `WebSearch` tools (not MCP tools; added directly to the `--allowedTools` list). Off by default; add the group in the P3RM1SS10NS tab and rebuild to enable. - **Capability-gated** — `get_host_journal` (requires `read_host_journal` capability set via the P3RM1SS10NS tab; orthogonal to tool groups). Full list of capabilities and their effects in [`docs/conventions.md#capabilities`](../conventions.md). Also documented in [`docs/tools/scheduling.md`](../tools/scheduling.md). - **Matrix MCP + extra servers** — `mcp__matrix__*` tools and per-agent extra MCP config. See [`docs/tools/matrix.md`](../tools/matrix.md). ## Waking the agent from inside the container External MCP servers (and any other in-container process) can inject a wake-up event into the agent's inbox via the per-agent socket at `/run/hive/mcp.sock`. Speak the wire protocol directly — JSON-line over the unix socket: `{"cmd":"wake","from":"matrix","body": "new dm from @alice"}\n`. Same shape as any other `AgentRequest`; see `hive-sh4re::AgentRequest::Wake`. (An earlier `hive-agent-wake` CLI wrapper existed for this but was removed — no shipped co-process daemon actually shelled out to it; every one that wakes the harness (matrix, bash) dials the socket directly, so the raw protocol is the only path now.) The wake event lands in the broker as `{from: