@kanbodev/mcp 1.2.0 → 1.2.1

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.
Files changed (3) hide show
  1. package/README.md +25 -6
  2. package/dist/index.js +314 -84
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -29,6 +29,24 @@ If you authenticated previously and need to register with a new editor:
29
29
  npx @kanbodev/mcp install
30
30
  ```
31
31
 
32
+ ### Windows note
33
+
34
+ On Windows, `npx` can cause stdio piping issues with some MCP hosts. The `install` command automatically uses `node` with a direct path instead. If you're setting up manually on Windows, use:
35
+
36
+ ```json
37
+ {
38
+ "mcpServers": {
39
+ "kanbodev": {
40
+ "type": "stdio",
41
+ "command": "node",
42
+ "args": ["C:\\Users\\<you>\\AppData\\Roaming\\npm\\node_modules\\@kanbodev\\mcp\\dist\\index.js"]
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ Replace `<you>` with your Windows username, or run `npm root -g` to find the correct path.
49
+
32
50
  ### Manual setup
33
51
 
34
52
  If auto-registration doesn't detect your editor, add the config manually:
@@ -303,12 +321,13 @@ The last example passes your raw notes directly to `generate_description` — th
303
321
  ## CLI Commands
304
322
 
305
323
  ```bash
306
- npx @kanbodev/mcp login # Authenticate + auto-register MCP server
307
- npx @kanbodev/mcp install # Register MCP server with detected editors
308
- npx @kanbodev/mcp whoami # Check auth status
309
- npx @kanbodev/mcp logout # Remove credentials
310
- npx @kanbodev/mcp help # Show help
311
- npx @kanbodev/mcp version # Show version
324
+ npx @kanbodev/mcp login # Authenticate + auto-register MCP server
325
+ npx @kanbodev/mcp install # Register MCP server with detected editors
326
+ npx @kanbodev/mcp uninstall # Remove MCP server from all editors
327
+ npx @kanbodev/mcp whoami # Check auth status
328
+ npx @kanbodev/mcp logout # Remove credentials
329
+ npx @kanbodev/mcp help # Show help
330
+ npx @kanbodev/mcp version # Show version
312
331
  ```
313
332
 
314
333
  ## Links
package/dist/index.js CHANGED
@@ -245,7 +245,7 @@ var init_constants = __esm(() => {
245
245
  };
246
246
  SERVER_INFO = {
247
247
  name: "kanbo-mcp",
248
- version: "1.2.0",
248
+ version: "1.2.1",
249
249
  description: "MCP server for Kanbo project management"
250
250
  };
251
251
  PAT_CONFIG = {
@@ -16449,11 +16449,17 @@ function saveConfig(input) {
16449
16449
  }
16450
16450
  function deleteConfig() {
16451
16451
  try {
16452
- if (fs2.existsSync(CONFIG_PATH)) {
16453
- fs2.unlinkSync(CONFIG_PATH);
16454
- return true;
16452
+ if (!fs2.existsSync(CONFIG_PATH)) {
16453
+ return false;
16455
16454
  }
16456
- return false;
16455
+ fs2.unlinkSync(CONFIG_PATH);
16456
+ try {
16457
+ const remaining = fs2.readdirSync(CONFIG_DIR);
16458
+ if (remaining.length === 0) {
16459
+ fs2.rmdirSync(CONFIG_DIR);
16460
+ }
16461
+ } catch {}
16462
+ return true;
16457
16463
  } catch {
16458
16464
  return false;
16459
16465
  }
@@ -16477,56 +16483,126 @@ var init_config = __esm(() => {
16477
16483
  CONFIG_PATH = path2.join(CONFIG_DIR, "config.json");
16478
16484
  });
16479
16485
 
16480
- // src/cli/register.ts
16481
- import * as fs3 from "node:fs";
16486
+ // src/cli/hosts.ts
16482
16487
  import * as path3 from "node:path";
16483
16488
  import * as os3 from "node:os";
16484
- import { execFileSync } from "node:child_process";
16485
- function getVscodeMcpPath() {
16486
- const platform = process.platform;
16487
- if (platform === "darwin") {
16488
- return path3.join(os3.homedir(), "Library", "Application Support", "Code", "User", "mcp.json");
16489
- }
16490
- if (platform === "win32") {
16491
- const appData = process.env.APPDATA || path3.join(os3.homedir(), "AppData", "Roaming");
16492
- return path3.join(appData, "Code", "User", "mcp.json");
16493
- }
16494
- return path3.join(os3.homedir(), ".config", "Code", "User", "mcp.json");
16489
+ function getAppData() {
16490
+ return process.env.APPDATA || path3.join(os3.homedir(), "AppData", "Roaming");
16495
16491
  }
16496
- function getVscodeInsidersMcpPath() {
16492
+ function platformPath(mac2, win, linux) {
16497
16493
  const platform = process.platform;
16498
- if (platform === "darwin") {
16499
- return path3.join(os3.homedir(), "Library", "Application Support", "Code - Insiders", "User", "mcp.json");
16500
- }
16501
- if (platform === "win32") {
16502
- const appData = process.env.APPDATA || path3.join(os3.homedir(), "AppData", "Roaming");
16503
- return path3.join(appData, "Code - Insiders", "User", "mcp.json");
16504
- }
16505
- return path3.join(os3.homedir(), ".config", "Code - Insiders", "User", "mcp.json");
16494
+ if (platform === "darwin")
16495
+ return mac2;
16496
+ if (platform === "win32")
16497
+ return win;
16498
+ return linux;
16499
+ }
16500
+ function getHostConfigs() {
16501
+ const home = os3.homedir();
16502
+ const appData = getAppData();
16503
+ return [
16504
+ {
16505
+ name: "VS Code",
16506
+ path: platformPath(path3.join(home, "Library", "Application Support", "Code", "User", "mcp.json"), path3.join(appData, "Code", "User", "mcp.json"), path3.join(home, ".config", "Code", "User", "mcp.json")),
16507
+ serversKey: "servers"
16508
+ },
16509
+ {
16510
+ name: "VS Code Insiders",
16511
+ path: platformPath(path3.join(home, "Library", "Application Support", "Code - Insiders", "User", "mcp.json"), path3.join(appData, "Code - Insiders", "User", "mcp.json"), path3.join(home, ".config", "Code - Insiders", "User", "mcp.json")),
16512
+ serversKey: "servers"
16513
+ },
16514
+ {
16515
+ name: "Cursor",
16516
+ path: path3.join(home, ".cursor", "mcp.json"),
16517
+ serversKey: "servers"
16518
+ },
16519
+ {
16520
+ name: "Windsurf",
16521
+ path: path3.join(home, ".codeium", "windsurf", "mcp_config.json"),
16522
+ serversKey: "mcpServers"
16523
+ },
16524
+ {
16525
+ name: "Claude Code",
16526
+ path: path3.join(home, ".claude", "settings.json"),
16527
+ serversKey: "mcpServers"
16528
+ },
16529
+ {
16530
+ name: "Claude Desktop",
16531
+ path: platformPath(path3.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json"), path3.join(appData, "Claude", "claude_desktop_config.json"), path3.join(home, ".config", "Claude", "claude_desktop_config.json")),
16532
+ serversKey: "mcpServers"
16533
+ }
16534
+ ];
16506
16535
  }
16507
- function getCursorMcpPath() {
16508
- return path3.join(os3.homedir(), ".cursor", "mcp.json");
16536
+ function hasAnyRegistration() {
16537
+ const fs3 = __require("node:fs");
16538
+ for (const host of getHostConfigs()) {
16539
+ try {
16540
+ if (!fs3.existsSync(host.path))
16541
+ continue;
16542
+ const content = fs3.readFileSync(host.path, "utf-8");
16543
+ const config3 = JSON.parse(content);
16544
+ const servers = config3[host.serversKey];
16545
+ if (servers && servers[SERVER_NAME])
16546
+ return true;
16547
+ } catch {
16548
+ continue;
16549
+ }
16550
+ }
16551
+ return false;
16509
16552
  }
16510
- function getWindsurfMcpPath() {
16511
- return path3.join(os3.homedir(), ".codeium", "windsurf", "mcp_config.json");
16553
+ var SERVER_NAME = "kanbodev";
16554
+ var init_hosts = () => {};
16555
+
16556
+ // src/cli/register.ts
16557
+ import * as fs3 from "node:fs";
16558
+ import * as path4 from "node:path";
16559
+ import { execFileSync } from "node:child_process";
16560
+ function getMcpServerEntry() {
16561
+ if (process.platform === "win32") {
16562
+ const entryPoint = resolvePackageEntryPoint();
16563
+ if (entryPoint) {
16564
+ return { type: "stdio", command: "node", args: [entryPoint] };
16565
+ }
16566
+ }
16567
+ return { type: "stdio", command: "npx", args: ["@kanbodev/mcp"] };
16512
16568
  }
16513
- function getClaudeCodeSettingsPath() {
16514
- return path3.join(os3.homedir(), ".claude", "settings.json");
16569
+ function resolvePackageEntryPoint() {
16570
+ try {
16571
+ const npmRoot = execFileSync("npm", ["root", "-g"], {
16572
+ stdio: "pipe",
16573
+ shell: true,
16574
+ encoding: "utf-8"
16575
+ }).trim();
16576
+ const globalEntry = path4.join(npmRoot, "@kanbodev", "mcp", "dist", "index.js");
16577
+ if (fs3.existsSync(globalEntry)) {
16578
+ return globalEntry;
16579
+ }
16580
+ } catch {}
16581
+ try {
16582
+ const dir = typeof import.meta.dirname === "string" ? import.meta.dirname : typeof __dirname === "string" ? __dirname : null;
16583
+ if (dir) {
16584
+ const selfEntry = path4.resolve(dir, "index.js");
16585
+ if (fs3.existsSync(selfEntry)) {
16586
+ return selfEntry;
16587
+ }
16588
+ const parentEntry = path4.resolve(dir, "..", "dist", "index.js");
16589
+ if (fs3.existsSync(parentEntry)) {
16590
+ return parentEntry;
16591
+ }
16592
+ }
16593
+ } catch {}
16594
+ return null;
16515
16595
  }
16516
- function getClaudeDesktopMcpPath() {
16517
- const platform = process.platform;
16518
- if (platform === "darwin") {
16519
- return path3.join(os3.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
16520
- }
16521
- if (platform === "win32") {
16522
- const appData = process.env.APPDATA || path3.join(os3.homedir(), "AppData", "Roaming");
16523
- return path3.join(appData, "Claude", "claude_desktop_config.json");
16596
+ function isEntryOutdated(existing) {
16597
+ if (process.platform !== "win32" || typeof existing !== "object" || existing === null) {
16598
+ return false;
16524
16599
  }
16525
- return path3.join(os3.homedir(), ".config", "Claude", "claude_desktop_config.json");
16600
+ const entry = existing;
16601
+ return entry.command === "npx" || entry.command === "npx.cmd";
16526
16602
  }
16527
16603
  function registerInConfigFile(configPath, hostName, serversKey = "servers") {
16528
16604
  try {
16529
- const parentDir = path3.dirname(configPath);
16605
+ const parentDir = path4.dirname(configPath);
16530
16606
  if (!fs3.existsSync(parentDir)) {
16531
16607
  return { host: hostName, success: false, message: `${hostName} not detected` };
16532
16608
  }
@@ -16543,6 +16619,17 @@ function registerInConfigFile(configPath, hostName, serversKey = "servers") {
16543
16619
  }
16544
16620
  const servers = config3[serversKey] || {};
16545
16621
  if (servers[SERVER_NAME]) {
16622
+ if (isEntryOutdated(servers[SERVER_NAME])) {
16623
+ servers[SERVER_NAME] = getMcpServerEntry();
16624
+ config3[serversKey] = servers;
16625
+ fs3.writeFileSync(configPath, JSON.stringify(config3, null, 2) + `
16626
+ `, "utf-8");
16627
+ return {
16628
+ host: hostName,
16629
+ success: true,
16630
+ message: `Updated in ${hostName} (fixed Windows stdio)`
16631
+ };
16632
+ }
16546
16633
  return {
16547
16634
  host: hostName,
16548
16635
  success: true,
@@ -16550,7 +16637,7 @@ function registerInConfigFile(configPath, hostName, serversKey = "servers") {
16550
16637
  message: `Already registered in ${hostName}`
16551
16638
  };
16552
16639
  }
16553
- servers[SERVER_NAME] = MCP_SERVER_ENTRY;
16640
+ servers[SERVER_NAME] = getMcpServerEntry();
16554
16641
  config3[serversKey] = servers;
16555
16642
  fs3.writeFileSync(configPath, JSON.stringify(config3, null, 2) + `
16556
16643
  `, "utf-8");
@@ -16578,7 +16665,8 @@ function registerWithClaudeCli() {
16578
16665
  if (!isClaudeCliAvailable()) {
16579
16666
  return { host: hostName, success: false, message: "Claude Code CLI not detected" };
16580
16667
  }
16581
- execFileSync("claude", ["mcp", "add", SERVER_NAME, "--", "npx", "@kanbodev/mcp"], {
16668
+ const entry = getMcpServerEntry();
16669
+ execFileSync("claude", ["mcp", "add", SERVER_NAME, "--", entry.command, ...entry.args], {
16582
16670
  stdio: "pipe",
16583
16671
  ...shellOpt
16584
16672
  });
@@ -16593,12 +16681,10 @@ function registerWithClaudeCli() {
16593
16681
  }
16594
16682
  function registerMcpServer() {
16595
16683
  const results = [];
16596
- results.push(registerInConfigFile(getVscodeMcpPath(), "VS Code"));
16597
- results.push(registerInConfigFile(getVscodeInsidersMcpPath(), "VS Code Insiders"));
16598
- results.push(registerInConfigFile(getCursorMcpPath(), "Cursor"));
16599
- results.push(registerInConfigFile(getWindsurfMcpPath(), "Windsurf", "mcpServers"));
16600
- results.push(registerInConfigFile(getClaudeCodeSettingsPath(), "Claude Code", "mcpServers"));
16601
- results.push(registerInConfigFile(getClaudeDesktopMcpPath(), "Claude Desktop", "mcpServers"));
16684
+ const hosts = getHostConfigs();
16685
+ for (const host of hosts) {
16686
+ results.push(registerInConfigFile(host.path, host.name, host.serversKey));
16687
+ }
16602
16688
  results.push(registerWithClaudeCli());
16603
16689
  return results;
16604
16690
  }
@@ -16617,9 +16703,9 @@ function printRegistrationResults(results) {
16617
16703
  console.log(` · ${r.message}`);
16618
16704
  }
16619
16705
  }
16620
- if (registered.length > 0) {
16706
+ if (anySuccess) {
16621
16707
  console.log("");
16622
- console.log(" Reload your editor to activate the Kanbo MCP server.");
16708
+ console.log(" Restart your editor or open a new chat session to activate the MCP server.");
16623
16709
  }
16624
16710
  if (!anySuccess) {
16625
16711
  printManualInstructions();
@@ -16627,6 +16713,9 @@ function printRegistrationResults(results) {
16627
16713
  return anySuccess;
16628
16714
  }
16629
16715
  function printManualInstructions() {
16716
+ const entry = getMcpServerEntry();
16717
+ const commandStr = [entry.command, ...entry.args].join(" ");
16718
+ const hosts = getHostConfigs();
16630
16719
  console.log(" To register the MCP server manually, add this to your editor config:");
16631
16720
  console.log("");
16632
16721
  console.log(" For VS Code / Cursor (mcp.json):");
@@ -16634,8 +16723,8 @@ function printManualInstructions() {
16634
16723
  console.log(' "servers": {');
16635
16724
  console.log(' "kanbodev": {');
16636
16725
  console.log(' "type": "stdio",');
16637
- console.log(' "command": "npx",');
16638
- console.log(' "args": ["@kanbodev/mcp"]');
16726
+ console.log(` "command": "${entry.command}",`);
16727
+ console.log(` "args": ${JSON.stringify(entry.args)}`);
16639
16728
  console.log(" }");
16640
16729
  console.log(" }");
16641
16730
  console.log(" }");
@@ -16645,30 +16734,24 @@ function printManualInstructions() {
16645
16734
  console.log(' "mcpServers": {');
16646
16735
  console.log(' "kanbodev": {');
16647
16736
  console.log(' "type": "stdio",');
16648
- console.log(' "command": "npx",');
16649
- console.log(' "args": ["@kanbodev/mcp"]');
16737
+ console.log(` "command": "${entry.command}",`);
16738
+ console.log(` "args": ${JSON.stringify(entry.args)}`);
16650
16739
  console.log(" }");
16651
16740
  console.log(" }");
16652
16741
  console.log(" }");
16653
16742
  console.log("");
16654
16743
  console.log(" Config file locations:");
16655
- console.log(` VS Code: ${getVscodeMcpPath()}`);
16656
- console.log(` VS Code Insiders: ${getVscodeInsidersMcpPath()}`);
16657
- console.log(` Cursor: ${getCursorMcpPath()}`);
16658
- console.log(` Windsurf: ${getWindsurfMcpPath()}`);
16659
- console.log(` Claude Code: ${getClaudeCodeSettingsPath()}`);
16660
- console.log(` Claude Desktop: ${getClaudeDesktopMcpPath()}`);
16744
+ for (const host of hosts) {
16745
+ const padding = " ".repeat(Math.max(0, 18 - host.name.length));
16746
+ console.log(` ${host.name}:${padding}${host.path}`);
16747
+ }
16661
16748
  console.log("");
16662
16749
  console.log(" Or register via Claude Code CLI:");
16663
- console.log(" claude mcp add kanbodev -- npx @kanbodev/mcp");
16750
+ console.log(` claude mcp add kanbodev -- ${commandStr}`);
16664
16751
  }
16665
- var SERVER_NAME = "kanbodev", MCP_SERVER_ENTRY, shellOpt;
16752
+ var __dirname = "C:\\Users\\cloudpg07\\0dev\\kanbo-mcp\\src\\cli", shellOpt;
16666
16753
  var init_register = __esm(() => {
16667
- MCP_SERVER_ENTRY = {
16668
- type: "stdio",
16669
- command: "npx",
16670
- args: ["@kanbodev/mcp"]
16671
- };
16754
+ init_hosts();
16672
16755
  shellOpt = process.platform === "win32" ? { shell: true } : {};
16673
16756
  });
16674
16757
 
@@ -16817,15 +16900,15 @@ var execFile2, wslDrivesMountPoint, powerShellPathFromWsl = async () => {
16817
16900
  const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
16818
16901
  const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
16819
16902
  return stdout.trim();
16820
- }, convertWslPathToWindows = async (path4) => {
16821
- if (/^[a-z]+:\/\//i.test(path4)) {
16822
- return path4;
16903
+ }, convertWslPathToWindows = async (path5) => {
16904
+ if (/^[a-z]+:\/\//i.test(path5)) {
16905
+ return path5;
16823
16906
  }
16824
16907
  try {
16825
- const { stdout } = await execFile2("wslpath", ["-aw", path4], { encoding: "utf8" });
16908
+ const { stdout } = await execFile2("wslpath", ["-aw", path5], { encoding: "utf8" });
16826
16909
  return stdout.trim();
16827
16910
  } catch {
16828
- return path4;
16911
+ return path5;
16829
16912
  }
16830
16913
  };
16831
16914
  var init_wsl_utils = __esm(() => {
@@ -17024,7 +17107,7 @@ __export(exports_open, {
17024
17107
  apps: () => apps
17025
17108
  });
17026
17109
  import process10 from "node:process";
17027
- import path4 from "node:path";
17110
+ import path5 from "node:path";
17028
17111
  import { fileURLToPath } from "node:url";
17029
17112
  import childProcess3 from "node:child_process";
17030
17113
  import fs8, { constants as fsConstants2 } from "node:fs/promises";
@@ -17213,19 +17296,19 @@ var fallbackAttemptSymbol, __dirname2, localXdgOpenPath, platform, arch, tryEach
17213
17296
  }
17214
17297
  const subprocess = childProcess3.spawn(command, cliArguments, childProcessOptions);
17215
17298
  if (options.wait) {
17216
- return new Promise((resolve, reject) => {
17299
+ return new Promise((resolve2, reject) => {
17217
17300
  subprocess.once("error", reject);
17218
17301
  subprocess.once("close", (exitCode) => {
17219
17302
  if (!options.allowNonzeroExitCode && exitCode !== 0) {
17220
17303
  reject(new Error(`Exited with code ${exitCode}`));
17221
17304
  return;
17222
17305
  }
17223
- resolve(subprocess);
17306
+ resolve2(subprocess);
17224
17307
  });
17225
17308
  });
17226
17309
  }
17227
17310
  if (isFallbackAttempt) {
17228
- return new Promise((resolve, reject) => {
17311
+ return new Promise((resolve2, reject) => {
17229
17312
  subprocess.once("error", reject);
17230
17313
  subprocess.once("spawn", () => {
17231
17314
  subprocess.once("close", (exitCode) => {
@@ -17235,17 +17318,17 @@ var fallbackAttemptSymbol, __dirname2, localXdgOpenPath, platform, arch, tryEach
17235
17318
  return;
17236
17319
  }
17237
17320
  subprocess.unref();
17238
- resolve(subprocess);
17321
+ resolve2(subprocess);
17239
17322
  });
17240
17323
  });
17241
17324
  });
17242
17325
  }
17243
17326
  subprocess.unref();
17244
- return new Promise((resolve, reject) => {
17327
+ return new Promise((resolve2, reject) => {
17245
17328
  subprocess.once("error", reject);
17246
17329
  subprocess.once("spawn", () => {
17247
17330
  subprocess.off("error", reject);
17248
- resolve(subprocess);
17331
+ resolve2(subprocess);
17249
17332
  });
17250
17333
  });
17251
17334
  }, open = (target, options) => {
@@ -17279,8 +17362,8 @@ var init_open = __esm(() => {
17279
17362
  init_is_inside_container();
17280
17363
  init_is_in_ssh();
17281
17364
  fallbackAttemptSymbol = Symbol("fallbackAttempt");
17282
- __dirname2 = import.meta.url ? path4.dirname(fileURLToPath(import.meta.url)) : "";
17283
- localXdgOpenPath = path4.join(__dirname2, "xdg-open");
17365
+ __dirname2 = import.meta.url ? path5.dirname(fileURLToPath(import.meta.url)) : "";
17366
+ localXdgOpenPath = path5.join(__dirname2, "xdg-open");
17284
17367
  ({ platform, arch } = process10);
17285
17368
  apps = {
17286
17369
  browser: "browser",
@@ -17453,6 +17536,12 @@ async function logout() {
17453
17536
  console.log("");
17454
17537
  console.log(` Config removed from: ${getConfigPath()}`);
17455
17538
  console.log("");
17539
+ if (hasAnyRegistration()) {
17540
+ console.log(" ⚠ MCP server is still registered in your editor(s).");
17541
+ console.log(" To remove it, run:");
17542
+ console.log(" kanbo-mcp uninstall");
17543
+ console.log("");
17544
+ }
17456
17545
  console.log(" To log in again, run:");
17457
17546
  console.log(" kanbo-mcp login");
17458
17547
  console.log("");
@@ -17463,6 +17552,7 @@ async function logout() {
17463
17552
  }
17464
17553
  var init_logout = __esm(() => {
17465
17554
  init_config();
17555
+ init_hosts();
17466
17556
  });
17467
17557
 
17468
17558
  // src/cli/whoami.ts
@@ -17539,6 +17629,142 @@ var init_install = __esm(() => {
17539
17629
  init_register();
17540
17630
  });
17541
17631
 
17632
+ // src/cli/uninstall.ts
17633
+ var exports_uninstall = {};
17634
+ __export(exports_uninstall, {
17635
+ uninstall: () => uninstall
17636
+ });
17637
+ import * as fs9 from "node:fs";
17638
+ import * as path6 from "node:path";
17639
+ import { execFileSync as execFileSync3 } from "node:child_process";
17640
+ function removeFromConfigFile(host) {
17641
+ try {
17642
+ if (!fs9.existsSync(host.path)) {
17643
+ return { host: host.name, removed: false, message: "Config file not found" };
17644
+ }
17645
+ const content = fs9.readFileSync(host.path, "utf-8");
17646
+ let config3;
17647
+ try {
17648
+ config3 = JSON.parse(content);
17649
+ } catch {
17650
+ return { host: host.name, removed: false, message: "Config file has invalid JSON" };
17651
+ }
17652
+ const servers = config3[host.serversKey];
17653
+ if (!servers || !servers[SERVER_NAME]) {
17654
+ return { host: host.name, removed: false, message: "Not registered" };
17655
+ }
17656
+ delete servers[SERVER_NAME];
17657
+ config3[host.serversKey] = servers;
17658
+ fs9.writeFileSync(host.path, JSON.stringify(config3, null, 2) + `
17659
+ `, "utf-8");
17660
+ return { host: host.name, removed: true, message: `Removed from ${host.name}` };
17661
+ } catch (error2) {
17662
+ const msg = error2 instanceof Error ? error2.message : "Unknown error";
17663
+ return { host: host.name, removed: false, message: `Failed: ${msg}` };
17664
+ }
17665
+ }
17666
+ function removeFromProjectMcpJson() {
17667
+ const hostName = "Project .mcp.json";
17668
+ const mcpJsonPath = path6.join(process.cwd(), ".mcp.json");
17669
+ try {
17670
+ if (!fs9.existsSync(mcpJsonPath)) {
17671
+ return { host: hostName, removed: false, message: "No project .mcp.json found" };
17672
+ }
17673
+ const content = fs9.readFileSync(mcpJsonPath, "utf-8");
17674
+ let config3;
17675
+ try {
17676
+ config3 = JSON.parse(content);
17677
+ } catch {
17678
+ return { host: hostName, removed: false, message: ".mcp.json has invalid JSON" };
17679
+ }
17680
+ let found = false;
17681
+ for (const key of ["servers", "mcpServers"]) {
17682
+ const servers = config3[key];
17683
+ if (servers && servers[SERVER_NAME]) {
17684
+ delete servers[SERVER_NAME];
17685
+ config3[key] = servers;
17686
+ found = true;
17687
+ }
17688
+ }
17689
+ if (!found) {
17690
+ return { host: hostName, removed: false, message: "Not registered in .mcp.json" };
17691
+ }
17692
+ const hasOtherServers = ["servers", "mcpServers"].some((key) => {
17693
+ const servers = config3[key];
17694
+ return servers && Object.keys(servers).length > 0;
17695
+ });
17696
+ if (hasOtherServers) {
17697
+ fs9.writeFileSync(mcpJsonPath, JSON.stringify(config3, null, 2) + `
17698
+ `, "utf-8");
17699
+ } else {
17700
+ fs9.unlinkSync(mcpJsonPath);
17701
+ }
17702
+ return { host: hostName, removed: true, message: "Removed from project .mcp.json" };
17703
+ } catch (error2) {
17704
+ const msg = error2 instanceof Error ? error2.message : "Unknown error";
17705
+ return { host: hostName, removed: false, message: `Failed: ${msg}` };
17706
+ }
17707
+ }
17708
+ function removeFromClaudeCli() {
17709
+ const hostName = "Claude Code CLI";
17710
+ try {
17711
+ execFileSync3("claude", ["--version"], { stdio: "pipe", ...shellOpt2 });
17712
+ } catch {
17713
+ return { host: hostName, removed: false, message: "Claude Code CLI not detected" };
17714
+ }
17715
+ try {
17716
+ execFileSync3("claude", ["mcp", "remove", SERVER_NAME], {
17717
+ stdio: "pipe",
17718
+ ...shellOpt2
17719
+ });
17720
+ return { host: hostName, removed: true, message: "Removed from Claude Code CLI" };
17721
+ } catch (error2) {
17722
+ const msg = error2 instanceof Error ? error2.message : "Unknown error";
17723
+ if (msg.includes("not found") || msg.includes("does not exist")) {
17724
+ return { host: hostName, removed: false, message: "Not registered" };
17725
+ }
17726
+ return { host: hostName, removed: false, message: `Failed: ${msg}` };
17727
+ }
17728
+ }
17729
+ async function uninstall() {
17730
+ console.log(`
17731
+ Kanbo MCP — Uninstall
17732
+ `);
17733
+ const results = [];
17734
+ for (const host of getHostConfigs()) {
17735
+ results.push(removeFromConfigFile(host));
17736
+ }
17737
+ results.push(removeFromProjectMcpJson());
17738
+ results.push(removeFromClaudeCli());
17739
+ const removed = results.filter((r) => r.removed);
17740
+ const notRegistered = results.filter((r) => !r.removed);
17741
+ if (removed.length > 0) {
17742
+ console.log(" MCP server removed from:");
17743
+ for (const r of removed) {
17744
+ console.log(` ✓ ${r.message}`);
17745
+ }
17746
+ }
17747
+ if (notRegistered.length > 0) {
17748
+ for (const r of notRegistered) {
17749
+ console.log(` · ${r.host}: ${r.message}`);
17750
+ }
17751
+ }
17752
+ console.log("");
17753
+ if (removed.length > 0) {
17754
+ console.log(" ⚡ Restart your editor or open a new chat session to complete the removal.");
17755
+ console.log("");
17756
+ }
17757
+ console.log(" Note: This only removes MCP server registrations.");
17758
+ console.log(" To also remove credentials, run: kanbo-mcp logout");
17759
+ console.log(" To uninstall the package: npm uninstall -g @kanbodev/mcp");
17760
+ console.log("");
17761
+ }
17762
+ var shellOpt2;
17763
+ var init_uninstall = __esm(() => {
17764
+ init_hosts();
17765
+ shellOpt2 = process.platform === "win32" ? { shell: true } : {};
17766
+ });
17767
+
17542
17768
  // src/index.ts
17543
17769
  init_constants();
17544
17770
 
@@ -45159,6 +45385,9 @@ async function handleCliCommand(command) {
45159
45385
  case "install":
45160
45386
  await Promise.resolve().then(() => (init_install(), exports_install)).then((m) => m.install());
45161
45387
  return true;
45388
+ case "uninstall":
45389
+ await Promise.resolve().then(() => (init_uninstall(), exports_uninstall)).then((m) => m.uninstall());
45390
+ return true;
45162
45391
  case "help":
45163
45392
  case "--help":
45164
45393
  case "-h":
@@ -45184,6 +45413,7 @@ function showHelp() {
45184
45413
  (none) Start the MCP server (default)
45185
45414
  login Authenticate via browser OAuth + register MCP server
45186
45415
  install Register MCP server with detected editors
45416
+ uninstall Remove MCP server from all registered editors
45187
45417
  logout Remove stored credentials
45188
45418
  whoami Show current authentication status
45189
45419
  help Show this help message
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kanbodev/mcp",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "MCP (Model Context Protocol) server for Kanbo - AI-native project management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",