feat(#2038): wire persistent hive-mcp-http daemon behind hyperhive.mcp.httpPort
This commit is contained in:
parent
4a82ed02cf
commit
3c10b00460
1 changed files with 62 additions and 0 deletions
|
|
@ -828,6 +828,34 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
options.hyperhive.mcp.httpPort = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.port;
|
||||||
|
default = null;
|
||||||
|
example = 8790;
|
||||||
|
description = ''
|
||||||
|
Serve the built-in hyperhive MCP surface as a persistent
|
||||||
|
streamable-http daemon on this loopback port instead of the
|
||||||
|
default per-turn stdio child.
|
||||||
|
|
||||||
|
When null (the default) claude spawns a fresh `hive … mcp` stdio
|
||||||
|
subprocess every turn — the shape that carries the per-turn MCP
|
||||||
|
re-registration race (a resumed turn can emit its first tool call
|
||||||
|
before that turn's async `initialize`/`tools-list` completes,
|
||||||
|
stranding the agent with `No such tool`). When set, a long-lived
|
||||||
|
`hive-mcp-http` systemd unit runs `hive mcp --http 127.0.0.1:<port>`
|
||||||
|
and `render_claude_config` points claude at the stable
|
||||||
|
`http://127.0.0.1:<port>/mcp` URL, which survives the per-turn
|
||||||
|
claude re-spawn (and a host-side hive-c0re restart — each tool call
|
||||||
|
dials the control socket fresh). Extra MCP servers (matrix/bash)
|
||||||
|
stay stdio bridges regardless.
|
||||||
|
|
||||||
|
Bound loopback-only; the rmcp streamable-http transport's default
|
||||||
|
`allowed_hosts` (`localhost` / `127.0.0.1` / `::1`) rejects Host
|
||||||
|
headers from anywhere else, so no auth token is required for a
|
||||||
|
container-local endpoint.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
warnings = lib.optional (config.hyperhive.allowedBashPatterns != [ ]) ''
|
warnings = lib.optional (config.hyperhive.allowedBashPatterns != [ ]) ''
|
||||||
hyperhive.allowedBashPatterns is deprecated and has no effect.
|
hyperhive.allowedBashPatterns is deprecated and has no effect.
|
||||||
|
|
@ -1709,6 +1737,33 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Persistent streamable-http MCP daemon for the built-in hyperhive
|
||||||
|
# surface. Only wired when `hyperhive.mcp.httpPort` is set; otherwise
|
||||||
|
# the surface stays the default per-turn stdio child (rendered by
|
||||||
|
# `render_claude_config`). Long-lived so claude reconnects to the
|
||||||
|
# stable URL each turn instead of respawning + re-registering a stdio
|
||||||
|
# subprocess (the per-turn MCP registration race). It dials the
|
||||||
|
# control socket (`/run/hive/mcp.sock`, the `hive` binary default)
|
||||||
|
# fresh on every tool call, so a host-side hive-c0re restart is
|
||||||
|
# transparent. `before = hive-ag3nt` so the URL is already listening
|
||||||
|
# by the time the harness renders the first turn's config; the
|
||||||
|
# harness/claude also reconnect on their own, so ordering is a
|
||||||
|
# latency nicety not a hard correctness dep.
|
||||||
|
systemd.services.hive-mcp-http = lib.mkIf (config.hyperhive.mcp.httpPort != null) {
|
||||||
|
description = "persistent streamable-http MCP daemon for the hyperhive surface";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
before = [ "hive-ag3nt.service" ];
|
||||||
|
environment.RUST_LOG = "info";
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${pkgs.hyperhive}/bin/hive mcp --http 127.0.0.1:${toString config.hyperhive.mcp.httpPort}";
|
||||||
|
SyslogIdentifier = "hive-mcp-http";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 3;
|
||||||
|
User = userName;
|
||||||
|
Group = userName;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# Re-fire the daemon when the matrix token appears (hive-c0re
|
# Re-fire the daemon when the matrix token appears (hive-c0re
|
||||||
# provisions it after agent containers come up). Without this
|
# provisions it after agent containers come up). Without this
|
||||||
# the daemon would exit 0 silently on first boot and the MCP
|
# the daemon would exit 0 silently on first boot and the MCP
|
||||||
|
|
@ -1802,6 +1857,13 @@ in
|
||||||
# bind-mounts and gateway upstream config stay in sync.
|
# bind-mounts and gateway upstream config stay in sync.
|
||||||
HIVE_WEB_SOCKET = "/run/hive-agent/${userName}/web.sock";
|
HIVE_WEB_SOCKET = "/run/hive-agent/${userName}/web.sock";
|
||||||
}
|
}
|
||||||
|
// lib.optionalAttrs (config.hyperhive.mcp.httpPort != null) {
|
||||||
|
# Presence tells `render_claude_config` to point claude at the
|
||||||
|
# persistent `hive-mcp-http` daemon's loopback URL instead of a
|
||||||
|
# per-turn stdio child. Kept in sync with the `hive-mcp-http`
|
||||||
|
# unit's `--http` port above via the same option.
|
||||||
|
HYPERHIVE_MCP_HTTP_PORT = toString config.hyperhive.mcp.httpPort;
|
||||||
|
}
|
||||||
// lib.optionalAttrs config.hyperhive.gui.enable {
|
// lib.optionalAttrs config.hyperhive.gui.enable {
|
||||||
# Tells the harness which fixed VNC port weston bound, and (by
|
# Tells the harness which fixed VNC port weston bound, and (by
|
||||||
# its presence) that gui is enabled — the harness `/screen/ws`
|
# its presence) that gui is enabled — the harness `/screen/ws`
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue