Copilot Chat edit/apply_patch tool stalls in an indefinite "tools changed"-style loop; no longer limited to MCP calls, survives full VS Code restart
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
### Environment
- VS Code: 1.132.0 (macOS, arm64)
- Extension: GitHub.copilot-chat, version 0.41 (2026-03-25)
- MCP server involved in earlier occurrences: a remote MCP server (company internal connector to Jira in our environment)
### Summary
In long-running Copilot Chat sessions, the extension host repeatedly logs
`[CopilotCLI] Handling tools changed notification for ` in a tight
~500ms loop that never self-resolves. This correlates directly with
`edit`/`apply_patch` tool calls appearing to hang or get silently interrupted
mid-turn. **Update:** the same stall has now also been observed originating
from the plain edit/create file tool with **no MCP call involved at all**,
and in the latest occurrence it **persisted through a full VS Code restart**
— previously the one reliable mitigation. Terminal/command-line tool calls
continued to work normally while the edit tool was stuck, suggesting the
failure is scoped to the edit/apply-patch code path rather than the whole
extension host.
### Root cause (MCP-triggered variant, confirmed via logs)
Two cooperating issues:
1. **Route/gateway leak** — every chat turn creates a new route + gateway for
the MCP server. Gateways are "disposed" (`Attempted to dispose unknown
gateway` warning — already gone from the tracking map) but the underlying
**route is never removed**. `active routes` only ever increases across a
session (observed 1 → 2 → … → 52+).
2. **Fan-out amplification** — after any tool call to that server, Copilot
re-fetches `tools/list`. If the server's response isn't byte-identical
across calls, `McpGatewayService` fires `Gateway servers changed`
**once per accumulated leaked route/gateway** (23 simultaneous lines at
the identical millisecond timestamp were observed), each broadcasting a
`notifications/tools/list_changed` to its client session — one upstream
event becomes N client notifications, each re-triggering a `tools/list`
re-fetch, sustaining the cycle indefinitely (~500ms cadence in our case).
### New evidence: not MCP-exclusive, restart no longer reliable
In the most recent occurrence (2026-08-06):
- The loop/stall triggered via the plain edit/create file tool, with no MCP
tool call in the turn at all.
- A full VS Code quit+reopen did **not** clear it (every prior MCP-triggered
occurrence cleared immediately on restart).
- CLI/terminal-based tool calls kept working normally throughout.
This suggests either (a) a structurally similar leak exists independently in
the edit/apply-patch tool's own request/notification routing, or (b) the
MCP-originated leaked state isn't fully cleared by a normal restart in all
cases and resurfaces through the edit tool's path instead. Either way, please
don't treat "restart VS Code" as a confirmed fix when triaging — it is
inconsistent in our reports.
### Minimum repro (MCP-triggered variant)
1. Keep a single window open across many chat turns with an MCP server
configured until routes have accumulated well beyond 1.
2. Make one successful tool call to that MCP server.
3. Within ~1s, `Handling tools changed notification for ` begins
firing every ~500ms and does not stop (12 notifications by +1s, 62+ by
+15s, sustained 35+ seconds and counting in testing). A fresh window with
0 accumulated routes does not reproduce it from the same tool call.
### Impact
- Sustained extension-host load; `edit`/`apply_patch` calls hang or silently
fail/restart mid-turn.
- Recurring across multiple unrelated workspaces/repos, with increasing
frequency (now multiple times per day in long sessions).
- Previously the only reliable mitigation was a full VS Code restart; this is
no longer consistently effective (see "New evidence" above).
### Suggested fix
- Ensure routes (not just gateways) are actually removed when a chat
turn/gateway is disposed, so they don't accumulate unboundedly per session.
- De-duplicate/debounce `servers changed` → `tools/list_changed` broadcasts so
one upstream change produces at most one client notification.
- Investigate whether the edit/apply-patch tool has its own, independent
request/notification queue that can enter the same "never torn down, only
grows" failure mode, since it now reproduces without any MCP server in the
loop.
Potential duplicate:
https://github.com/microsoft/vscode/issues/317440 (closed with missing information / not planned)
https://github.com/microsoft/vscode/issues/317432 (closed as duplicate)
Contributor guide
Assessment
This issue has not been assessed yet.