argsbarg 3.4.0 → 3.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -1
- package/docs/install.md +1 -1
- package/docs/mcp.md +19 -3
- package/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/builtins/mcp.ts +2 -2
- package/src/docs/api-guide.ts +1 -1
- package/src/docs/docs.test.ts +5 -1
- package/src/docs/mcp-guide.ts +27 -7
- package/src/hidden-mcpb.test.ts +1 -4
- package/src/install/detect-installed.ts +6 -0
- package/src/install/index.ts +1 -1
- package/src/install/install.test.ts +27 -1
- package/src/install/paths.ts +23 -1
- package/src/install/plan.ts +26 -4
- package/src/install/status.ts +3 -1
- package/src/install/uninstall.ts +11 -1
- package/src/mcp/bundle.ts +2 -6
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.4.2] - 2026-06-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`install --mcp`** — also merges into Claude Desktop `claude_desktop_config.json` when Claude Desktop app data is present (macOS, Windows, Linux paths).
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **`docs mcp`** — generated guide documents Cursor, Claude Code, and Claude Desktop install targets and platform config paths.
|
|
19
|
+
- **`mcp bundle`** — no longer macOS-only; packs `.mcpb` on any platform when the compiled binary exists.
|
|
20
|
+
|
|
21
|
+
## [3.4.1] - 2026-06-22
|
|
22
|
+
|
|
23
|
+
|
|
10
24
|
## [3.4.0] - 2026-06-22
|
|
11
25
|
|
|
12
26
|
### Added
|
|
@@ -345,7 +359,9 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
|
|
|
345
359
|
- Migrate schemas: rename every `children` property to **`commands`**; move positional definitions to **`CliPositional`** objects on `positionals` and strip `positional` / `argMin` / `argMax` from flag definitions under `options` (flags only carry `name`, `description`, `kind`, and optional `shortName`).
|
|
346
360
|
- Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
|
|
347
361
|
|
|
348
|
-
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.4.
|
|
362
|
+
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.4.2...HEAD
|
|
363
|
+
[3.4.2]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.4.2
|
|
364
|
+
[3.4.1]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.4.1
|
|
349
365
|
[3.4.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.4.0
|
|
350
366
|
[3.3.14]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.3.14
|
|
351
367
|
[3.3.13]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.3.13
|
package/docs/install.md
CHANGED
|
@@ -31,7 +31,7 @@ myapp install --uninstall --all --yes
|
|
|
31
31
|
| Fish completion | `--completions` | `~/.config/fish/completions/<key>.fish` |
|
|
32
32
|
| Cursor skill | `--skill` | `~/.cursor/skills/<dir>/` when `~/.cursor` exists |
|
|
33
33
|
| Claude skill | `--skill` | `~/.claude/skills/<dir>/` when `~/.claude` exists |
|
|
34
|
-
| MCP config | `--mcp` | `~/.cursor/mcp.json`
|
|
34
|
+
| MCP config | `--mcp` | `~/.cursor/mcp.json` (when `~/.cursor` exists), `~/.claude.json` (Claude Code), and Claude Desktop `claude_desktop_config.json` when Claude Desktop app data exists |
|
|
35
35
|
|
|
36
36
|
`--all` expands to `--bin`, `--completions`, `--skill`, and `--mcp` (when `mcpServer.enabled` is `true`) for both install and uninstall. Missing targets are skipped silently (no error if nothing is on disk or a shell/agent directory does not exist).
|
|
37
37
|
|
package/docs/mcp.md
CHANGED
|
@@ -57,7 +57,23 @@ Add a server entry under `mcpServers` in your Cursor MCP config:
|
|
|
57
57
|
}
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
Use your real binary or script path. For a compiled CLI, `command` can be the installed binary and `args` can be `["
|
|
60
|
+
Use your real binary or script path. For a compiled CLI, `command` can be the installed binary and `args` can be `["mcp"]`.
|
|
61
|
+
|
|
62
|
+
### Claude Code
|
|
63
|
+
|
|
64
|
+
`install --mcp` merges into `~/.claude.json` under `mcpServers`.
|
|
65
|
+
|
|
66
|
+
### Claude Desktop
|
|
67
|
+
|
|
68
|
+
`install --mcp` also merges into Claude Desktop config when app data is present:
|
|
69
|
+
|
|
70
|
+
| Platform | Path |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
73
|
+
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
74
|
+
| Linux | `~/.config/Claude/claude_desktop_config.json` |
|
|
75
|
+
|
|
76
|
+
Restart Claude Desktop after config changes. You can also install a **`.mcpb`** bundle via **`mcp bundle`** (see [MCP Bundle](#mcp-bundle-mcp-bundle)).
|
|
61
77
|
|
|
62
78
|
### Other MCP hosts
|
|
63
79
|
|
|
@@ -295,7 +311,7 @@ You should get one JSON line on stdout with `result.capabilities` and `result.se
|
|
|
295
311
|
|
|
296
312
|
## MCP Bundle (`mcp bundle`)
|
|
297
313
|
|
|
298
|
-
When `mcpServer.enabled` is true, **`mcp bundle`** packs a Claude Desktop **`.mcpb`** bundle
|
|
314
|
+
When `mcpServer.enabled` is true, **`mcp bundle`** packs a Claude Desktop **`.mcpb`** bundle:
|
|
299
315
|
|
|
300
316
|
```bash
|
|
301
317
|
just build
|
|
@@ -305,7 +321,7 @@ just build
|
|
|
305
321
|
|
|
306
322
|
Expects the compiled binary at **`dist/<program.key>`** and writes **`dist/<program.key>.mcpb`**. Manifest metadata is generated from your schema (`mcpServerId`, tools, `requiresEnv`). Optional pack-time fields live under **`mcpServer.bundle`** (`author`, `icon`, `longDescription`).
|
|
307
323
|
|
|
308
|
-
Bare **`myapp mcp`** still runs the stdio MCP server (unchanged for `install --mcp` and MCP hosts). Use **`install --mcp`** for Cursor
|
|
324
|
+
Bare **`myapp mcp`** still runs the stdio MCP server (unchanged for `install --mcp` and MCP hosts). Use **`install --mcp`** for Cursor, Claude Code, and Claude Desktop JSON config.
|
|
309
325
|
|
|
310
326
|
## Hidden commands and options
|
|
311
327
|
|
package/index.d.ts
CHANGED
|
@@ -422,7 +422,7 @@ export interface PackMcpBundleOpts {
|
|
|
422
422
|
}
|
|
423
423
|
/**
|
|
424
424
|
* Stages manifest + binary (+ optional icon) and writes a `.mcpb` ZIP.
|
|
425
|
-
*
|
|
425
|
+
* Requires the compiled binary to exist.
|
|
426
426
|
*/
|
|
427
427
|
export declare function packMcpBundle(program: CliProgram, opts?: PackMcpBundleOpts): string;
|
|
428
428
|
|
package/package.json
CHANGED
package/src/builtins/mcp.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { type CliLeaf, type CliProgram, type CliRouter, CliFallbackMode } from "
|
|
|
6
6
|
export function cliBuiltinMcpCommand(program: CliProgram): CliRouter {
|
|
7
7
|
const caps = resolveCapabilities(program);
|
|
8
8
|
const lines = [
|
|
9
|
-
"Stdio MCP server. Add to Cursor or Claude:",
|
|
9
|
+
"Stdio MCP server. Add to Cursor, Claude Code, or Claude Desktop:",
|
|
10
10
|
"",
|
|
11
11
|
" command: {argsbarg:program}",
|
|
12
12
|
" args: mcp",
|
|
@@ -28,7 +28,7 @@ export function cliBuiltinMcpCommand(program: CliProgram): CliRouter {
|
|
|
28
28
|
|
|
29
29
|
const bundle: CliLeaf = {
|
|
30
30
|
key: "bundle",
|
|
31
|
-
description: "Pack a Claude Desktop MCP Bundle (.mcpb) from dist/<key
|
|
31
|
+
description: "Pack a Claude Desktop MCP Bundle (.mcpb) from dist/<key>.",
|
|
32
32
|
handler: () => {},
|
|
33
33
|
};
|
|
34
34
|
|
package/src/docs/api-guide.ts
CHANGED
|
@@ -57,7 +57,7 @@ function formatOutputSchemaSection(schema: Record<string, unknown>): string[] {
|
|
|
57
57
|
return [
|
|
58
58
|
"#### Output",
|
|
59
59
|
"",
|
|
60
|
-
"JSON Schema for
|
|
60
|
+
"JSON Schema for output when/if handler emits JSON",
|
|
61
61
|
"",
|
|
62
62
|
"```json",
|
|
63
63
|
JSON.stringify(schema, null, 2),
|
package/src/docs/docs.test.ts
CHANGED
|
@@ -102,6 +102,8 @@ test("docs mcp when MCP enabled", async () => {
|
|
|
102
102
|
expect(result.exitCode).toBe(0);
|
|
103
103
|
expect(result.stdout).toContain("MCP server (myapp)");
|
|
104
104
|
expect(result.stdout).toContain("myapp mcp");
|
|
105
|
+
expect(result.stdout).toContain("claude_desktop_config.json");
|
|
106
|
+
expect(result.stdout).toContain("install --mcp --yes");
|
|
105
107
|
});
|
|
106
108
|
|
|
107
109
|
test("docs rejects unknown subcommand", async () => {
|
|
@@ -192,9 +194,11 @@ test("completions offer docs subcommands", () => {
|
|
|
192
194
|
expect(bash).toContain("skill) echo");
|
|
193
195
|
});
|
|
194
196
|
|
|
195
|
-
test("generateMcpGuide includes schema URI", () => {
|
|
197
|
+
test("generateMcpGuide includes schema URI and install targets", () => {
|
|
196
198
|
const guide = generateMcpGuide(docsFixture(true));
|
|
197
199
|
expect(guide).toContain("myapp://schema");
|
|
200
|
+
expect(guide).toContain("~/.cursor/mcp.json");
|
|
201
|
+
expect(guide).toContain("claude_desktop_config.json");
|
|
198
202
|
});
|
|
199
203
|
|
|
200
204
|
test("docs --save writes topic file", async () => {
|
package/src/docs/mcp-guide.ts
CHANGED
|
@@ -37,7 +37,33 @@ export function generateMcpGuide(root: CliProgram): string {
|
|
|
37
37
|
`${root.key} mcp`,
|
|
38
38
|
"```",
|
|
39
39
|
"",
|
|
40
|
-
"
|
|
40
|
+
"## Client setup",
|
|
41
|
+
"",
|
|
42
|
+
"### `install --mcp`",
|
|
43
|
+
"",
|
|
44
|
+
"```bash",
|
|
45
|
+
`${root.key} install --mcp --yes`,
|
|
46
|
+
"```",
|
|
47
|
+
"",
|
|
48
|
+
"Merges the server entry below into host config when each host is present:",
|
|
49
|
+
"",
|
|
50
|
+
"| Host | Config file |",
|
|
51
|
+
"| --- | --- |",
|
|
52
|
+
"| Cursor | `~/.cursor/mcp.json` (when `~/.cursor` exists) |",
|
|
53
|
+
"| Claude Code | `~/.claude.json` |",
|
|
54
|
+
"| Claude Desktop | `claude_desktop_config.json` (when Claude Desktop app data exists) |",
|
|
55
|
+
"",
|
|
56
|
+
"Claude Desktop paths by platform:",
|
|
57
|
+
"",
|
|
58
|
+
"- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`",
|
|
59
|
+
"- **Windows:** `%APPDATA%\\Claude\\claude_desktop_config.json`",
|
|
60
|
+
"- **Linux:** `~/.config/Claude/claude_desktop_config.json`",
|
|
61
|
+
"",
|
|
62
|
+
"Restart Claude Desktop after changing its config.",
|
|
63
|
+
"",
|
|
64
|
+
"### Manual entry",
|
|
65
|
+
"",
|
|
66
|
+
"Add under `mcpServers` in the host config:",
|
|
41
67
|
"",
|
|
42
68
|
"```json",
|
|
43
69
|
JSON.stringify(
|
|
@@ -54,12 +80,6 @@ export function generateMcpGuide(root: CliProgram): string {
|
|
|
54
80
|
),
|
|
55
81
|
"```",
|
|
56
82
|
"",
|
|
57
|
-
"Or run:",
|
|
58
|
-
"",
|
|
59
|
-
"```bash",
|
|
60
|
-
`${root.key} install --mcp --yes`,
|
|
61
|
-
"```",
|
|
62
|
-
"",
|
|
63
83
|
];
|
|
64
84
|
|
|
65
85
|
if (mcp.shellEnv || mcp.envFile) {
|
package/src/hidden-mcpb.test.ts
CHANGED
|
@@ -129,10 +129,7 @@ describe("mcp bundle", () => {
|
|
|
129
129
|
expect(paths.outPath).toBe(join(cwd, "dist", "myapp.mcpb"));
|
|
130
130
|
});
|
|
131
131
|
|
|
132
|
-
test("packMcpBundle writes zip with manifest and binary
|
|
133
|
-
if (process.platform !== "darwin") {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
132
|
+
test("packMcpBundle writes zip with manifest and binary", () => {
|
|
136
133
|
const work = mkdtempSync(join(tmpdir(), "mcpb-test-"));
|
|
137
134
|
try {
|
|
138
135
|
const dist = join(work, "dist");
|
|
@@ -10,6 +10,7 @@ export interface InstalledArtifacts {
|
|
|
10
10
|
claudeSkill: boolean;
|
|
11
11
|
cursorMcp: boolean;
|
|
12
12
|
claudeMcp: boolean;
|
|
13
|
+
claudeDesktopMcp: boolean;
|
|
13
14
|
bashRcPath: boolean;
|
|
14
15
|
zshRcFpath: boolean;
|
|
15
16
|
}
|
|
@@ -35,6 +36,7 @@ export function detectInstalledArtifacts(paths: InstallPaths): InstalledArtifact
|
|
|
35
36
|
claudeSkill: existsSync(paths.claudeSkillDir),
|
|
36
37
|
cursorMcp: mcpConfigHasServer(paths.cursorMcpPath, paths.mcpName),
|
|
37
38
|
claudeMcp: mcpConfigHasServer(paths.claudeMcpPath, paths.mcpName),
|
|
39
|
+
claudeDesktopMcp: mcpConfigHasServer(paths.claudeDesktopMcpPath, paths.mcpName),
|
|
38
40
|
bashRcPath: false,
|
|
39
41
|
zshRcFpath: false,
|
|
40
42
|
};
|
|
@@ -49,6 +51,7 @@ export interface InstallStatus {
|
|
|
49
51
|
claudeSkill?: string;
|
|
50
52
|
cursorMcp?: string;
|
|
51
53
|
claudeMcp?: string;
|
|
54
|
+
claudeDesktopMcp?: string;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
/** Builds a status inventory from detected artifacts. */
|
|
@@ -62,5 +65,8 @@ export function buildInstallStatus(paths: InstallPaths, detected: InstalledArtif
|
|
|
62
65
|
if (detected.claudeSkill) status.claudeSkill = paths.claudeSkillDir + "/";
|
|
63
66
|
if (detected.cursorMcp) status.cursorMcp = `${paths.cursorMcpPath} (server "${paths.mcpName}")`;
|
|
64
67
|
if (detected.claudeMcp) status.claudeMcp = `${paths.claudeMcpPath} (server "${paths.mcpName}")`;
|
|
68
|
+
if (detected.claudeDesktopMcp) {
|
|
69
|
+
status.claudeDesktopMcp = `${paths.claudeDesktopMcpPath} (server "${paths.mcpName}")`;
|
|
70
|
+
}
|
|
65
71
|
return status;
|
|
66
72
|
}
|
package/src/install/index.ts
CHANGED
|
@@ -151,7 +151,7 @@ export async function runInstallMutation(
|
|
|
151
151
|
if (!opts.uninstall && resolveCapabilities(root).mcp && (opts.all || opts.mcp)) {
|
|
152
152
|
const entry = expectedMcpEntry(root);
|
|
153
153
|
const yes = !!opts.yes;
|
|
154
|
-
for (const p of [paths.cursorMcpPath, paths.claudeMcpPath]) {
|
|
154
|
+
for (const p of [paths.cursorMcpPath, paths.claudeMcpPath, paths.claudeDesktopMcpPath]) {
|
|
155
155
|
const conflict = checkMcpConflict(p, paths.mcpName, entry, yes);
|
|
156
156
|
if (conflict) {
|
|
157
157
|
throw new Error(conflict);
|
|
@@ -4,7 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { CliProgram } from "../types.ts";
|
|
6
6
|
import { detectInstalledArtifacts } from "./detect-installed.ts";
|
|
7
|
-
import { resolveInstallPaths } from "./paths.ts";
|
|
7
|
+
import { resolveInstallPaths, resolveClaudeDesktopMcpPath } from "./paths.ts";
|
|
8
8
|
import { buildInstallPlan } from "./plan.ts";
|
|
9
9
|
import { buildUninstallPlan } from "./uninstall.ts";
|
|
10
10
|
import { printInstallStatus } from "./status.ts";
|
|
@@ -45,6 +45,18 @@ describe("install paths", () => {
|
|
|
45
45
|
const paths = resolveInstallPaths(fixture, {});
|
|
46
46
|
expect(paths.fishCompletion).toBe(join(xdg, "fish", "completions", "testapp.fish"));
|
|
47
47
|
});
|
|
48
|
+
|
|
49
|
+
test("claude desktop mcp path on darwin", () => {
|
|
50
|
+
const prev = process.platform;
|
|
51
|
+
Object.defineProperty(process, "platform", { value: "darwin" });
|
|
52
|
+
try {
|
|
53
|
+
expect(resolveClaudeDesktopMcpPath(home)).toBe(
|
|
54
|
+
join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json"),
|
|
55
|
+
);
|
|
56
|
+
} finally {
|
|
57
|
+
Object.defineProperty(process, "platform", { value: prev });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
48
60
|
});
|
|
49
61
|
|
|
50
62
|
describe("detect installed", () => {
|
|
@@ -68,6 +80,20 @@ describe("install plan", () => {
|
|
|
68
80
|
const plan = buildInstallPlan(fixture, paths, parseInstallOpts({ all: "1" }));
|
|
69
81
|
expect(plan.some((a) => a.kind === "binary")).toBe(true);
|
|
70
82
|
});
|
|
83
|
+
|
|
84
|
+
test("buildInstallPlan --mcp includes claude desktop when app data exists", () => {
|
|
85
|
+
const paths = resolveInstallPaths(fixture, {});
|
|
86
|
+
mkdirSync(join(home, "Library", "Application Support", "Claude"), { recursive: true });
|
|
87
|
+
const plan = buildInstallPlan(fixture, paths, parseInstallOpts({ mcp: "1" }));
|
|
88
|
+
expect(plan.some((a) => a.kind === "claude-desktop-mcp")).toBe(process.platform === "darwin");
|
|
89
|
+
expect(plan.some((a) => a.kind === "claude-mcp")).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("buildInstallPlan --mcp skips claude desktop without app data", () => {
|
|
93
|
+
const paths = resolveInstallPaths(fixture, {});
|
|
94
|
+
const plan = buildInstallPlan(fixture, paths, parseInstallOpts({ mcp: "1" }));
|
|
95
|
+
expect(plan.some((a) => a.kind === "claude-desktop-mcp")).toBe(false);
|
|
96
|
+
});
|
|
71
97
|
});
|
|
72
98
|
|
|
73
99
|
describe("install status", () => {
|
package/src/install/paths.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
1
2
|
import { homedir } from "node:os";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
3
4
|
import { CliProgram } from "../types.ts";
|
|
4
5
|
import { sanitizeToolSegment, mcpServerId } from "../mcp/tools.ts";
|
|
5
6
|
|
|
@@ -13,6 +14,7 @@ export interface InstallPaths {
|
|
|
13
14
|
claudeSkillDir: string;
|
|
14
15
|
cursorMcpPath: string;
|
|
15
16
|
claudeMcpPath: string;
|
|
17
|
+
claudeDesktopMcpPath: string;
|
|
16
18
|
bashRc: string;
|
|
17
19
|
zshRc: string;
|
|
18
20
|
mcpName: string;
|
|
@@ -43,6 +45,24 @@ export function resolveBindir(root: CliProgram, prefix?: string): string {
|
|
|
43
45
|
return join(userHome(), ".local", "bin");
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
/** Resolves Claude Desktop `claude_desktop_config.json` for the current OS. */
|
|
49
|
+
export function resolveClaudeDesktopMcpPath(home: string): string {
|
|
50
|
+
if (process.platform === "darwin") {
|
|
51
|
+
return join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
52
|
+
}
|
|
53
|
+
if (process.platform === "win32") {
|
|
54
|
+
const appData = process.env.APPDATA ?? join(home, "AppData", "Roaming");
|
|
55
|
+
return join(appData, "Claude", "claude_desktop_config.json");
|
|
56
|
+
}
|
|
57
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME ?? join(home, ".config");
|
|
58
|
+
return join(xdgConfig, "Claude", "claude_desktop_config.json");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** True when Claude Desktop app data exists (config file or app support directory). */
|
|
62
|
+
export function claudeDesktopPresent(home: string, configPath: string): boolean {
|
|
63
|
+
return existsSync(configPath) || existsSync(dirname(configPath));
|
|
64
|
+
}
|
|
65
|
+
|
|
46
66
|
/** Resolves all install artifact paths for a program root. */
|
|
47
67
|
export function resolveInstallPaths(root: CliProgram, opts: { prefix?: string }): InstallPaths {
|
|
48
68
|
const home = userHome();
|
|
@@ -50,6 +70,7 @@ export function resolveInstallPaths(root: CliProgram, opts: { prefix?: string })
|
|
|
50
70
|
const key = root.key;
|
|
51
71
|
const skillDirName = sanitizeToolSegment(root.key);
|
|
52
72
|
const xdgConfig = process.env.XDG_CONFIG_HOME ?? join(home, ".config");
|
|
73
|
+
const claudeDesktopMcpPath = resolveClaudeDesktopMcpPath(home);
|
|
53
74
|
|
|
54
75
|
return {
|
|
55
76
|
bindir,
|
|
@@ -61,6 +82,7 @@ export function resolveInstallPaths(root: CliProgram, opts: { prefix?: string })
|
|
|
61
82
|
claudeSkillDir: join(home, ".claude", "skills", skillDirName),
|
|
62
83
|
cursorMcpPath: join(home, ".cursor", "mcp.json"),
|
|
63
84
|
claudeMcpPath: join(home, ".claude.json"),
|
|
85
|
+
claudeDesktopMcpPath,
|
|
64
86
|
bashRc: join(home, ".bashrc"),
|
|
65
87
|
zshRc: join(home, ".zshrc"),
|
|
66
88
|
mcpName: mcpServerId(root),
|
package/src/install/plan.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { installBinary } from "./binary.ts";
|
|
|
6
6
|
import { installCompletions } from "./completions.ts";
|
|
7
7
|
import { detectInstalledArtifacts } from "./detect-installed.ts";
|
|
8
8
|
import { expectedMcpEntry, mergeMcpConfig } from "./mcp-config.ts";
|
|
9
|
-
import { InstallPaths, userHome } from "./paths.ts";
|
|
9
|
+
import { InstallPaths, userHome, claudeDesktopPresent } from "./paths.ts";
|
|
10
10
|
import { detectShells } from "./shell.ts";
|
|
11
11
|
|
|
12
12
|
export interface InstallOpts {
|
|
@@ -27,7 +27,14 @@ export interface InstallOpts {
|
|
|
27
27
|
prefix?: string;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
export type InstallActionKind =
|
|
30
|
+
export type InstallActionKind =
|
|
31
|
+
| "binary"
|
|
32
|
+
| "completions"
|
|
33
|
+
| "cursor-skill"
|
|
34
|
+
| "claude-skill"
|
|
35
|
+
| "cursor-mcp"
|
|
36
|
+
| "claude-mcp"
|
|
37
|
+
| "claude-desktop-mcp";
|
|
31
38
|
|
|
32
39
|
export interface InstallAction {
|
|
33
40
|
kind: InstallActionKind;
|
|
@@ -139,13 +146,24 @@ export function buildInstallPlan(root: CliProgram, paths: InstallPaths, opts: In
|
|
|
139
146
|
}
|
|
140
147
|
actions.push({
|
|
141
148
|
kind: "claude-mcp",
|
|
142
|
-
summary: `claude mcp: ${paths.claudeMcpPath} (server "${paths.mcpName}")`,
|
|
149
|
+
summary: `claude code mcp: ${paths.claudeMcpPath} (server "${paths.mcpName}")`,
|
|
143
150
|
message: `Merging MCP server "${paths.mcpName}" into ${paths.claudeMcpPath}`,
|
|
144
151
|
run: () => {
|
|
145
152
|
mergeMcpConfig(paths.claudeMcpPath, paths.mcpName, entry, dry);
|
|
146
153
|
return [paths.claudeMcpPath];
|
|
147
154
|
},
|
|
148
155
|
});
|
|
156
|
+
if (claudeDesktopPresent(userHome(), paths.claudeDesktopMcpPath)) {
|
|
157
|
+
actions.push({
|
|
158
|
+
kind: "claude-desktop-mcp",
|
|
159
|
+
summary: `claude desktop mcp: ${paths.claudeDesktopMcpPath} (server "${paths.mcpName}")`,
|
|
160
|
+
message: `Merging MCP server "${paths.mcpName}" into ${paths.claudeDesktopMcpPath}`,
|
|
161
|
+
run: () => {
|
|
162
|
+
mergeMcpConfig(paths.claudeDesktopMcpPath, paths.mcpName, entry, dry);
|
|
163
|
+
return [paths.claudeDesktopMcpPath];
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
}
|
|
149
167
|
}
|
|
150
168
|
|
|
151
169
|
return actions;
|
|
@@ -158,7 +176,9 @@ export function buildUpdatePlan(root: CliProgram, paths: InstallPaths, opts: Ins
|
|
|
158
176
|
bin: true,
|
|
159
177
|
completions: detected.bashCompletion || detected.zshCompletion || detected.fishCompletion,
|
|
160
178
|
skill: detected.cursorSkill || detected.claudeSkill,
|
|
161
|
-
mcp:
|
|
179
|
+
mcp:
|
|
180
|
+
(detected.cursorMcp || detected.claudeMcp || detected.claudeDesktopMcp) &&
|
|
181
|
+
resolveCapabilities(root).mcp,
|
|
162
182
|
dry: opts.dry,
|
|
163
183
|
};
|
|
164
184
|
const plan = buildInstallPlan(root, paths, scoped);
|
|
@@ -180,6 +200,8 @@ export function buildUpdatePlan(root: CliProgram, paths: InstallPaths, opts: Ins
|
|
|
180
200
|
return detected.cursorMcp;
|
|
181
201
|
case "claude-mcp":
|
|
182
202
|
return detected.claudeMcp;
|
|
203
|
+
case "claude-desktop-mcp":
|
|
204
|
+
return detected.claudeDesktopMcp;
|
|
183
205
|
default:
|
|
184
206
|
return false;
|
|
185
207
|
}
|
package/src/install/status.ts
CHANGED
|
@@ -35,6 +35,7 @@ export function printInstallStatus(root: CliProgram, opts: InstallOpts): void {
|
|
|
35
35
|
if (status.claudeSkill) json.claudeSkill = status.claudeSkill;
|
|
36
36
|
if (status.cursorMcp) json.cursorMcp = status.cursorMcp;
|
|
37
37
|
if (status.claudeMcp) json.claudeMcp = status.claudeMcp;
|
|
38
|
+
if (status.claudeDesktopMcp) json.claudeDesktopMcp = status.claudeDesktopMcp;
|
|
38
39
|
process.stdout.write(JSON.stringify(json, null, 2) + "\n");
|
|
39
40
|
return;
|
|
40
41
|
}
|
|
@@ -48,7 +49,8 @@ export function printInstallStatus(root: CliProgram, opts: InstallOpts): void {
|
|
|
48
49
|
["cursor skill", status.cursorSkill],
|
|
49
50
|
["claude skill", status.claudeSkill],
|
|
50
51
|
["cursor mcp", status.cursorMcp],
|
|
51
|
-
["claude mcp", status.claudeMcp],
|
|
52
|
+
["claude code mcp", status.claudeMcp],
|
|
53
|
+
["claude desktop mcp", status.claudeDesktopMcp],
|
|
52
54
|
];
|
|
53
55
|
let any = false;
|
|
54
56
|
for (const [label, value] of lines) {
|
package/src/install/uninstall.ts
CHANGED
|
@@ -93,7 +93,7 @@ export function buildUninstallPlan(
|
|
|
93
93
|
}
|
|
94
94
|
if (detected.claudeMcp) {
|
|
95
95
|
actions.push({
|
|
96
|
-
summary: `claude mcp: ${paths.claudeMcpPath}`,
|
|
96
|
+
summary: `claude code mcp: ${paths.claudeMcpPath}`,
|
|
97
97
|
message: `Removing MCP server "${paths.mcpName}" from ${paths.claudeMcpPath}`,
|
|
98
98
|
run: () => {
|
|
99
99
|
removeMcpConfig(paths.claudeMcpPath, paths.mcpName, dry);
|
|
@@ -101,6 +101,16 @@ export function buildUninstallPlan(
|
|
|
101
101
|
},
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
|
+
if (detected.claudeDesktopMcp) {
|
|
105
|
+
actions.push({
|
|
106
|
+
summary: `claude desktop mcp: ${paths.claudeDesktopMcpPath}`,
|
|
107
|
+
message: `Removing MCP server "${paths.mcpName}" from ${paths.claudeDesktopMcpPath}`,
|
|
108
|
+
run: () => {
|
|
109
|
+
removeMcpConfig(paths.claudeDesktopMcpPath, paths.mcpName, dry);
|
|
110
|
+
return [paths.claudeDesktopMcpPath];
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
}
|
|
104
114
|
}
|
|
105
115
|
|
|
106
116
|
return actions;
|
package/src/mcp/bundle.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
Packs a CLI program into an MCP Bundle (`.mcpb`) for Claude Desktop.
|
|
3
|
-
|
|
3
|
+
Expects `dist/<program.key>` as the compiled binary input.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
@@ -198,13 +198,9 @@ export interface PackMcpBundleOpts {
|
|
|
198
198
|
|
|
199
199
|
/**
|
|
200
200
|
* Stages manifest + binary (+ optional icon) and writes a `.mcpb` ZIP.
|
|
201
|
-
*
|
|
201
|
+
* Requires the compiled binary to exist.
|
|
202
202
|
*/
|
|
203
203
|
export function packMcpBundle(program: CliProgram, opts: PackMcpBundleOpts = {}): string {
|
|
204
|
-
if (process.platform !== "darwin") {
|
|
205
|
-
throw new Error("mcp bundle is macOS-only in this release. Build the bundle on darwin.");
|
|
206
|
-
}
|
|
207
|
-
|
|
208
204
|
const cwd = opts.cwd ?? process.cwd();
|
|
209
205
|
const defaults = defaultMcpBundlePaths(program, cwd);
|
|
210
206
|
const binaryPath = resolve(cwd, opts.binaryPath ?? defaults.binaryPath);
|