Skip to content

Commit 235b608

Browse files
authored
Merge pull request #141 from leadbay/ArtyETH06/fix-installer-scope-fallback
fix(installer): use `--package=` long form in Claude Code install argv
2 parents ad307fe + 5be54ae commit 235b608

6 files changed

Lines changed: 89 additions & 5 deletions

File tree

packages/mcp/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog — @leadbay/mcp
22

3+
## 0.23.12 — 2026-07-03
4+
5+
Claude Code install no longer fails with `unknown option '--scope'` / `--env` (product#3847).
6+
7+
- **`buildClaudeCodeAddArgs` (installer)** — the `claude mcp add` command built its subprocess tail with a `-p` **short** flag (`-- npx -y -p @leadbay/mcp@latest leadbay-mcp`). Even after the `--` separator, `-p` leaks back into Claude Code's own Commander parser on current CLIs, which then rejects an *earlier* option (`--scope`, or `--env`) with a misleading `unknown option` error — so the install aborted with exit 1. The tail now uses the `=`-joined long form `-- npx -y --package=@leadbay/mcp@latest leadbay-mcp`: the package spec must stay flagged and the `leadbay-mcp` bin named explicitly (the package declares several bins and none is `mcp`, so a bare `npx -y @leadbay/mcp@latest` would die at launch with `could not determine executable to run`), while `--package=…` is left untouched by Claude Code's parser. Verified live against `claude 2.1.199`: install → registered, uninstall → removed.
8+
39
## 0.23.11 — 2026-07-02
410

511
Windows `.dxt` sign-in now opens the browser reliably (product#3839).

packages/mcp/installer/install-claude-code.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,22 @@ export function buildClaudeCodeAddArgs(
2525
if (localBinPath) {
2626
args.push("--", "node", localBinPath);
2727
} else {
28-
args.push("--", "npx", "-y", "-p", "@leadbay/mcp@latest", "leadbay-mcp");
28+
// `npx -y --package=@leadbay/mcp@latest leadbay-mcp` (product#3847).
29+
// Two constraints must BOTH hold:
30+
// 1. @leadbay/mcp declares several bins and NONE is named `mcp`, so npx
31+
// can't infer an executable from the package name alone — a bare
32+
// `npx -y @leadbay/mcp@latest` (with or without a trailing bin name)
33+
// dies at launch with `could not determine executable to run`. The
34+
// package spec MUST be flagged and the `leadbay-mcp` bin named
35+
// explicitly.
36+
// 2. The SHORT flag `-p`, though after the `--` separator, leaks back
37+
// into Claude Code's own Commander parser on current CLIs, which then
38+
// rejects an EARLIER option (`--scope`/`--env`) with a misleading
39+
// `unknown option` error at `claude mcp add` time.
40+
// The `=`-joined long form `--package=…` satisfies both: npx disambiguates
41+
// the package, and Claude Code's parser leaves the `--long=value` token
42+
// alone (verified against claude 2.1.199).
43+
args.push("--", "npx", "-y", "--package=@leadbay/mcp@latest", "leadbay-mcp");
2944
}
3045
return args;
3146
}

packages/mcp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@leadbay/mcp",
3-
"version": "0.23.11",
3+
"version": "0.23.12",
44
"mcpName": "io.github.leadbay/leadbay-mcp",
55
"description": "Model Context Protocol (MCP) server for Leadbay — AI lead discovery, qualification, and enrichment for Claude Desktop, Cursor, and Claude Code.",
66
"type": "module",

packages/mcp/server.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"name": "io.github.leadbay/leadbay-mcp",
44
"title": "Leadbay",
55
"description": "AI lead discovery, qualification, and outreach prep on your Leadbay account.",
6-
"version": "0.23.11",
6+
"version": "0.23.12",
77
"repository": {
88
"url": "https://github.com/leadbay/mcp",
99
"source": "github",
@@ -15,7 +15,7 @@
1515
"registryType": "npm",
1616
"registryBaseUrl": "https://registry.npmjs.org",
1717
"identifier": "@leadbay/mcp",
18-
"version": "0.23.11",
18+
"version": "0.23.12",
1919
"transport": {
2020
"type": "stdio"
2121
},
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Regression for product#3847 — Claude Code install failing with a misleading
3+
* `unknown option '--scope'` / `--env`.
4+
*
5+
* The `claude mcp add` subprocess tail must satisfy TWO constraints at once:
6+
*
7+
* 1. No SHORT `-p` flag. Even after the `--` separator, `-p` leaks back into
8+
* Claude Code's own Commander parser on current CLIs, which then rejects an
9+
* earlier option (`--scope`/`--env`) with a confusing `unknown option`
10+
* error — the install aborts at `claude mcp add` time.
11+
*
12+
* 2. The package MUST still be flagged (`--package=…`) AND the `leadbay-mcp`
13+
* bin named explicitly. @leadbay/mcp declares several bins and none is
14+
* named `mcp`, so a bare `npx -y @leadbay/mcp@latest` (with or without a
15+
* trailing bin) can't be resolved by npx — it dies at LAUNCH with
16+
* `could not determine executable to run`, even though `claude mcp add`
17+
* itself succeeded.
18+
*
19+
* The `=`-joined long form `--package=@leadbay/mcp@latest` is the shape that
20+
* satisfies both. This test pins it and guards against a `-p` regression.
21+
*
22+
* New file — no existing test is modified.
23+
*/
24+
import { describe, it, expect } from "vitest";
25+
import { buildClaudeCodeAddArgs } from "../../installer/install-claude-code.js";
26+
27+
describe("buildClaudeCodeAddArgs — subprocess tail (product#3847)", () => {
28+
it("post-`--` tail is exactly `npx -y --package=@leadbay/mcp@latest leadbay-mcp`", () => {
29+
const args = buildClaudeCodeAddArgs("tok", "us", true, true);
30+
const sep = args.indexOf("--");
31+
expect(args.slice(sep + 1)).toEqual([
32+
"npx",
33+
"-y",
34+
"--package=@leadbay/mcp@latest",
35+
"leadbay-mcp",
36+
]);
37+
});
38+
39+
it("carries no bare `-p` short flag after the separator (would break the parser)", () => {
40+
const args = buildClaudeCodeAddArgs("tok", "us", true, true);
41+
const tail = args.slice(args.indexOf("--") + 1);
42+
expect(tail).not.toContain("-p");
43+
});
44+
45+
it("flags the package AND names the leadbay-mcp bin (so npx can launch it)", () => {
46+
const args = buildClaudeCodeAddArgs("tok", "us", true, true);
47+
const tail = args.slice(args.indexOf("--") + 1);
48+
// Package must be flagged (bare `@leadbay/mcp@latest` as the command is
49+
// unresolvable) and the explicit bin present (no bin is named `mcp`).
50+
expect(tail.some((a) => a.startsWith("--package=@leadbay/mcp@"))).toBe(true);
51+
expect(tail).toContain("leadbay-mcp");
52+
});
53+
54+
it("localBinPath dev override still uses `-- node <path>` (no npx, no -p)", () => {
55+
const args = buildClaudeCodeAddArgs("tok", "us", true, true, "/abs/dist/bin.js");
56+
const sep = args.indexOf("--");
57+
expect(args.slice(sep + 1)).toEqual(["node", "/abs/dist/bin.js"]);
58+
});
59+
});

packages/mcp/test/unit/install-flags.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ describe("buildClaudeCodeAddArgs — Claude Code registration argv", () => {
5050
const args = buildClaudeCodeAddArgs("tok", "us", true, true);
5151
const sep = args.indexOf("--");
5252
expect(sep).toBeGreaterThan(0);
53-
expect(args.slice(sep + 1)).toEqual(["npx", "-y", "-p", "@leadbay/mcp@latest", "leadbay-mcp"]);
53+
// `--package=` long form (not `-p`): the short flag leaks into Claude
54+
// Code's own arg parser after `--` and breaks the add, but the package
55+
// must still be flagged + the `leadbay-mcp` bin named so npx can launch
56+
// it (no bin is named `mcp`) — product#3847.
57+
expect(args.slice(sep + 1)).toEqual(["npx", "-y", "--package=@leadbay/mcp@latest", "leadbay-mcp"]);
5458
});
5559

5660
it("token and region are NOT placed after the `--` separator (would be passed to npx, not claude)", () => {

0 commit comments

Comments
 (0)