tinyhumansai/openhuman · error · anyhow::Error

stdio MCP server closed stdout while waiting for `{method}`

Error message

stdio MCP server closed stdout while waiting for `{method}`

What it means

During a stdio JSON-RPC round-trip, `read_line` on the server's stdout returned 0 bytes — the child process closed/exited before answering the pending `{method}` request. Because a single request/response is framed per line, EOF means the reply will never arrive, so the client bails immediately instead of waiting on a timeout. Typical root cause is the server crashing on startup (bad args, missing env, panicking on the request) after stdout closed.

Source

Thrown at src/openhuman/mcp/config_servers/stdio.rs:226

        method: &str,
        params: Value,
    ) -> anyhow::Result<Value> {
        let id = self.next_id.fetch_add(1, Ordering::Relaxed);
        let line = serde_json::to_string(&json!({
            "jsonrpc": "2.0",
            "id": id,
            "method": method,
            "params": params,
        }))?;
        session.stdin.write_all(line.as_bytes()).await?;
        session.stdin.write_all(b"\n").await?;
        session.stdin.flush().await?;

        loop {
            let mut response = String::new();
            let read = session.stdout.read_line(&mut response).await?;
            if read == 0 {
                anyhow::bail!("stdio MCP server closed stdout while waiting for `{method}`");
            }
            let trimmed = response.trim();
            if trimmed.is_empty() {
                continue;
            }
            if !trimmed.starts_with('{') && !trimmed.starts_with('[') {
                tracing::debug!(
                    target: "[mcp_client::stdio]",
                    command = %self.command,
                    line = %trimmed,
                    "ignoring non-JSON stdout line from stdio MCP server"
                );
                continue;
            }
            let payload: Value = serde_json::from_str(trimmed)
                .with_context(|| format!("parsing stdio MCP response: {trimmed}"))?;
            if let Some(err) = payload.get("error") {
                anyhow::bail!("MCP stdio error: {err}");

View on GitHub (pinned to 7491200858)

Solutions

  1. Run the exact `command args` from the config manually in a terminal and watch stderr — the crash reason is almost always printed there.
  2. Fix args/package names (e.g. missing `-y` for npx, wrong package version).
  3. Supply required env vars (API keys) via the server entry's `env` config.
  4. If it dies only under load, check memory limits; a server that dies on one specific tool call is a server bug — capture its stderr/stack.

Example fix

# before — npx prompts/fails and exits immediately
[[mcp_client.servers.context7]]
command = "npx"
args = ["@upstash/context7-mcp"]

# after — non-interactive install flag, plus debug by running it yourself:
#   npx -y @upstash/context7-mcp
[[mcp_client.servers.context7]]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]
Defensive patterns

Strategy: retry

Validate before calling

null

Try / catch

// on 'closed stdout while waiting for': tear down and re-initialize once
match stdio_client.request(method, params).await {
    Err(e) if e.to_string().contains("closed stdout") => {
        stdio_client = McpStdioClient::new(cmd, args, env, None, identity);
        stdio_client.initialize().await?;
        stdio_client.request(method, params).await
    }
    other => other,
}

Prevention

When it happens

Trigger: `initialize`, `tools/list`, or `tools/call` over stdio where the spawned command exits first: wrong CLI args making npx/uvx fail fast, the package failing to install, an unhandled exception in the server triggered by the request, or the server being OOM-killed.

Common situations: First `initialize` after a config change introduced a bad flag; npx package name typo (npx errors out and exits); server requires an env var/API key it reads at startup and aborts when missing; intermittent OOM or the user/system killing the helper process.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/9e8ad680a791d719. Report an issue: GitHub.