fix(client): honour explicit Path casing in stdio env on Windows - #2871
Open
sean-park-funda wants to merge 1 commit into
Open
sean-park-funda wants to merge 1 commit into
sean-park-funda wants to merge 1 commit into
Conversation
Windows environment variables are case-insensitive, but an object spread is not: the PATH produced by getDefaultEnvironment and a caller's Path survived the merge as two separate keys. Node's child_process resolves that duplicate by taking the first in sorted order, so the inherited PATH reached the child and the configured one was silently dropped. Path is the casing Windows itself uses when listing process.env and in many config files, so callers hit this without doing anything unusual. Drop an inherited default when the caller supplied the same variable under any casing, on win32 only. Elsewhere the two names are genuinely different variables and both are kept. Fixes modelcontextprotocol#2859 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 4365653 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
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 |
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/core
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2859.
The problem
Windows environment variables are case-insensitive, but an object spread is not:
Both keys survive the merge. Node's
child_processthen resolves the duplicate by taking the first in sorted order, andPATHsorts beforePath, so the inherited value reaches the child and the caller's configured one is silently dropped.Pathis the casing Windows itself uses when listingprocess.envand in many config files, so callers hit this without doing anything unusual.The change
mergeDefaultEnvironmentdrops an inherited default when the caller supplied the same variable under any casing — on win32 only. Off Windows,PATHandPathare genuinely two different variables and dropping either would be wrong, so the plain spread is kept there.The helper is exported from
src/client/stdioso the tests can reach it, but deliberately not added to theclient/stdiosubpath barrel: this is a fix, not a new public API.On verification
I could not run the Windows repro from the issue — I am on macOS. What I did instead was pin the mechanism in a unit test and confirm it goes red without the fix:
That is the duplicate-key state the issue describes, reproduced directly. The remaining step — that
child_processprefersPATHonce both keys are present — is the part I am taking from the issue's repro and Node's documented behaviour rather than having observed myself. Worth a maintainer with a Windows box confirming end to end before merge.Platform is mocked with
Object.defineProperty(process, 'platform', ...), matching the existing pattern incrossSpawn.test.ts.Testing
Four cases in
packages/client/test/client/stdio.test.ts: theundefinedenv copy, the win32 case-mismatch override, a win32 exact-case override with unrelated defaults preserved, and the POSIX case where both names must stay.vitest runinpackages/client— 38 files, 895 tests, all passing.pnpm typecheck,eslintandprettier --checkclean.DEFAULT_INHERITED_ENV_VARSis untouched, so thestdioEnvPinsbehaviour-surface pins are unaffected. Changeset included (@modelcontextprotocol/client: patch).This PR was authored by an AI agent at Vibement Inc. The diff has been read and understood before sending, and I can answer design questions about it.