github / github/copilot-cli

Post-authentication MCP client rebuild at startup leaves orphaned stdio MCP server processes

Đang mở
#4,392 2 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

area:mcp area:sessions
Ngôn ngữ chính
Shell
Star
11.2k
Fork
1.9k
Merge trung bình
14 giờ 16 phút
Pull request đã merge (30 ngày)
6

Mô tả

Describe the bug

At startup, the CLI spawns its configured MCP servers, then — once GitHub authentication completes — tears down and rebuilds the entire MCP client, re-spawning every configured server. The first generation of stdio child processes is neither killed nor reaped, so each affected session permanently leaks one orphaned MCP server process.

Remote HTTP MCP servers simply reconnect and leave no trace, so the leak is invisible unless you have a local/stdio server configured.

This appears to be a race: only servers that finish their handshake before the post-auth rebuild get orphaned. Servers still cold-starting at that moment are unaffected.

Affected version

GitHub Copilot CLI 1.0.78 (Node v24.18.1)

Steps to reproduce the behavior

My setup: one local (stdio) MCP server (a Python CLI with a slow cold start, roughly 6–50 s) plus two remote HTTP MCP servers.

  1. Configure a stdio MCP server in ~/.copilot/mcp-config.json that completes its handshake within a few seconds of launch.
  2. Start copilot interactively and wait until the session is ready.
  3. Count the child processes for that server: ps -eo pid,ppid,lstart,command | grep <server>
  4. Observe two live child processes under the same CLI pid, spawned roughly 15–50 s apart. Only the second one is actually in use.

Note on reproduction: I could not produce a minimal repro on this machine, because my org's managed MCP allow list rejects any server not on the corporate whitelist (Skipping MCP server "<name>": not permitted by enterprise managed allow list), so a throwaway stdio test server never gets spawned at all. Anyone on an unrestricted account should be able to reproduce with any trivial stdio MCP server.

Expected behavior

When the MCP client is rebuilt after authentication, the previous generation of stdio child processes should be terminated and reaped — the same teardown that 1.0.51 added for session.disconnect().

Ideally the post-authentication reconfiguration would only (re)start the GitHub MCP server rather than recycling every configured server, since the other servers' configuration has not changed.

Additional context

Timeline from one real session (1.0.78), from --log-level debug:

17:16:11  spawn stdio server #1 (pid A); connect HTTP servers
17:17:02  stdio server #1 completes handshake ("Service initialized as client")
17:17:02  [ERROR] GitHub MCP server configured after authentication
17:17:03  → entire MCP client rebuilt:
             - spawn stdio server #2 (pid B)
             - HTTP servers: "worker quit with fatal: Transport channel closed"
             - "Handling tools refresh for <server>"
17:17:14  stdio server #2 completes handshake

pid A is never killed. It keeps running with its stdin pipe dangling.

Decisive evidence that the child is abandoned, not merely idle:

I killed the 6 suspected orphans across my running sessions. All 6 became Z+ (zombie) rather than disappearing:

$ kill 29835 56680 26768 92092 83359 43758
$ ps -p 29835 -o pid=,stat=
29835 Z+

A child only stays a zombie if its parent never called wait()/waitpid(). The CLI processes were still running and still owned these PIDs, but had no outstanding wait on them. After the kill, every session was left with exactly one live MCP child and all sessions kept working normally — confirming the killed ones were dropped, not in use.

Correlation check. Across 4 sessions I compared, the counts matched exactly every time:

occurrences of "GitHub MCP server configured after authentication"
  == number of "Service initialized as client" handshakes for that server
  == number of spawned child processes

Impact. 18 concurrent interactive sessions accumulated 6 orphans. Because this particular stdio server is heavyweight (~25 MB idle, ~570 MB warm), total MCP server residency reached ~3 GB, of which the orphans were pure waste. Long-lived terminal sessions make this monotonically worse — the oldest orphan had been running for 2 days 15 hours before I noticed.

Related issues:

  • #3440 — session.disconnect() does not kill stdio MCP server processes. Closed as fixed in 1.0.51 for the SDK path, but a later comment reports the same leak on 1.0.68 via /new and /resume. This report is a third trigger path: the automatic post-authentication rebuild at startup, which affects plain interactive use with no user action at all. It may be worth fixing the teardown at the MCP-client-rebuild layer rather than per-entry-point.
  • #4206 — quotes the same GitHub MCP server configured after authentication log line for a different symptom, which may help locate the code path.

Environment: macOS 26.6 (darwin-arm64), Node v24.18.1, zsh, Ghostty/iTerm2.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu từ quá trình rebuild sau xác thực được xác định bởi dòng log “GitHub MCP server configured after authentication”, và so sánh quá trình teardown của nó với đường dẫn session.disconnect() được đề cập trong issue. Tái hiện bằng một máy chủ MCP stdio cục bộ và kiểm tra các tiến trình con trước và sau khi xác thực. Được xem là hoàn tất khi thế hệ stdio cũ đã bị chấm dứt và được thu hồi, không còn tiến trình mồ côi hoặc zombie nào.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
node.js
Lĩnh vực
cli, devtools
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Sôi nổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
52/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.