Skip to content

Latest commit

 

History

History
88 lines (73 loc) · 4 KB

File metadata and controls

88 lines (73 loc) · 4 KB
summary Checklist for diagnosing mcporter commands that never exit, using tmux and active-handle dumps.
read_when
Seeing the CLI hang after tool completion

Debugging Hanging mcporter Calls

When mcporter call prints a tool response but the process never exits, it usually means Node still has active handles it is waiting on. The most common culprit is a child MCP server process that keeps the stdio transport alive.

Quick Checklist

  1. Run under tmux – launch the command inside tmux so you can inspect the pane even after Cursor or another agent times out.
  2. Enable hang diagnostics – set MCPORTER_DEBUG_HANG=1 when invoking the CLI. mcporter will dump the active handles/requests after the tool finishes and around the runtime.close() call.
  3. Inspect the handle list – look for ChildProcess (pid=…) entries. If a child remains, mcporter will now unref and force-kill it, but the debug list tells you exactly what was keeping the event loop alive.
  4. Capture the pane output – run tmux capture-pane -p -t <session> -S -200 to save the diagnostic log for later review.
  5. Retry with --timeout – if the tool itself hangs, use --timeout <ms> or MCPORTER_CALL_TIMEOUT to fail fast while still gathering diagnostics.
  6. Clamp OAuth waits – when the browser-based sign-in never completes, run with --oauth-timeout <ms> (or MCPORTER_OAUTH_TIMEOUT_MS) so the CLI tears down the pending flow instead of waiting the full minute.

Example Session

tmux new-session -d -s mcphang \
  'cd /path/to/project && \
   MCPORTER_DEBUG_HANG=1 \
   CHROME_DEVTOOLS_MCP_BROWSER_URL=http://127.0.0.1:9222 \
   pnpm --dir "$HOME/projects/mcporter" exec tsx \
   "$HOME/projects/mcporter/src/cli.ts" call \
   --config "$PWD/config/mcporter.json" \
   --root "$PWD" \
   chrome-devtools --tool list_pages'

sleep 5
tmux capture-pane -p -t mcphang -S -200

Sample diagnostic output (abridged):

[mcporter] [debug] after call (object result): 6 active handle(s), 0 request(s)
[mcporter] [debug] handle => ChildProcess (pid=78480)
[mcporter] [debug] beginning runtime.close()
[mcporter] [debug] after runtime.close: 6 active handle(s), 0 request(s)
[mcporter] [debug] forcibly killed child pid=78480 (runtime.finally)

This confirms the CLI response completed and that the lingering handle was a child process, which mcporter will now terminate during shutdown.

Notes

  • The diagnostics only appear when MCPORTER_DEBUG_HANG=1 is set.
  • Killing residual children is best-effort; if you see repeated kill-failed messages, manually terminate the PID listed in the log.
  • Always keep tmux sessions tidy after debugging: tmux kill-session -t <session>.
  • The CLI now forces process.exit(0) after cleanup by default so Node never lingers on leaked handles. Export MCPORTER_NO_FORCE_EXIT=1 if you’re debugging and need the process to stay alive.
  • You can still set MCPORTER_FORCE_EXIT=1 explicitly when you want to force termination even with MCPORTER_NO_FORCE_EXIT in play.
  • Stdio servers have their stderr output suppressed by default; set MCPORTER_STDIO_LOGS=1 to print their logs (they’re also surfaced whenever a child exits with a non-zero status).

Upstream Tracking

We keep a local checkout of the SDK under ~/Projects/typescript-sdk/ so we can diff against upstream and craft repros/patches quickly. Any mcporter-specific workarounds live in src/sdk-patches.ts until the upstream fixes land.