Skip to content

fix: prevent MCP servers from restarting repeatedly on settings save - #5817

Closed
markijbema wants to merge 2 commits into
mainfrom
mark/fix-mcp-restart-loop
Closed

fix: prevent MCP servers from restarting repeatedly on settings save#5817
markijbema wants to merge 2 commits into
mainfrom
mark/fix-mcp-restart-loop

Conversation

@markijbema

Copy link
Copy Markdown
Contributor

Problem

When saving settings, all MCP servers restart and keep restarting in a loop.

Root Causes & Fixes

1. Config deep-equal mismatch (stored injected config vs raw validated config)

updateServerConnections() compared the stored config (post-injectVariables()) against the incoming Zod-validated config (pre-injection). If any variable substitution occurred (${workspaceFolder}, ${env:*}, etc.), configs would never match — causing every server to restart on every config re-read.

Fix: Added rawConfig field to connection types that stores the pre-injection validated config. Changed the comparison in updateServerConnections() to use rawConfig against validatedConfig.

2. isProgrammaticUpdate flag timing race

debounceConfigChange() checked the flag only at entry time. The debounced handler fires 500ms later, but the flag resets at 600ms. If a file system event arrives after the flag resets, the config change would be processed — restarting servers for config we wrote ourselves.

Fix: Added a re-check of isProgrammaticUpdate inside the debounced callback.

3. Fire-and-forget transport.close() triggering auto-reconnect

deleteConnection() called cancelReconnect() then fired transport.close() as fire-and-forget (not awaited). The onclose handler would run after cancelReconnect completed, calling scheduleReconnect() again — racing with the normal restart flow.

Fix: Added intentionalDisconnects set. deleteConnection() marks servers before closing. All onclose/onerror handlers skip scheduleReconnect() for intentional disconnects.

Testing

All 44 existing McpHub tests pass.

Three root causes fixed:
1. Config deep-equal mismatch: stored injected config vs raw validated config
   always differed due to variable injection, causing spurious restarts.
   Fix: store rawConfig (pre-injection) on connections for accurate comparison.

2. isProgrammaticUpdate race condition: debounce callback only checked the
   flag at entry, not when the timer fires 500ms later.
   Fix: re-check isProgrammaticUpdate inside the debounced callback.

3. Fire-and-forget transport.close() triggered auto-reconnect: onclose
   handler called scheduleReconnect after cancelReconnect had already run.
   Fix: intentionalDisconnects guard prevents onclose from scheduling
   reconnect during programmatic disconnects.
@changeset-bot

changeset-bot Bot commented Feb 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e0ba998

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
kilo-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

jeremylongshore added a commit to jeremylongshore/kilocode that referenced this pull request Feb 15, 2026
jeremylongshore added a commit to jeremylongshore/kilocode that referenced this pull request Feb 15, 2026
Mirror: fix: prevent MCP servers from restarting repeatedly on settings save (Kilo-Org#5817)
jeremylongshore added a commit to jeremylongshore/kilocode that referenced this pull request Feb 15, 2026
@markijbema markijbema closed this Feb 19, 2026
@markijbema
markijbema deleted the mark/fix-mcp-restart-loop branch February 22, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant