Skip to content

Remote MCP servers leave zombie processes after laptop sleep, blocking restart #3429

@flfeurmou-indeed

Description

@flfeurmou-indeed

Problem

After laptop sleep/wake cycles, old thv processes sometimes remain running and continue holding their ports. When attempting to restart these servers, the new process fails with:

failed to listen: listen tcp 127.0.0.1:XXXXX: bind: address already in use

This happens even with #3417 (SO_REUSEADDR), because SO_REUSEADDR cannot override an actively running process, it only helps with sockets in TIME_WAIT state.

Observed behavior

  1. Laptop goes to sleep with Datadog/Glean MCP servers running
  2. Laptop wakes up
  3. Old thv start <server> processes are still running (visible in ps aux | grep thv)
  4. thv start <server> or thv restart <server> fails because the old process holds the port
  5. Manual kill <pid> is required before the server can start

Environment

  • macOS (Apple Silicon)
  • Toolhive v0.7.x
  • Remote MCP servers (Datadog, Glean) using OAuth

Possible solutions

  1. PID file tracking: Store PID on start, check/kill stale process on restart
  2. Better signal handling: Ensure processes terminate cleanly on SIGTERM/SIGHUP during sleep
  3. Port-based cleanup: Before binding, check if another thv process holds the port and terminate it
  4. Enhanced thv restart: Make restart explicitly kill the old process before starting new one

Workaround

Currently using a wrapper script that runs pkill -f "thv start <server>" before starting.

Related

Happy to submit a PR if you'd like me to implement one of these solutions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    authenticationbugSomething isn't workingcliChanges that impact CLI functionalityproxy

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions