refactor(#2112): remove the dead stdio transport from hive-agent-mcp

This commit is contained in:
damocles 2026-07-11 00:55:41 +02:00
commit 4745274fca
3 changed files with 19 additions and 39 deletions

View file

@ -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 `hive-mcp-http` systemd unit, on `hyperhive.mcp.httpPort`, default
8790); claude connects to its URL via `--mcp-config`. HTTP is the sole 8790); claude connects to its URL via `--mcp-config`. HTTP is the sole
transport — no per-turn stdio child (eliminates the re-registration transport — no per-turn stdio child (eliminates the re-registration
race). (A stdio mode still exists in the binary but isn't wired for race).
the built-in surface.)
- `hive-agent-wake --from <name> --body <body>` — push a message into - `hive-agent-wake --from <name> --body <body>` — push a message into
our own inbox so the next turn fires with the given body. Used by our own inbox so the next turn fires with the given body. Used by
co-process helpers (scrapers, webhook listeners) to nudge claude on co-process helpers (scrapers, webhook listeners) to nudge claude on

View file

@ -1,9 +1,9 @@
//! MCP-server binary. Default is stdio — spawned by `claude` via //! MCP-server binary for the built-in hyperhive surface. Runs a long-lived
//! `--mcp-config`; tools dispatch through `/run/hive/mcp.sock` back into //! streamable-http listener (the `hive-mcp-http` systemd unit) on `--http
//! the hyperhive broker. Pass `--http <addr>` to instead run a long-lived //! <addr>`; tools dispatch through `/run/hive/mcp.sock` back into the
//! streamable-http listener (persistent daemon, the `hive-mcp-http` //! hyperhive broker. claude reconnects to the stable URL each turn via
//! systemd unit) that claude reconnects to each turn, avoiding the //! `--mcp-config`, avoiding the per-turn re-registration race. HTTP is the
//! per-turn stdio re-registration race. Sibling of `hive-agent` (the //! sole transport — there is no stdio mode. Sibling of `hive-agent` (the
//! serve loop that renders the `--mcp-config` blob pointing here) and //! serve loop that renders the `--mcp-config` blob pointing here) and
//! `hive-agent-wake`. //! `hive-agent-wake`.
@ -20,10 +20,10 @@ struct Cli {
#[arg(long, default_value = DEFAULT_SOCKET)] #[arg(long, default_value = DEFAULT_SOCKET)]
socket: PathBuf, socket: PathBuf,
/// Serve over streamable-http on this address (e.g. /// Serve streamable-http on this address (e.g. `127.0.0.1:8790`).
/// `127.0.0.1:8790`) instead of stdio. Bind loopback only. /// Bind loopback only.
#[arg(long)] #[arg(long)]
http: Option<std::net::SocketAddr>, http: std::net::SocketAddr,
} }
#[tokio::main] #[tokio::main]
@ -36,8 +36,5 @@ async fn main() -> Result<()> {
.init(); .init();
let cli = Cli::parse(); let cli = Cli::parse();
match cli.http { mcp::serve_http(cli.socket, cli.http).await
Some(addr) => mcp::serve_http(cli.socket, addr).await,
None => mcp::serve_agent_stdio(cli.socket).await,
}
} }

View file

@ -1,12 +1,13 @@
//! Embedded MCP server. Claude Code (running inside the agent container) //! Embedded MCP server. Claude Code (running inside the agent container)
//! launches this as a stdio child via `--mcp-config`; tool calls land here //! connects to this over streamable-HTTP via `--mcp-config` (the long-lived
//! and are translated to `AgentRequest::*` / `ManagerRequest::*` against //! `hive-mcp-http` daemon); tool calls land here and are translated to
//! hyperhive's own per-container unix socket at `/run/hive/mcp.sock`. //! `AgentRequest::*` / `ManagerRequest::*` against hyperhive's own
//! per-container unix socket at `/run/hive/mcp.sock`.
//! //!
//! Two protocols, two surfaces: //! Two protocols, two surfaces:
//! - **hyperhive socket** at `/run/hive/mcp.sock` — JSON-line, our //! - **hyperhive socket** at `/run/hive/mcp.sock` — JSON-line, our
//! broker-routed protocol. Unaffected by this module. //! 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. //! One `AgentServer { socket }` struct for all roles.
//! Tool access is gated upstream by `--allowedTools` (derived from the //! Tool access is gated upstream by `--allowedTools` (derived from the
@ -17,10 +18,7 @@ use std::future::Future;
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use rmcp::{ use rmcp::{ServerHandler, handler::server::wrapper::Parameters, tool, tool_handler, tool_router};
ServerHandler, ServiceExt, handler::server::wrapper::Parameters, tool, tool_handler,
tool_router, transport::stdio,
};
use crate::client; use crate::client;
@ -1011,24 +1009,10 @@ impl AgentServer {
)] )]
impl ServerHandler for 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`. /// 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 the sole transport for the built-in hyperhive surface. It runs as a
/// this is meant to run as a long-lived in-container daemon. claude reconnects /// long-lived in-container daemon. claude reconnects
/// to the stable URL each turn instead of respawning and re-registering a stdio /// 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 /// 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 /// an agent when the async `initialize`/`tools/list` loses to claude's first