Matrix MCP tools and extra MCP servers

Built-in matrix MCP (mcp__matrix__*)

When hyperhive.matrix.enable = true and the host-level matrix tuwunel is configured, the harness auto-injects hive-matrix-daemon's streamable-http endpoint as a second MCP server (no stdio bridge — see Architecture below). Tools land as mcp__matrix__<name>:

Messaging

Unread guard: send_message, send_dm, send_file, and send_reply are all rejected if the room has unread messages — call read_room then mark_read on the latest event before sending to a room you haven't read yet.

Reading

Room membership

Receipts

Architecture

hive-matrix-daemon is a single long-running process (one per agent container, systemd service in nix/agent-modules/matrix.nix) — no stdio bridge, no separate bin. It owns the matrix-sdk Client + sync loop per configured account and serves the matrix tool surface directly over streamable-http on hyperhive.mcp.matrixHttpPort (declared in hyperhive.extraMcpServers.matrix as { type = "http"; url = ...; }). Same shape as hive-bash-daemon and the built-in hyperhive surface (hive-mcp-http) — claude reconnects to the stable URL every turn instead of respawning a stdio child. Silently exits when <state>/matrix-token is absent (account not yet provisioned); the systemd.paths.hive-matrix-daemon watcher restarts it the moment hive-c0re provisions the token.

Incoming room events wake the agent via AgentRequest::Wake with from: "matrix". The wake body format depends on the unread state:

The same per-room breakdown is included in the UnreadMatrix entry returned by get_loose_ends so unread rooms surface in the loose-ends list between turns.

Invite wakes: when the daemon's sync loop receives an m.room.member invite event, it upserts a todo (keyed invite:<room>) on the harness's in-agent socket, which drives a turn. The daemon does not auto-join — the agent calls list_invites to see pending invites and resolve_invite to accept or reject them.

Pending invites as loose ends: pending invites are upserted as keyed todos and appear in get_loose_ends output as [matrix] pending invite: <room> — use list_invites to see, resolve_invite to accept or reject. The keyed todo is cleared when a resolve_invite (or join_room) call resolves the invite.

See docs/matrix.md for the homeserver setup, provisioning flow, and federation config.

Extra MCP servers (per-agent)

Each agent's NixOS config can declare additional MCP servers via hyperhive.extraMcpServers.<key> = { type, command, args, env, url, allowedTools }type = "stdio" (the default, uses command/args/ env) or type = "http" (uses url, a long-lived streamable-http endpoint — see hive-bash-daemon and hive-matrix-daemon above for the "http" shape). The module writes the map to /etc/hyperhive/extra-mcp.json; the harness reads it at boot and merges every entry into --mcp-config (under mcpServers.<key>) and --allowedTools (as mcp__<key>__<pattern>).

The agent's flake.nix forwards every flake input to agent.nix as the flakeInputs module arg, so external MCP-server flakes are pulled in by adding them to inputs.* and referenced as flakeInputs.<name>.packages.${pkgs.system}.default — the resolved sha lands in the agent's own flake.lock and rolls up to meta's.

allowedTools defaults to ["*"], which expands to mcp__<key>__* (every tool from that server auto-approved). Restrict to specific tool names when you want finer control.