Skip to content

fix(agents): use cmd /c npx on Windows for init-agents MCP config#39221

Open
SeoJaeWan wants to merge 5 commits intomicrosoft:mainfrom
SeoJaeWan:docs/agents-windows-mcp-workaround
Open

fix(agents): use cmd /c npx on Windows for init-agents MCP config#39221
SeoJaeWan wants to merge 5 commits intomicrosoft:mainfrom
SeoJaeWan:docs/agents-windows-mcp-workaround

Conversation

@SeoJaeWan
Copy link

@SeoJaeWan SeoJaeWan commented Feb 11, 2026

Summary

  • On Windows, npx resolves to npx.cmd (a batch file) which cannot be executed by MCP clients using child_process.spawn() without shell: true
  • Added platform detection in generateAgents.ts for Claude generator to use cmd /c npx on Windows
  • Other generators unchanged: VS Code handles .cmd resolution internally, Copilot runs on GitHub cloud, Opencode spawns a shell

Changes

  • ClaudeGenerator.init(): generates .mcp.json with cmd /c npx on Windows
  • Added 1 test in tests/mcp/init-agents.spec.ts verifying MCP config output for claude generator

Test plan

  • Build passes
  • All 4 init-agents tests pass
  • Verified VS Code works with plain npx on Windows (no cmd /c needed)
  • Test uses if/else platform branching, validated across CI environments (ubuntu, macos, windows)

@SeoJaeWan
Copy link
Author

SeoJaeWan commented Feb 11, 2026

@microsoft-github-policy-service agree

@Skn0tt
Copy link
Member

Skn0tt commented Feb 11, 2026

Instead of a docs note, i'd prefer fixing our output - would you like to contribute a PR that fixes the install command?

@SeoJaeWan SeoJaeWan force-pushed the docs/agents-windows-mcp-workaround branch from 58e7f6c to 9cbfb37 Compare February 11, 2026 14:06
@SeoJaeWan SeoJaeWan changed the title docs(agents): add Windows workaround for MCP server npx command fix(agents): use cmd /c npx on Windows for init-agents MCP config Feb 11, 2026
@SeoJaeWan
Copy link
Author

SeoJaeWan commented Feb 11, 2026

@Skn0tt Updated the PR to fix the init-agents output instead of adding a docs note.

Changes:

  • Added npxCommand() helper in generateAgents.ts to wrap npx with cmd /c on Windows
  • Applied to Claude, VSCode, and Opencode generators (local execution)
  • Left Copilot generator unchanged since it runs remotely on GitHub (Linux) via remote: true

Verified the generated configs on Windows for all 4 generators.

@Skn0tt
Copy link
Member

Skn0tt commented Feb 11, 2026

Thanks! Could you add tests to tests/mcp/init-agents.spec.ts?

@SeoJaeWan
Copy link
Author

@Skn0tt Thanks for the review! Added tests in tests/mcp/init-agents.spec.ts that verify the generated MCP config for each generator (claude, vscode, opencode). The tests assert platform-correct command/args values using process.platform, so they will validate across all 3 CI environments (ubuntu, macos, windows).

Copy link
Member

@Skn0tt Skn0tt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're getting there! it seems that not all targets have the distinction (copilot, opencode), so let's keep this change focused on those that do.

asOpencodeTool(tools, tool);
}

const { command, args } = npxCommand(['playwright', 'run-test-mcp-server']);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opencode seems to spawn a shell, so we should also pick 'npx' here. maybe let's not use the abstraction?

await runInitAgents({ cwd: baseDir, args: ['--loop', 'claude'] });

const mcpJson = JSON.parse(fs.readFileSync(path.join(baseDir, '.mcp.json'), 'utf-8'));
expect(mcpJson.mcpServers['playwright-test'].command).toBe(expectedCommand);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we usually have this structure in our test suite so that tests can be copied easily, let's match that.

Suggested change
expect(mcpJson.mcpServers['playwright-test'].command).toBe(expectedCommand);
if (process.platform === 'win32')
expect(mcpJson.mcpServers['playwright-test'].command).toBe(expectedCommand);
else
expect(mcpJson.mcpServers['playwright-test'].command).toBe(expectedCommand);

@SeoJaeWan
Copy link
Author

SeoJaeWan commented Feb 11, 2026

@Skn0tt Thank you so much for the thorough review. Sorry for the over-engineering — I didn’t realize opencode spawns a shell, so the cmd /c wrapping isn’t needed there.

I’ve narrowed the scope to only the Claude and VSCode generators, removed the npxCommand() abstraction, reverted the Copilot and Opencode changes, and restructured the tests using the suggested if/else pattern.

Appreciate the guidance — I’ve updated the PR with these changes.

@Skn0tt
Copy link
Member

