claude -p with --output-format text hangs after completing — MCP servers not cleaned up

Resolved 💬 3 comments Opened Apr 19, 2026 by aviadshiber Closed May 27, 2026

Problem

When running claude -p "<prompt>" --output-format text --mcp-config mcp.json > output.txt, the process completes its work (writes full response to conversation JSONL) but the Node.js process never exits.

Root Cause

MCP server child processes spawned during the session stay alive after Claude finishes its work. Node.js won't exit until all child process stdio pipes close. The MCP server (in this case @upstash/context7-mcp via npx) keeps running indefinitely, holding the event loop open.

Additionally, a zsh -c child process from a Bash tool call that didn't complete cleanly also remained alive.

Observed State

Process: sleeping in epoll_wait, 0 API TCP connections, 7 threads
Response file (stdout redirect): 0 bytes (only written on process exit)
Conversation JSONL: contains the full completed response
Child processes still alive:
  - PID 4352: npm exec @upstash/context7-mcp  (MCP server)
  - PID 7270: zsh -c <bash tool call>          (stuck tool execution)

The process ran for 2+ hours in this state before being manually killed.

Environment

  • CLAUDE_CODE_EXIT_AFTER_STOP_DELAY=10000 was set but did not help — the MCP server keeps the process alive past the delay
  • Model: claude-opus-4-6
  • MCP config: single server (@upstash/context7-mcp)
  • Running inside a container (Podman) with --dangerously-skip-permissions

Expected Behavior

When claude -p completes its response in prompt mode:

  1. All MCP server child processes should be terminated (SIGTERM → SIGKILL)
  2. Any stuck Bash tool child processes should be cleaned up
  3. The process should exit and flush stdout (so --output-format text actually writes the response)
  4. CLAUDE_CODE_EXIT_AFTER_STOP_DELAY should force-kill child processes if they don't exit within the delay

Questions

  1. Does -p mode have explicit MCP server cleanup on completion?
  2. Is CLAUDE_CODE_EXIT_AFTER_STOP_DELAY supposed to handle MCP server shutdown, or only the main process?
  3. Would --output-format stream-json avoid this issue by streaming output incrementally rather than buffering until exit?

Workaround

External timeout wrapper: timeout 3600 claude -p ...

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