Severity
P2 — full stderr pipe (journald, container logs with slow consumer) can deadlock the MCP request loop.
Files
crates/librefang-runtime-mcp/src/lib.rs:1010-1036 (connect_stdio)
Finding
The Command configured for the MCP child never sets
.stderr(Stdio::piped()) or .stderr(Stdio::null()), so it inherits the
daemon's stderr. Two consequences:
- Failure debugging: when a server crashes during handshake, its stack
trace is dumped raw to the daemon's stderr without any server="<name>"
context, mixed with structured logs — operators can't tell which MCP
server died.
- Fd-fill stall: if the daemon's stderr is a fully-buffered pipe
(journald, container docker logs with a slow consumer, CI capture), an
MCP server spamming stderr can fill the pipe; once full and the consumer
is slow, the child blocks on write(stderr), which deadlocks the MCP
request loop. There's no rate limit, no truncation, no per-server log
routing.
Evidence
tokio::process::Command::new(&resolved_command).configure(|cmd| {
cmd.args(&args_owned);
cmd.env_clear();
// ... no .stderr(Stdio::piped()) or .stderr(Stdio::null())
})
Suggested Fix
Set cmd.stderr(std::process::Stdio::piped()) and spawn a tokio task that
forwards lines to tracing::warn!(server=%name, line=%l) with a per-server
line/byte cap; alternatively Stdio::null() if surfacing isn't required.
Always pair with kill_on_drop(true) from #66.
Severity
P2 — full stderr pipe (journald, container logs with slow consumer) can deadlock the MCP request loop.
Files
crates/librefang-runtime-mcp/src/lib.rs:1010-1036(connect_stdio)Finding
The
Commandconfigured for the MCP child never sets.stderr(Stdio::piped())or.stderr(Stdio::null()), so it inherits thedaemon's stderr. Two consequences:
trace is dumped raw to the daemon's stderr without any
server="<name>"context, mixed with structured logs — operators can't tell which MCP
server died.
(journald, container
docker logswith a slow consumer, CI capture), anMCP server spamming stderr can fill the pipe; once full and the consumer
is slow, the child blocks on
write(stderr), which deadlocks the MCPrequest loop. There's no rate limit, no truncation, no per-server log
routing.
Evidence
Suggested Fix
Set
cmd.stderr(std::process::Stdio::piped())and spawn a tokio task thatforwards lines to
tracing::warn!(server=%name, line=%l)with a per-serverline/byte cap; alternatively
Stdio::null()if surfacing isn't required.Always pair with
kill_on_drop(true)from #66.