Skip to content

fix(client): let an explicit env var replace the inherited default in any casing on Windows - #2874

Open
ohad6k wants to merge 1 commit into
modelcontextprotocol:v1.xfrom
ohad6k:fix/win32-env-casing
Open

ohad6k wants to merge 1 commit into
modelcontextprotocol:v1.xfrom
ohad6k:fix/win32-env-casing

Conversation

@ohad6k

@ohad6k ohad6k commented Sep 25, 2026

Copy link
Copy Markdown

Fixes #2859.

On Windows, environment variable names are case-insensitive, but StdioClientTransport builds the child env with a plain object spread:

env: { ...getDefaultEnvironment(), ...this._serverParams.env }

getDefaultEnvironment() stores the inherited value under PATH. If the caller passes Path, the spread keeps both keys, and the child ends up with the inherited PATH instead of the one the caller configured.

This change routes the merge through a small private helper. On win32 it skips an inherited default whenever env already has the same name in any casing, then applies env on top. On every other platform it is the same spread as before. getDefaultEnvironment() and DEFAULT_INHERITED_ENV_VARS are unchanged.

A side effect of the old behaviour: cross-spawn already resolved command with the explicit Path (path-key picks the last matching key), but the child then ran with the inherited PATH, so the command was found with one PATH and run with the other. With this change both use the caller's value.

The Windows casing half mirrors a fix merged this week in the Vercel AI SDK's MCP client, vercel/ai#21435.

Tests:

  • test/client/cross-spawn.test.ts: with process.platform set to win32 and env: { Path: 'C:\\explicit-only' }, the spawned env equals every other inherited default plus Path, so it also fails if the merge ever drops the rest of the defaults. A second test pins the non-Windows behaviour: keys stay case-sensitive and the result is the plain spread.
  • test/client/stdio.test.ts: a Windows-only test spawns a real node child that reports its PATH-like key names and whether PATH equals the explicit value, so a failure never prints the machine's PATH. Without the fix the child sees the parent's PATH, with it the child sees C:\explicit-only.

Both win32 tests fail on v1.x without the source change and pass with it (Windows 11, Node 24.12.0). npm run lint and npm run typecheck pass. Added a patch changeset.

One note for Windows runs: the existing more based tests in test/client/stdio.test.ts log 2 unhandled "Unexpected end of JSON input" errors. That happens on v1.x without this change too, so I left it alone.

main has the same merge in packages/client/src/client/stdio.ts. Happy to send a port there as well if you want it.

🤖 Generated with Claude Code

… any casing on Windows

Fixes modelcontextprotocol#2859.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ohad6k
ohad6k requested a review from a team as a code owner September 25, 2026 11:50
@changeset-bot

changeset-bot Bot commented Sep 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c99b0b2

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

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

@pkg-pr-new

pkg-pr-new Bot commented Sep 25, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@modelcontextprotocol/sdk@2874

commit: c99b0b2

@claude claude Bot added the v1 Issues / PRs related to v1.x label Sep 26, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v1 Issues / PRs related to v1.x

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant