[BUG] VS Code config probe starts every MCP server (spawnConfigProbe never sets strictMcpConfig)

Status Open
Reported on v2.1.251
Maintainer reply None cached
Activity 0 comments · opened Aug 31, 2026

Preflight Checklist

  • [x] I have searched existing issues
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code

What's Wrong?

The VS Code extension's config probe starts every configured MCP server, then tears them all down seconds later. This was reported in #15969 (2026-01-01, v2.0.76) and auto-closed as stale without a fix. It still reproduces on extension 2.1.251 / agent-sdk 0.3.251, and I can now add the root cause and the reason it looks intermittent — which I suspect is why it read as unreproducible.

Root cause. loadConfig() in extension.js arms a 500 ms fallback timer:

$.fallbackTimer = setTimeout((Y) => {
    if (this.configResolver !== Y) return;
    this.configResolver = void 0;
    this.spawnConfigProbe().then(Y.resolve, Y.reject);
}, 500, $);

The design is cooperative: a real session spawn calls claimConfigResolver(), which clears the timer, so no probe is needed.

claimConfigResolver(){
  let $ = this.configResolver;
  if ($) clearTimeout($.fallbackTimer), this.configResolver = void 0;
  return $;
}

This is why it's intermittent — it's a race, not a constant. If the session spawns within 500 ms it claims the resolver and nothing extra happens. On a slower machine it loses, and the probe fires. On my box the session spawn lands 653 ms and 1134 ms after loadConfig() — missing the budget by 153 ms and 634 ms. That likely explains why some users see it on every start and others never do.

The actual defect is what the probe spawns. spawnConfigProbe() calls:

this.spawnClaude(Q, void 0, async()=>({behavior:"deny",message:"Config loading only"}),
                 void 0, this.cwd, "default", !1, {type:"disabled"}, void 0)

The 9th parameter is mcpServers, which defaults to {}. But {} only means "inject no extension-side servers" — it does not mean "load none", and strictMcpConfig is never set, so the CLI still loads every server from ~/.claude.json. Grepping the bundle, strictMcpConfig appears three times, all inside the bundled SDK's option plumbing; the extension's own options object never sets it.

So a config-only, deny-everything, throwaway process boots the user's entire MCP stack.

What Should Happen?

The config probe needs no MCP servers at all. It should pass strictMcpConfig: true (with the empty mcpServers) so it starts none.

Impact

Beyond the wasted startup work, servers with side effects at boot do them twice:

  • Serena opens its web dashboard in a browser tab on launch, so users get two tabs on consecutive ports, one of them dead within seconds. That is the visible symptom in #15969 and the reason I chased this.
  • Any server that fetches on start pays the network cost twice. A uvx --from git+... server re-resolves the git remote per launch (~1.5 s measured here).
  • Servers that acquire a lock, bind a port, or register a session get a spurious second instance.

Error Messages/Logs

Extension log, one session start (paths shortened):

09:41:28.077 [info] Loading config cache by launching Claude (no channel)...
09:41:28.189 [info] Spawning Claude with SDK query function - permission mode: default, version: 2.1.251, resume: undefined
09:41:28.711 [info] Spawning Claude with SDK query function - permission mode: auto,    version: 2.1.251, resume: ef7bf00a-...
09:41:30.348 [DEBUG] MCP server "serena": Starting connection with timeout of 30000ms
09:41:31.217 [DEBUG] MCP server "serena": Starting connection with timeout of 30000ms
09:41:35.880 [DEBUG] MCP server "serena": Successfully connected (transport: stdio) in 4666ms

Two serena connections ~900 ms apart from a single session start. Only one of them is ever used. From the discarded instance's own server-side log:

09:41:35,143 serena.mcp:server_lifespan:408 - MCP server lifetime setup complete
09:41:35,147 serena.mcp:server_lifespan:415 - MCP server shutting down

It completes the full handshake and is shut down 4 ms later, having served zero ListToolsRequest calls — it did all the startup work and answered nothing. Counting server logs across three days on this machine, 25 of 59 Serena starts never served a ListToolsRequest. Slightly over 40% of all MCP server launches here were probe launches.

Steps to Reproduce

  1. Configure any stdio MCP server in ~/.claude.json (Serena makes it visible, since it opens a browser tab at launch).
  2. Open a workspace in VS Code and start or resume a Claude session.
  3. Watch the extension output for Loading config cache by launching Claude (no channel)... followed by two Spawning Claude lines, and two Starting connection lines for the same server.

Because it is a 500 ms race, it reproduces most reliably where session startup is slow — a large workspace, a cold cache, or a remote/WSL setup.

Suggested Fix

Pass strictMcpConfig: true from spawnConfigProbe(). The SDK already supports the option.

Claude Code Version

2.1.251 (extension), agent-sdk 0.3.251

Platform

Anthropic API (subscription login)

Operating System

Linux — WSL2 Ubuntu 26.04, VS Code Remote-WSL. Originally reported on macOS in #15969, so it is not platform-specific.

Is this a regression?

No — previously reported as #15969 against 2.0.76 and auto-closed as stale while still present.

Related prior reports, all closed and locked without a fix: #15969 (this exact symptom), #60045 (config probe timing out), #15973 (singleton MCP spawning, closed as duplicate), #23915 (double activation / process duplication, closed as duplicate). Because every one of them is locked, this could not be raised as a comment on the existing threads.

View original on GitHub ↗