Stop the npm wrapper's platform-package auto-install from writing to the caller's package.json - #3184
Open
Dan Dombrowski (djdmbrwsk) wants to merge 1 commit into
Conversation
When the platform package is missing, the wrapper auto-installs it with a bare `npm install`. cwd is inherited from whoever spawned the wrapper, so for an MCP client that is an unrelated user project: npm resolves the nearest package.json from there and saves `@azure/mcp-<platform>-<arch>` into its dependencies and lockfile. `--no-save` was only applied on the second attempt, which never runs when the first one succeeds. Install into a private `.platform` directory inside the wrapper package instead, with `--no-save` and an explicit `--prefix`, and resolve the platform package from there. The directory has no package.json of its own on purpose - pointing npm at the wrapper's own manifest is a no-op, because the platform package is declared there as an optionalDependency that npm is already skipping, which is usually why this code path runs at all (npm skips optional dependencies whose `engines` do not match the running Node, and both packages require `>=22.0.0` as of 3.0.0-beta.27). Also stop inheriting stdout for the install: under `server start` that is the JSON-RPC channel, and npm output written there corrupts the stream. Verified on macOS arm64 with npm 11.6.1: on Node 20 the caller's package.json and lockfile are now untouched while the server still starts, and on Node 22 the platform package resolves as before without the fallback running.
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
|
Thank you for your contribution Dan Dombrowski (@djdmbrwsk)! We will review the pull request and get back to you soon. |
Dan Dombrowski (djdmbrwsk)
force-pushed
the
fix/wrapper-platform-install-no-save
branch
from
July 30, 2026 16:32
33a461b to
95cce2e
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request updates the Azure MCP npm wrapper’s platform-package fallback installation flow to avoid mutating the caller’s project files and to keep stdout clean for JSON-RPC transport.
Changes:
- Install missing
@azure/mcp-<platform>-<arch>packages into a private.platformdirectory under the wrapper instead of the caller’s working directory (using--prefixand--no-save). - Stop sending npm install output to stdout to avoid corrupting the MCP protocol stream during
server start. - Improve troubleshooting output by including the running Node version and the wrapper’s
engines.nodeconstraint.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| servers/Azure.Mcp.Server/CHANGELOG.md | Adds a release note describing the wrapper fix and stdout behavior change. |
| eng/npm/wrapper/index.js | Redirects auto-install into a private directory, updates module resolution accordingly, and enhances diagnostics. |
Author
|
@microsoft-github-policy-service agree |
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.
Problem
When the wrapper can't
requireits platform package, it auto-installs it with a barenpm install(eng/npm/wrapper/index.js#L48-L52):There's no
--no-saveand no--prefix, andcwdis inherited from whoever spawned the wrapper. For an MCP client that's an unrelated user project, so npm walks up from there, finds the user'spackage.json, and saves@azure/mcp-<platform>-<arch>into their dependencies and lockfile.--no-saveis only applied on the second attempt (L58), which never runs because the first one succeeds.I hit this as an unexplained
@azure/mcp-darwin-arm64entry in thedependenciesof a Next.js app with no Azure involvement — it then propagates to CI and to every other developer on the repo via the lockfile.Why the fallback fires at all
npm skips
optionalDependencieswhoseenginesdon't match the running Node, and3.0.0-beta.27raisedengines.nodeto>=22.0.0on the wrapper and the platform packages. On Node 20 the platform package is silently omitted from the install:The wrapper's own engines mismatch is just an
EBADENGINEwarning (it's a direct dependency), so the install looks clean and the failure only shows up at runtime. That skip is what puts users on this code path; whether>=22.0.0is the intended floor is a separate question I've left alone here.Fix
.platformdirectory inside the wrapper package, with--no-saveand an explicit--prefix, and resolve the platform package from that path. The directory intentionally has nopackage.json: pointing npm at the wrapper's own manifest is a no-op, because the platform package is declared there as anoptionalDependencythat npm is already skipping.server startthat's the JSON-RPC channel, so npm output written there can corrupt the protocol stream. The wrapper's own messages already go to stderr.Verification
macOS arm64, npm 11.6.1, against
@azure/mcp@3.0.0-beta.30.Before (Node 20, wrapper run from a project directory):
After (same setup, patched wrapper):
Happy path (Node 22, platform package present): unchanged — the server runs, the fallback never fires, and no
.platformdirectory is created.Notes
eng/npm/wrapper/index.js. Happy to add some if you'd like a preferred location.