Repository navigation
fix(package): restore npx @modelcontextprotocol/inspector with an inspector bin alias #2652
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
397d66d
fix(package): restore `npx @modelcontextprotocol/inspector` with an `…
cliffhall 7759adb
chore(package): record the inspector bin alias in package-lock.json (…
cliffhall c92978e
docs(readme): list mcpdo among the clients, with its npx command (#2651)
cliffhall File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| /** | ||
| * Which bin `npx <package>` / `npm exec <package>` runs, by npm's own rule | ||
| * (#2651). | ||
| * | ||
| * A mirror of `getBinFromManifest` in npm's bundled `libnpmexec` | ||
| * (`lib/get-bin-from-manifest.js`): run the sole bin when every entry points at | ||
| * the same file; otherwise run the bin named after the package's **unscoped** | ||
| * name; otherwise npm fails with "could not determine executable to run". | ||
| * | ||
| * 2.10.0 shipped exactly that failure. Adding `mcpdo` gave the package a second | ||
| * distinct bin, and nothing named `inspector` existed, so the documented | ||
| * `npx @modelcontextprotocol/inspector` stopped working for everyone — while | ||
| * `pack:verify` and every smoke stayed green, because they all invoke the | ||
| * installed bin by name and never ask npm to choose one. This is the offline | ||
| * half of the guard (its test asserts the root manifest); `pack:verify` runs | ||
| * the installed tarball through `npm exec` for the online half. | ||
| * | ||
| * Mirrored rather than imported: `libnpmexec` is npm's internal dependency, not | ||
| * one of ours, and its location depends on how Node was installed. | ||
| */ | ||
|
|
||
| /** | ||
| * @param {{ name: string, bin?: string | Record<string, string> }} manifest | ||
| * @returns {string | null} the bin name npm would run, or null where npm fails | ||
| */ | ||
| export function npxDefaultBin(manifest) { | ||
| // npm normalizes a string `bin` to `{ <unscoped name>: <path> }` on publish. | ||
| const name = manifest.name.replace(/^@[^/]+\//, ""); | ||
| const bin = | ||
| typeof manifest.bin === "string" | ||
| ? { [name]: manifest.bin } | ||
| : (manifest.bin ?? {}); | ||
| const entries = Object.keys(bin); | ||
| if (new Set(Object.values(bin)).size === 1) return entries[0]; | ||
| if (bin[name]) return name; | ||
| return null; | ||
| } |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| // Tests for `npx-default-bin.mjs` (#2651): npm's default-bin rule, and the | ||
| // assertion that the root manifest — the one that publishes — resolves | ||
| // `npx @modelcontextprotocol/inspector` to the launcher. | ||
|
|
||
| import { test } from "node:test"; | ||
| import assert from "node:assert/strict"; | ||
| import { readFileSync } from "node:fs"; | ||
| import path from "node:path"; | ||
| import { fileURLToPath } from "node:url"; | ||
| import { npxDefaultBin } from "./npx-default-bin.mjs"; | ||
|
|
||
| const repoRoot = path.resolve( | ||
| path.dirname(fileURLToPath(import.meta.url)), | ||
| "..", | ||
| "..", | ||
| ); | ||
| const LAUNCHER = "./clients/launcher/build/index.js"; | ||
|
|
||
| test("the root manifest's npx default bin is the launcher", () => { | ||
| const manifest = JSON.parse( | ||
| readFileSync(path.join(repoRoot, "package.json"), "utf8"), | ||
| ); | ||
| const bin = npxDefaultBin(manifest); | ||
| assert.notEqual( | ||
| bin, | ||
| null, | ||
| "npx @modelcontextprotocol/inspector would fail: no single bin and none named after the package", | ||
| ); | ||
| assert.equal(manifest.bin[bin], LAUNCHER); | ||
| }); | ||
|
|
||
| test("a sole bin is run whatever its name", () => { | ||
| assert.equal( | ||
| npxDefaultBin({ name: "@s/pkg", bin: { "mcp-inspector": LAUNCHER } }), | ||
| "mcp-inspector", | ||
| ); | ||
| }); | ||
|
|
||
| test("aliases of one file count as a sole bin", () => { | ||
| assert.equal( | ||
| npxDefaultBin({ name: "@s/pkg", bin: { a: LAUNCHER, b: LAUNCHER } }), | ||
| "a", | ||
| ); | ||
| }); | ||
|
|
||
| test("several distinct bins resolve to the one named after the unscoped package", () => { | ||
| assert.equal( | ||
| npxDefaultBin({ | ||
| name: "@s/inspector", | ||
| bin: { inspector: LAUNCHER, mcpdo: "./mcpdo.js" }, | ||
| }), | ||
| "inspector", | ||
| ); | ||
| }); | ||
|
|
||
| test("several distinct bins with none named after the package fail (the 2.10.0 shape)", () => { | ||
| assert.equal( | ||
| npxDefaultBin({ | ||
| name: "@modelcontextprotocol/inspector", | ||
| bin: { "mcp-inspector": LAUNCHER, mcpdo: "./mcpdo.js" }, | ||
| }), | ||
| null, | ||
| ); | ||
| }); | ||
|
|
||
| test("a string bin is named after the unscoped package", () => { | ||
| assert.equal(npxDefaultBin({ name: "@s/pkg", bin: LAUNCHER }), "pkg"); | ||
| }); | ||
|
|
||
| test("no bin at all fails", () => { | ||
| assert.equal(npxDefaultBin({ name: "pkg" }), null); | ||
| }); |
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.