Skn0tt commented Feb 11, 2026

Cool, i'll quickly test this out myself on Windows. Could you do me a favor and revert those whitespace changes in the md file?

@SeoJaeWan
Copy link
Author

@Skn0tt Done! Reverted the whitespace change in the md file.

@Skn0tt
Copy link
Member

Skn0tt commented Feb 11, 2026

I could repro the bug with Claude and can see the fix works. But with VS Code, it already worked prior to the fix. Did you see this happen under VS Code as well? If not, let's trim down this PR to just the Claude fix.

Taking a step back, I wonder if this should be fixed by Claude Code itself - if what we generate is platform-specific, it can't be comitted into repositories that need to work under different platforms.

@SeoJaeWan
Copy link
Author

@Skn0tt Thanks for checking! Sorry for the noise — you’re right.

I was able to reproduce the issue with Claude Code, but I haven’t been able to reproduce it in VS Code either (it seems to work there even before this change). I had already started trimming the PR, and I’ll update it to keep the fix scoped to the Claude generator only.

@Skn0tt
Copy link
Member

Skn0tt commented Feb 11, 2026

I have a weird question to ask. Are you a human? You respond so quickly and so well-written that nowadays, I have to suspect you're OpenClaw!

@SeoJaeWan
Copy link
Author

I’m a Korean developer, and I’m genuinely excited that I can contribute to open source for the first time.

It’s 12:40 AM here in Korea, and I can’t fall asleep because I’m so focused on this PR. I’m just staying up and waiting for the review updates.

@SeoJaeWan
Copy link
Author

image I’m sorry for the mistakes — my enthusiasm got ahead of me.

@SeoJaeWan
Copy link
Author

@Skn0tt Updated — narrowed the scope to Claude generator only. VS Code confirmed working with plain npx on Windows. The PR now has just the Claude fix + 1 test.

@SeoJaeWan
Copy link
Author

@Skn0tt Your suspicion is understandable, and I realize I’ve made too many mistakes. I sincerely apologize for that.

Copy link
Member

@Skn0tt Skn0tt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me. i'm torn on whether we should be fixing it, since it's really on claude to do it - but erring on the side of making it work today, so that we can revert once claude fixed it. cc @dgozman for double-checking.

@Skn0tt Skn0tt requested a review from dgozman February 11, 2026 15:45
@Skn0tt
Copy link
Member

Skn0tt commented Feb 11, 2026

Your suspicion is understandable, and I realize I’ve made too many mistakes. I sincerely apologize for that.

No worries! It's not the mistakes, it's the speed that got me suspicious :D Good to hear you're enjoying contributing to open source, it's a wonderful thing 👍

@SeoJaeWan
Copy link
Author

@Skn0tt
Thank you so much for being so kind about it — I really appreciate it.

It’s getting late here, so I think I should finally get some sleep. I’ll be able to respond again in about 5 hours.

This PR has been one of the most nerve-wracking, thrilling, and exciting moments in my developer life — and I’m grateful for your patience and encouragement. Thank you!

@github-actions
Copy link
Contributor

Test results for "tests 1"

5 failed
❌ [playwright-test] › aria-snapshot-file.spec.ts:225 › should respect config.expect.toMatchAriaSnapshot.pathTemplate @macos-latest-node20
❌ [playwright-test] › playwright.spec.ts:485 › should work with video: on-first-retry @macos-latest-node20
❌ [playwright-test] › playwright.trace.spec.ts:137 › should not throw with trace: on-first-retry and two retries in the same worker @macos-latest-node20
❌ [playwright-test] › reporter.spec.ts:251 › created › should not have internal error when steps are finished after timeout @macos-latest-node20
❌ [playwright-test] › update-aria-snapshot.spec.ts:669 › update-source-method › should overwrite source when specified in the config @macos-latest-node20

1 flaky ⚠️ [playwright-test] › ui-mode-trace.spec.ts:700 › should indicate current test status `@macos-latest-node20`

38553 passed, 843 skipped


Merge workflow run.

@github-actions
Copy link
Contributor

Test results for "MCP"

5 failed
❌ [chromium] › mcp/cli-save-as.spec.ts:19 › screenshot @mcp-macos-15
❌ [chromium] › mcp/http.spec.ts:263 › http transport shared context @mcp-macos-15
❌ [chromium] › mcp/launch.spec.ts:21 › test reopen browser @mcp-macos-15
❌ [firefox] › mcp/cli-session.spec.ts:50 › close non-running session @mcp-macos-15
❌ [firefox] › mcp/cli-session.spec.ts:152 › workspace isolation - sessions in different workspaces are isolated @mcp-macos-15

4787 passed, 135 skipped


Merge workflow run.

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.

3 participants