Summary
On Windows, an explicit Path (or any casing other than PATH) passed in StdioServerParameters.env is silently ignored. The inherited PATH from getDefaultEnvironment() wins, so the server runs with the parent's PATH instead of the one the caller configured.
This is separate from #2037 (which variables are inherited). It is about precedence when the caller's key differs only in case.
Where
packages/client/src/client/stdio.ts (main @ 7f7a94c):
env: {
...getDefaultEnvironment(), // emits the key 'PATH'
...this._serverParams.env // caller passes 'Path'
},
The spread keeps both PATH and Path as separate keys. On Windows, Node's child_process resolves duplicate case-insensitive keys by taking the first one in sorted order, and PATH sorts before Path, so the inherited value reaches the child.
Repro (Windows, Node v24.12.0)
import { spawnSync } from 'node:child_process';
const env = { PATH: process.env.PATH, SYSTEMROOT: process.env.SYSTEMROOT, ...{ Path: 'C:\explicit-only' } };
const r = spawnSync(process.execPath, ['-e', 'console.log(process.env.PATH)'], { env });
console.log(r.stdout.toString());
Expected: C:\explicit-only
Actual: the parent's full PATH.
Path is the casing Windows itself uses in process.env keys listings and in many config files, so callers hit this without doing anything unusual.
Suggested fix
When building the merged env on win32, skip an inherited default whose key matches an explicit key case-insensitively (or delete it before spreading). The same fix was proposed for the AI SDK's MCP stdio transport in vercel/ai#21431 / #21435, with regression tests for Path casing.
Happy to open a PR with a test if that's welcome.
Summary
On Windows, an explicit
Path(or any casing other thanPATH) passed inStdioServerParameters.envis silently ignored. The inheritedPATHfromgetDefaultEnvironment()wins, so the server runs with the parent's PATH instead of the one the caller configured.This is separate from #2037 (which variables are inherited). It is about precedence when the caller's key differs only in case.
Where
packages/client/src/client/stdio.ts(main @ 7f7a94c):The spread keeps both
PATHandPathas separate keys. On Windows, Node'schild_processresolves duplicate case-insensitive keys by taking the first one in sorted order, andPATHsorts beforePath, so the inherited value reaches the child.Repro (Windows, Node v24.12.0)
Expected:
C:\explicit-onlyActual: the parent's full PATH.
Pathis the casing Windows itself uses inprocess.envkeys listings and in many config files, so callers hit this without doing anything unusual.Suggested fix
When building the merged env on win32, skip an inherited default whose key matches an explicit key case-insensitively (or delete it before spreading). The same fix was proposed for the AI SDK's MCP stdio transport in vercel/ai#21431 / #21435, with regression tests for
Pathcasing.Happy to open a PR with a test if that's welcome.