Summary
On Windows 11 over a residential connection in Australia, every Desktop Commander cold start blocks for ~30 seconds between the client's initialize request and the server's initialize response. Claude Desktop reports the MCP server as failing to connect during this window; if the user is impatient and disables/re-enables the server, the cycle repeats.
The cause is the feature flags fetch in dist/utils/feature-flags.js:
this.flagUrl = process.env.DC_FLAG_URL ||
'https://desktopcommander.app/flags/v2/production.json';
// ...
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
const response = await fetch(this.flagUrl, { signal: controller.signal, ... });
The 5-second AbortController timeout does not prevent the 30s startup hang. The request seems to hang at the TCP connect level, which the abort signal apparently isn't interrupting on this Node/Windows combination, and ends up bound by the Windows-level TCP connect timeout instead.
The empirical proof is unambiguous: with WiFi disabled, startup completes in ~1.6 seconds (DNS resolution fails fast → fetch rejects immediately → process continues). With WiFi enabled, startup takes ~31 seconds every time.
Environment
Desktop Commander: 0.2.40 (installed as DXT extension)
Claude Desktop: 1.6608.0.0 (Microsoft Store / WindowsApps)
OS: Windows 11
Node.js: 24.15.0 (bundled with Claude Desktop)
undici: 7.24.4
Client: claude-ai 0.1.0
User location / network: Brisbane, Australia, residential ISP
Note: desktopcommander.app itself is reachable from this network — curl and a browser load it without trouble. The connect is just slow enough that the JS-level AbortController apparently doesn't preempt it.
Reproduction
- Install Desktop Commander on a Windows host located somewhere with high latency / slow TCP connect to
desktopcommander.app (Australia, parts of Africa, anywhere with degraded transit to the flags origin).
- Restart Claude Desktop.
- Observe
mcp-server-Desktop Commander.log — the time between the client's initialize request and the server's initialize response is ~30 seconds.
To confirm the cause:
- Disable the network adapter, restart Claude Desktop. Startup completes in ~2 seconds.
- Re-enable the network. Startup is slow again.
- As a workaround, blackhole the host in
C:\Windows\System32\drivers\etc\hosts
0.0.0.0 desktopcommander.app
Startup returns to ~2 seconds permanently.
Evidence (log excerpts)
Slow startup (network enabled), ~31s gap:
05:23:01.443 Server started and connected successfully
05:23:01.498 Message from client: initialize (id:0)
⋮ 31 seconds elapse ⋮
05:23:32.599 Message from server: initialize response (id:0)
05:23:32.601 Message from client: tools/list, prompts/list, resources/list
05:23:32.672 Replaying 2 buffered initialization messages
05:23:32.672 Loaded 3 feature flags from cache
05:23:32.673 MCP fully initialized, all startup messages sent
05:23:32.679 Message from server: tools list response (id:1, ~78ms)
Fast startup (network disabled), ~1.6s gap:
05:50:23.380 Server started and connected successfully
05:50:23.385 Message from client: initialize (id:0)
05:50:25.004 Message from server: initialize response (id:0)
05:50:25.072 Loaded 3 feature flags from cache
05:50:25.073 MCP fully initialized, all startup messages sent
05:50:25.074 Failed to fetch feature flags: fetch failed ← key line
05:50:25.079 tools list response (~6ms)
The "Failed to fetch feature flags: fetch failed" line confirms the fetch is what's being preempted; without the network, it fails immediately and startup proceeds.
Root cause notes
featureFlagManager.initialize() is documented as non-blocking and the inner this.fetchFlags() call is fire-and-forget, so on paper this shouldn't delay the initialize response. In practice it does — the empirical 30s vs 1.6s difference correlates 1:1 with whether desktopcommander.app is reachable. Two possible (not mutually exclusive) explanations worth checking:
AbortController not interrupting in-progress TCP connect in Node 24.15 / undici 7.24.4 on Windows for connections that are slowly succeeding rather than failing. The setTimeout(() => controller.abort(), 5000) fires, but the underlying socket continues to negotiate until the OS-level connect timeout returns (~30s on Windows by default), at which point the awaited fetch finally rejects.
- Some
await chain blocking the SDK's initialize response on the fetch promise — e.g. via waitForFreshFlags() or an unawaited promise that nonetheless gates a downstream handler. (Couldn't pin this down by reading dist/, but it's consistent with the timing.)
Either way, the fix is to ensure the feature flags fetch can never delay startup, regardless of network conditions.
Suggested fixes
In rough priority order:
- Add an env flag to disable the fetch entirely, e.g.
DC_DISABLE_FLAG_FETCH=1. Trivial to implement in feature-flags.js, immediately rescues affected users, and doesn't depend on diagnosing the AbortController behavior.
- Document
DC_FLAG_URL in the README/FAQ so users with this problem can at least redirect the fetch to http://127.0.0.1:1 (which fails fast). Right now it's only discoverable by reading source.
- Hard-cap the fetch with
Promise.race against an explicit setTimeout reject, so the 5s budget is enforced regardless of whether AbortController actually interrupts the underlying socket. Something like:
const fetchPromise = fetch(this.flagUrl, { signal: controller.signal, ... });
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Feature flags fetch timed out')), 5000)
);
const response = await Promise.race([fetchPromise, timeoutPromise]);
- Lower the fetch timeout to 2-3 seconds. The flags load from cache anyway; a fresh fetch isn't worth even 5 seconds of perceived startup latency.
- Confirm
fetchFlags() truly never blocks the initialize response. A unit/integration test that measures initialize latency with a mocked slow flags endpoint would catch regressions like this.
Workaround for affected users
Add to C:\Windows\System32\drivers\etc\hosts (run editor as Administrator):
0.0.0.0 desktopcommander.app
Followed by ipconfig /flushdns. Restart Claude Desktop. Startup drops from ~30s to ~2s. The flags subsystem keeps running off its local cache (Loaded 3 feature flags from cache), and as long as the cache file exists this has no functional impact.
Happy to provide additional logs or test patches against main if useful. Thanks for the project.
Summary
On Windows 11 over a residential connection in Australia, every Desktop Commander cold start blocks for ~30 seconds between the client's
initializerequest and the server'sinitializeresponse. Claude Desktop reports the MCP server as failing to connect during this window; if the user is impatient and disables/re-enables the server, the cycle repeats.The cause is the feature flags fetch in
dist/utils/feature-flags.js:The 5-second
AbortControllertimeout does not prevent the 30s startup hang. The request seems to hang at the TCP connect level, which the abort signal apparently isn't interrupting on this Node/Windows combination, and ends up bound by the Windows-level TCP connect timeout instead.The empirical proof is unambiguous: with WiFi disabled, startup completes in ~1.6 seconds (DNS resolution fails fast → fetch rejects immediately → process continues). With WiFi enabled, startup takes ~31 seconds every time.
Environment
Desktop Commander: 0.2.40 (installed as DXT extension)
Claude Desktop: 1.6608.0.0 (Microsoft Store / WindowsApps)
OS: Windows 11
Node.js: 24.15.0 (bundled with Claude Desktop)
undici: 7.24.4
Client: claude-ai 0.1.0
User location / network: Brisbane, Australia, residential ISP
Note:
desktopcommander.appitself is reachable from this network —curland a browser load it without trouble. The connect is just slow enough that the JS-levelAbortControllerapparently doesn't preempt it.Reproduction
desktopcommander.app(Australia, parts of Africa, anywhere with degraded transit to the flags origin).mcp-server-Desktop Commander.log— the time between the client'sinitializerequest and the server'sinitializeresponse is ~30 seconds.To confirm the cause:
C:\Windows\System32\drivers\etc\hosts0.0.0.0 desktopcommander.appStartup returns to ~2 seconds permanently.
Evidence (log excerpts)
Slow startup (network enabled), ~31s gap:
Fast startup (network disabled), ~1.6s gap:
The "Failed to fetch feature flags: fetch failed" line confirms the fetch is what's being preempted; without the network, it fails immediately and startup proceeds.
Root cause notes
featureFlagManager.initialize()is documented as non-blocking and the innerthis.fetchFlags()call is fire-and-forget, so on paper this shouldn't delay theinitializeresponse. In practice it does — the empirical 30s vs 1.6s difference correlates 1:1 with whetherdesktopcommander.appis reachable. Two possible (not mutually exclusive) explanations worth checking:AbortControllernot interrupting in-progress TCP connect in Node 24.15 / undici 7.24.4 on Windows for connections that are slowly succeeding rather than failing. ThesetTimeout(() => controller.abort(), 5000)fires, but the underlying socket continues to negotiate until the OS-level connect timeout returns (~30s on Windows by default), at which point the awaitedfetchfinally rejects.awaitchain blocking the SDK'sinitializeresponse on the fetch promise — e.g. viawaitForFreshFlags()or an unawaited promise that nonetheless gates a downstream handler. (Couldn't pin this down by readingdist/, but it's consistent with the timing.)Either way, the fix is to ensure the feature flags fetch can never delay startup, regardless of network conditions.
Suggested fixes
In rough priority order:
DC_DISABLE_FLAG_FETCH=1. Trivial to implement infeature-flags.js, immediately rescues affected users, and doesn't depend on diagnosing the AbortController behavior.DC_FLAG_URLin the README/FAQ so users with this problem can at least redirect the fetch tohttp://127.0.0.1:1(which fails fast). Right now it's only discoverable by reading source.Promise.raceagainst an explicit setTimeout reject, so the 5s budget is enforced regardless of whetherAbortControlleractually interrupts the underlying socket. Something like:fetchFlags()truly never blocks the initialize response. A unit/integration test that measuresinitializelatency with a mocked slow flags endpoint would catch regressions like this.Workaround for affected users
Add to
C:\Windows\System32\drivers\etc\hosts(run editor as Administrator):0.0.0.0 desktopcommander.appFollowed by
ipconfig /flushdns. Restart Claude Desktop. Startup drops from ~30s to ~2s. The flags subsystem keeps running off its local cache (Loaded 3 feature flags from cache), and as long as the cache file exists this has no functional impact.Happy to provide additional logs or test patches against
mainif useful. Thanks for the project.