argsbarg 3.4.1 → 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 CHANGED
@@ -7,6 +7,17 @@ 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
+
10
21
  ## [3.4.1] - 2026-06-22
11
22
 
12
23
 
@@ -348,7 +359,8 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
348
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`).
349
360
  - Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
350
361
 
351
- [Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.4.1...HEAD
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
352
364
  [3.4.1]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.4.1
353
365
  [3.4.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.4.0
354
366
  [3.3.14]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.3.14
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` and `~/.claude.json` when MCP is enabled |
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 `["ai", "mcp"]`.
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 (macOS-only v1):
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 / Claude Code JSON config.
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
- * macOS-only v1; requires the compiled binary to exist.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "argsbarg",
3
- "version": "3.4.1",
3
+ "version": "3.4.2",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "bun": ">=1.3"
@@ -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> (macOS-only v1).",
31
+ description: "Pack a Claude Desktop MCP Bundle (.mcpb) from dist/<key>.",
32
32
  handler: () => {},
33
33
  };
34
34
 
@@ -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 () => {
@@ -37,7 +37,33 @@ export function generateMcpGuide(root: CliProgram): string {
37
37
  `${root.key} mcp`,
38
38
  "```",
39
39
  "",
40
- "Cursor / Claude `mcp.json` entry:",
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) {
@@ -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 on darwin", () => {
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
  }
@@ -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", () => {
@@ -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),
@@ -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 = "binary" | "completions" | "cursor-skill" | "claude-skill" | "cursor-mcp" | "claude-mcp";
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: (detected.cursorMcp || detected.claudeMcp) && resolveCapabilities(root).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
  }
@@ -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) {
@@ -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
- macOS-only v1: expects `dist/<program.key>` as the compiled binary input.
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
- * macOS-only v1; requires the compiled binary to exist.
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);