diff --git a/docs/turn-loop.md b/docs/turn-loop.md index 02b90e4a..dba0c023 100644 --- a/docs/turn-loop.md +++ b/docs/turn-loop.md @@ -65,8 +65,7 @@ refused by the standard agent socket regardless of who sends them.) `hive-mcp-http` systemd unit, on `hyperhive.mcp.httpPort`, default 8790); claude connects to its URL via `--mcp-config`. HTTP is the sole transport — no per-turn stdio child (eliminates the re-registration - race). (A stdio mode still exists in the binary but isn't wired for - the built-in surface.) + race). - `hive-agent-wake --from --body ` — push a message into our own inbox so the next turn fires with the given body. Used by co-process helpers (scrapers, webhook listeners) to nudge claude on diff --git a/hive-ag3nt/src/bin/hive-agent-mcp.rs b/hive-ag3nt/src/bin/hive-agent-mcp.rs index f9fe5eea..baee732b 100644 --- a/hive-ag3nt/src/bin/hive-agent-mcp.rs +++ b/hive-ag3nt/src/bin/hive-agent-mcp.rs @@ -1,9 +1,9 @@ -//! MCP-server binary. Default is stdio — spawned by `claude` via -//! `--mcp-config`; tools dispatch through `/run/hive/mcp.sock` back into -//! the hyperhive broker. Pass `--http ` to instead run a long-lived -//! streamable-http listener (persistent daemon, the `hive-mcp-http` -//! systemd unit) that claude reconnects to each turn, avoiding the -//! per-turn stdio re-registration race. Sibling of `hive-agent` (the +//! MCP-server binary for the built-in hyperhive surface. Runs a long-lived +//! streamable-http listener (the `hive-mcp-http` systemd unit) on `--http +//! `; tools dispatch through `/run/hive/mcp.sock` back into the +//! hyperhive broker. claude reconnects to the stable URL each turn via +//! `--mcp-config`, avoiding the per-turn re-registration race. HTTP is the +//! sole transport — there is no stdio mode. Sibling of `hive-agent` (the //! serve loop that renders the `--mcp-config` blob pointing here) and //! `hive-agent-wake`. @@ -20,10 +20,10 @@ struct Cli { #[arg(long, default_value = DEFAULT_SOCKET)] socket: PathBuf, - /// Serve over streamable-http on this address (e.g. - /// `127.0.0.1:8790`) instead of stdio. Bind loopback only. + /// Serve streamable-http on this address (e.g. `127.0.0.1:8790`). + /// Bind loopback only. #[arg(long)] - http: Option, + http: std::net::SocketAddr, } #[tokio::main] @@ -36,8 +36,5 @@ async fn main() -> Result<()> { .init(); let cli = Cli::parse(); - match cli.http { - Some(addr) => mcp::serve_http(cli.socket, addr).await, - None => mcp::serve_agent_stdio(cli.socket).await, - } + mcp::serve_http(cli.socket, cli.http).await } diff --git a/hive-ag3nt/src/mcp/mod.rs b/hive-ag3nt/src/mcp/mod.rs index 693a6322..563ce71f 100644 --- a/hive-ag3nt/src/mcp/mod.rs +++ b/hive-ag3nt/src/mcp/mod.rs @@ -1,12 +1,13 @@ //! Embedded MCP server. Claude Code (running inside the agent container) -//! launches this as a stdio child via `--mcp-config`; tool calls land here -//! and are translated to `AgentRequest::*` / `ManagerRequest::*` against -//! hyperhive's own per-container unix socket at `/run/hive/mcp.sock`. +//! connects to this over streamable-HTTP via `--mcp-config` (the long-lived +//! `hive-mcp-http` daemon); tool calls land here and are translated to +//! `AgentRequest::*` / `ManagerRequest::*` against hyperhive's own +//! per-container unix socket at `/run/hive/mcp.sock`. //! //! Two protocols, two surfaces: //! - **hyperhive socket** at `/run/hive/mcp.sock` — JSON-line, our //! broker-routed protocol. Unaffected by this module. -//! - **MCP stdio** owned by this module — what claude actually speaks. +//! - **MCP over HTTP** owned by this module — what claude actually speaks. //! //! One `AgentServer { socket }` struct for all roles. //! Tool access is gated upstream by `--allowedTools` (derived from the @@ -17,10 +18,7 @@ use std::future::Future; use std::path::PathBuf; use anyhow::Result; -use rmcp::{ - ServerHandler, ServiceExt, handler::server::wrapper::Parameters, tool, tool_handler, - tool_router, transport::stdio, -}; +use rmcp::{ServerHandler, handler::server::wrapper::Parameters, tool, tool_handler, tool_router}; use crate::client; @@ -1011,24 +1009,10 @@ impl AgentServer { )] impl ServerHandler for AgentServer {} -/// Run the MCP server over stdio. Used by all roles. Returns when the client -/// disconnects. -/// -/// # Errors -/// -/// Returns an error if the MCP server fails to initialize or the transport -/// encounters a fatal error. -pub async fn serve_agent_stdio(socket: PathBuf) -> Result<()> { - let server = AgentServer::new(socket); - let service = server.serve(stdio()).await?; - service.waiting().await?; - Ok(()) -} - /// Run the MCP server over HTTP (rmcp streamable-http transport) on `addr`. /// -/// Unlike [`serve_agent_stdio`] — a fresh stdio child claude respawns every turn — -/// this is meant to run as a long-lived in-container daemon. claude reconnects +/// This is the sole transport for the built-in hyperhive surface. It runs as a +/// long-lived in-container daemon. claude reconnects /// to the stable URL each turn instead of respawning and re-registering a stdio /// subprocess, which removes the per-turn MCP registration race that can strand /// an agent when the async `initialize`/`tools/list` loses to claude's first