@teambit/cli-mcp-server 0.0.12 → 0.0.14

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.
@@ -18,6 +18,13 @@ function _child_process() {
18
18
  };
19
19
  return data;
20
20
  }
21
+ function _fsExtra() {
22
+ const data = _interopRequireDefault(require("fs-extra"));
23
+ _fsExtra = function () {
24
+ return data;
25
+ };
26
+ return data;
27
+ }
21
28
  function _cliMcpServer() {
22
29
  const data = require("./cli-mcp-server.aspect");
23
30
  _cliMcpServer = function () {
@@ -81,6 +88,20 @@ function _nodeFetch() {
81
88
  };
82
89
  return data;
83
90
  }
91
+ function _setupCmd() {
92
+ const data = require("./setup-cmd");
93
+ _setupCmd = function () {
94
+ return data;
95
+ };
96
+ return data;
97
+ }
98
+ function _setupUtils() {
99
+ const data = require("./setup-utils");
100
+ _setupUtils = function () {
101
+ return data;
102
+ };
103
+ return data;
104
+ }
84
105
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
85
106
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
86
107
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -247,8 +268,7 @@ class CliMcpServerMain {
247
268
  }
248
269
 
249
270
  // Resolve the real path to handle symlinks (e.g., /tmp -> /private/tmp on macOS)
250
- const fs = require('fs');
251
- const realCwd = fs.realpathSync(cwd);
271
+ const realCwd = _fsExtra().default.realpathSync(cwd);
252
272
  let body;
253
273
  let url;
254
274
  if (isIDERoute) {
@@ -310,8 +330,6 @@ class CliMcpServerMain {
310
330
  const commands = this.cli.commands;
311
331
  const extended = Boolean(options.extended);
312
332
  this.bitBin = options.bitBin || this.bitBin;
313
- // Default set of tools to include
314
- const defaultTools = new Set(['create', 'schema', 'remote-search']);
315
333
 
316
334
  // Tools to always exclude
317
335
  const alwaysExcludeTools = new Set(['login', 'logout', 'completion', 'mcp-server', 'start', 'run-action', 'watch', 'run', 'resume-export', 'server', 'serve-preview']);
@@ -338,7 +356,7 @@ class CliMcpServerMain {
338
356
  });
339
357
 
340
358
  // Set of tools for consumer projects (non-Bit workspaces)
341
- const consumerProjectTools = new Set(['schema', 'show', 'remote-search']);
359
+ const consumerProjectTools = new Set(['schema', 'show']);
342
360
  const consumerProject = Boolean(options.consumerProject);
343
361
 
344
362
  // Store consumer project mode globally in the class
@@ -346,7 +364,7 @@ class CliMcpServerMain {
346
364
 
347
365
  // Validate flags combination
348
366
  if (consumerProject) {
349
- this.logger.debug(`[MCP-DEBUG] Running MCP server in consumer project mode (for non-Bit workspaces) with tools: ${Array.from(consumerProjectTools).join(', ')}`);
367
+ this.logger.debug(`[MCP-DEBUG] Running MCP server in consumer project mode (for non-Bit workspaces) with tools: ${Array.from(consumerProjectTools).join(', ')} + remote-search (always available)`);
350
368
  if (options.includeAdditional) {
351
369
  this.logger.debug(`[MCP-DEBUG] Additional tools enabled in consumer project mode: ${options.includeAdditional}`);
352
370
  }
@@ -355,7 +373,6 @@ class CliMcpServerMain {
355
373
  }
356
374
  }
357
375
  const filterOptions = {
358
- defaultTools,
359
376
  additionalCommandsSet,
360
377
  userExcludeSet,
361
378
  alwaysExcludeTools,
@@ -376,12 +393,9 @@ class CliMcpServerMain {
376
393
  this.processSubCommands(server, cmd, filterOptions);
377
394
  }
378
395
  });
379
- const remoteCommands = ['remote-search'];
380
- remoteCommands.forEach(cmdName => {
381
- if (this.shouldIncludeCommand(cmdName, filterOptions)) {
382
- this.registerToolForRemote(server, cmdName);
383
- }
384
- });
396
+
397
+ // Always register remote-search tool
398
+ this.registerRemoteSearchTool(server);
385
399
 
386
400
  // Register the bit_workspace_info tool
387
401
  this.registerWorkspaceInfoTool(server);
@@ -389,10 +403,9 @@ class CliMcpServerMain {
389
403
  // Register the bit_component_details tool
390
404
  this.registerComponentDetailsTool(server);
391
405
 
392
- // Register the bit_commands_info tool
393
- this.registerCommandsInfoTool(server);
394
-
395
- // Register arbitrary command execution tools
406
+ // Register command discovery and help tools
407
+ this.registerCommandsListTool(server);
408
+ this.registerCommandHelpTool(server);
396
409
  this.registerQueryTool(server);
397
410
  this.registerExecuteTool(server);
398
411
  await server.connect(new (_stdio().StdioServerTransport)());
@@ -428,8 +441,8 @@ class CliMcpServerMain {
428
441
  return shouldInclude;
429
442
  }
430
443
 
431
- // Default mode: include default tools + any additional specified
432
- return options.defaultTools.has(cmdName) || (options.additionalCommandsSet?.has(cmdName) ?? false);
444
+ // Default mode: only include additional specified commands (no default tools anymore)
445
+ return options.additionalCommandsSet?.has(cmdName) ?? false;
433
446
  }
434
447
  buildZodSchema(config) {
435
448
  const schema = {
@@ -522,16 +535,11 @@ class CliMcpServerMain {
522
535
  return this.runBit(argsToRun, params.cwd);
523
536
  });
524
537
  }
525
- registerToolForRemote(server, name) {
526
- if (name === 'remote-search') {
527
- this.registerRemoteSearchTool(server);
528
- }
529
- }
530
538
  registerRemoteSearchTool(server) {
531
- const toolName = this.getToolName('remote-search');
532
- const description = 'Search for components in remote scopes';
539
+ const toolName = 'bit_remote_search';
540
+ const description = 'Search for components in remote scopes. Use this tool to find existing components before creating new ones. Essential for component reuse and discovery. Returns component IDs that can be converted to package names for installation (e.g., "teambit.design/ui/button" becomes "@teambit/design.ui.button"). Use broad keywords rather than multiple specific terms for better results.';
533
541
  const schema = {
534
- queryStr: _zod().z.string().describe('Search query string')
542
+ queryStr: _zod().z.string().describe('Search query string - use broad keywords like "button", "form", "card" rather than multiple specific terms')
535
543
  };
536
544
  server.tool(toolName, description, schema, async params => {
537
545
  const http = await this.getHttp();
@@ -647,134 +655,147 @@ class CliMcpServerMain {
647
655
  }
648
656
  });
649
657
  }
650
- registerCommandsInfoTool(server) {
651
- const toolName = 'bit_commands_info';
652
- const description = 'Get information about Bit commands and their groups. Specify command or subcommand to get detailed info.';
658
+ registerCommandsListTool(server) {
659
+ const toolName = 'bit_commands_list';
660
+ const description = 'Get all available Bit commands with descriptions and groups. Use this to discover what commands are available.';
653
661
  const schema = {
654
662
  extendedDescription: _zod().z.boolean().optional().describe('Include extended descriptions for commands (default: false)'),
655
- internal: _zod().z.boolean().optional().describe('Include internal/debug commands (default: false)'),
656
- command: _zod().z.string().optional().describe('Get info for a specific command only'),
657
- subcommand: _zod().z.string().optional().describe('Get info for subcommands of a specific main command')
663
+ internal: _zod().z.boolean().optional().describe('Include internal/debug commands (default: false)')
658
664
  };
659
665
  server.tool(toolName, description, schema, async params => {
660
666
  try {
661
667
  const {
662
668
  extendedDescription = false,
663
- internal = false,
664
- command: specificCommand,
665
- subcommand: specificSubcommand
669
+ internal = false
666
670
  } = params;
667
671
  const commandsInfo = [];
668
672
  const shouldSkipCommand = cmd => {
669
673
  return Boolean(cmd.private && !internal || cmd.description.startsWith('DEPRECATED'));
670
674
  };
671
- const buildCommandInfo = (cmd, parentName, parentGroup, detailed = false) => {
672
- if (shouldSkipCommand(cmd)) return null;
673
- const cmdName = parentName ? `${parentName} ${(0, _cli().getCommandName)(cmd)}` : (0, _cli().getCommandName)(cmd);
674
- const groupKey = cmd.group || parentGroup;
675
+
676
+ // Build list of all commands
677
+ this.cli.commands.forEach(cmd => {
678
+ if (shouldSkipCommand(cmd)) return;
679
+ const mainCmdName = (0, _cli().getCommandName)(cmd);
680
+ const groupKey = cmd.group;
675
681
  const commandInfo = {
676
- name: cmdName,
677
- description: cmd.description || ''
682
+ name: mainCmdName,
683
+ description: cmd.description || '',
684
+ alias: cmd.alias || ''
678
685
  };
679
686
  if (extendedDescription && cmd.extendedDescription) {
680
687
  commandInfo.extendedDescription = cmd.extendedDescription;
681
688
  }
682
689
  if (groupKey) commandInfo.group = this.cli.groups[groupKey] || groupKey;
683
- if (!detailed) return commandInfo;
684
-
685
- // Add detailed information
686
690
  if (cmd.helpUrl) commandInfo.helpUrl = cmd.helpUrl;
691
+
692
+ // Add subcommands summary
693
+ if (cmd.commands && cmd.commands.length > 0) {
694
+ commandInfo.subcommands = cmd.commands.filter(subCmd => !shouldSkipCommand(subCmd)).map(subCmd => ({
695
+ name: (0, _cli().getCommandName)(subCmd),
696
+ description: subCmd.description || '',
697
+ alias: subCmd.alias || ''
698
+ }));
699
+ }
700
+ commandsInfo.push(commandInfo);
701
+ });
702
+ commandsInfo.sort((a, b) => a.name.localeCompare(b.name));
703
+ const result = JSON.stringify({
704
+ total: commandsInfo.length,
705
+ commands: commandsInfo
706
+ }, null, 2);
707
+ this.logger.debug(`[MCP-DEBUG] Successfully retrieved commands list. Total: ${commandsInfo.length}`);
708
+ return this.formatAsCallToolResult(result);
709
+ } catch (error) {
710
+ this.logger.error(`[MCP-DEBUG] Error in bit_commands_list tool: ${error.message}`);
711
+ return this.formatErrorAsCallToolResult(error, 'getting commands list');
712
+ }
713
+ });
714
+ }
715
+ registerCommandHelpTool(server) {
716
+ const toolName = 'bit_command_help';
717
+ const description = 'Get detailed help for a specific Bit command including syntax, arguments, flags, and usage examples. Use this to understand exactly how to use a command.';
718
+ const schema = {
719
+ command: _zod().z.string().describe('The command name to get help for (e.g., "status", "install", "create")'),
720
+ subcommand: _zod().z.string().optional().describe('Optional subcommand name (e.g., for "lane show", use command="lane" and subcommand="show")')
721
+ };
722
+ server.tool(toolName, description, schema, async params => {
723
+ try {
724
+ const {
725
+ command: requestedCommand,
726
+ subcommand: requestedSubcommand
727
+ } = params;
728
+ let commandInfo = null;
729
+ const buildDetailedCommandInfo = (cmd, parentName) => {
730
+ const cmdName = parentName ? `${parentName} ${(0, _cli().getCommandName)(cmd)}` : (0, _cli().getCommandName)(cmd);
731
+ const info = {
732
+ name: cmdName,
733
+ description: cmd.description || '',
734
+ extendedDescription: cmd.extendedDescription || '',
735
+ alias: cmd.alias || '',
736
+ group: cmd.group ? this.cli.groups[cmd.group] || cmd.group : '',
737
+ helpUrl: cmd.helpUrl || '',
738
+ private: cmd.private || false
739
+ };
740
+
741
+ // Add arguments information
687
742
  const argsData = (0, _cli().getArgsData)(cmd);
688
743
  if (argsData.length > 0) {
689
- commandInfo.arguments = argsData.map(arg => ({
744
+ info.arguments = argsData.map(arg => ({
690
745
  name: arg.nameRaw,
691
746
  description: arg.description || '',
692
747
  required: arg.required,
693
748
  isArray: arg.isArray
694
749
  }));
695
750
  }
696
- commandInfo.options = (0, _cli().getFlagsData)(cmd);
697
- commandInfo.examples = cmd.examples;
751
+
752
+ // Add options/flags information
753
+ info.options = (0, _cli().getFlagsData)(cmd);
754
+
755
+ // Add examples if available
756
+ if (cmd.examples) {
757
+ info.examples = cmd.examples;
758
+ }
759
+
760
+ // Add subcommands if available (including private ones for help purposes)
698
761
  if (cmd.commands && cmd.commands.length > 0) {
699
- commandInfo.subcommands = cmd.commands.filter(subCmd => !shouldSkipCommand(subCmd)).map(subCmd => ({
700
- name: `${cmdName} ${(0, _cli().getCommandName)(subCmd)}`,
762
+ info.subcommands = cmd.commands.map(subCmd => ({
763
+ name: (0, _cli().getCommandName)(subCmd),
701
764
  description: subCmd.description || '',
702
- alias: subCmd.alias || '',
703
- private: Boolean(subCmd.private)
765
+ alias: subCmd.alias || ''
704
766
  }));
705
767
  }
706
- return commandInfo;
768
+ return info;
707
769
  };
708
770
 
709
- // Handle specific command + subcommand lookup
710
- if (specificCommand && specificSubcommand) {
711
- this.cli.commands.forEach(cmd => {
712
- if ((0, _cli().getCommandName)(cmd) === specificCommand && cmd.commands) {
713
- const subCmd = cmd.commands.find(sub => (0, _cli().getCommandName)(sub) === specificSubcommand);
771
+ // Search for the requested command
772
+ this.cli.commands.forEach(cmd => {
773
+ const mainCmdName = (0, _cli().getCommandName)(cmd);
774
+ if (requestedSubcommand) {
775
+ // Looking for a subcommand
776
+ if (mainCmdName === requestedCommand && cmd.commands) {
777
+ const subCmd = cmd.commands.find(sub => (0, _cli().getCommandName)(sub) === requestedSubcommand);
714
778
  if (subCmd) {
715
- const info = buildCommandInfo(subCmd, specificCommand, cmd.group, true);
716
- if (info) commandsInfo.push(info);
717
- }
718
- }
719
- });
720
- }
721
- // Handle subcommand-only lookup
722
- else if (specificSubcommand && !specificCommand) {
723
- this.cli.commands.forEach(cmd => {
724
- if ((0, _cli().getCommandName)(cmd) === specificSubcommand && cmd.commands) {
725
- cmd.commands.forEach(subCmd => {
726
- const info = buildCommandInfo(subCmd, specificSubcommand, cmd.group);
727
- if (info) commandsInfo.push(info);
728
- });
729
- }
730
- });
731
- }
732
- // Handle specific command lookup or general listing
733
- else {
734
- const isDetailedMode = Boolean(specificCommand);
735
- this.cli.commands.forEach(cmd => {
736
- const mainCmdName = (0, _cli().getCommandName)(cmd);
737
-
738
- // Process main command
739
- if (!specificCommand || mainCmdName === specificCommand) {
740
- const info = buildCommandInfo(cmd, undefined, undefined, isDetailedMode);
741
- if (info && (!specificCommand || info.name === specificCommand)) {
742
- commandsInfo.push(info);
779
+ commandInfo = buildDetailedCommandInfo(subCmd, requestedCommand);
743
780
  }
744
781
  }
745
-
746
- // Process subcommands
747
- if (cmd.commands) {
748
- cmd.commands.forEach(subCmd => {
749
- const subCmdInfo = buildCommandInfo(subCmd, mainCmdName, cmd.group, isDetailedMode);
750
- if (subCmdInfo && (!specificCommand || subCmdInfo.name === specificCommand)) {
751
- commandsInfo.push(subCmdInfo);
752
- }
753
- });
782
+ } else {
783
+ // Looking for a main command
784
+ if (mainCmdName === requestedCommand) {
785
+ commandInfo = buildDetailedCommandInfo(cmd);
754
786
  }
755
- });
756
- }
757
- commandsInfo.sort((a, b) => a.name.localeCompare(b.name));
758
- if (commandsInfo.length === 0) {
759
- let errorMessage = 'No commands found';
760
- if (specificCommand && specificSubcommand) {
761
- errorMessage = `No subcommand "${specificSubcommand}" found for command: ${specificCommand}`;
762
- } else if (specificCommand) {
763
- errorMessage = `No command found with name: ${specificCommand}`;
764
- } else if (specificSubcommand) {
765
- errorMessage = `No subcommands found for command: ${specificSubcommand}`;
766
787
  }
767
- return this.formatAsCallToolResult(errorMessage);
788
+ });
789
+ if (!commandInfo) {
790
+ const commandFullName = requestedSubcommand ? `${requestedCommand} ${requestedSubcommand}` : requestedCommand;
791
+ return this.formatAsCallToolResult(`Command not found: ${commandFullName}`);
768
792
  }
769
- const result = JSON.stringify({
770
- total: commandsInfo.length,
771
- commands: commandsInfo
772
- }, null, 2);
773
- this.logger.debug(`[MCP-DEBUG] Successfully retrieved commands info. Total: ${commandsInfo.length}`);
793
+ const result = JSON.stringify(commandInfo, null, 2);
794
+ this.logger.debug(`[MCP-DEBUG] Successfully retrieved command help for: ${commandInfo.name}`);
774
795
  return this.formatAsCallToolResult(result);
775
796
  } catch (error) {
776
- this.logger.error(`[MCP-DEBUG] Error in bit_commands_info tool: ${error.message}`);
777
- return this.formatErrorAsCallToolResult(error, 'getting commands info');
797
+ this.logger.error(`[MCP-DEBUG] Error in bit_command_help tool: ${error.message}`);
798
+ return this.formatErrorAsCallToolResult(error, 'getting command help');
778
799
  }
779
800
  });
780
801
  }
@@ -828,21 +849,30 @@ class CliMcpServerMain {
828
849
  }
829
850
  registerExecuteTool(server) {
830
851
  const toolName = 'bit_execute';
831
- const description = 'Execute any Bit command, including those that modify workspace or repository state. ⚠️ Use with caution as this can make permanent changes to your project. Consider using bit_query for read-only operations.';
852
+ const description = 'Execute Bit commands that make changes to workspace or components (not read-only).';
832
853
  const schema = {
833
854
  cwd: _zod().z.string().describe('Path to workspace directory'),
834
- command: _zod().z.string().describe('The Bit command to execute (e.g., "add", "tag", "export", "remove")'),
855
+ command: _zod().z.string().describe('The Bit command to execute (e.g., "import", "tag", "export", "remove")'),
835
856
  args: _zod().z.array(_zod().z.string()).optional().describe('Arguments to pass to the command'),
836
857
  flags: _zod().z.record(_zod().z.union([_zod().z.string(), _zod().z.boolean()])).optional().describe('Flags to pass to the command as key-value pairs')
837
858
  };
838
859
  server.tool(toolName, description, schema, async params => {
839
860
  try {
840
- const {
861
+ let {
841
862
  command,
842
- args = [],
863
+ args = []
864
+ } = params;
865
+ const {
843
866
  flags = {},
844
867
  cwd
845
868
  } = params;
869
+
870
+ // Handle sub-commands: if command has multiple words, move the second word to args
871
+ const commandParts = command.trim().split(/\s+/);
872
+ if (commandParts.length > 1) {
873
+ command = commandParts[0];
874
+ args = [commandParts[1], ...args];
875
+ }
846
876
  this.logger.debug(`[MCP-DEBUG] Executing command: ${command} with args: ${JSON.stringify(args)} and flags: ${JSON.stringify(flags)}`);
847
877
  const result = await this.callBitServerAPI(command, args, flags, cwd);
848
878
  return this.formatAsCallToolResult(result);
@@ -965,10 +995,37 @@ class CliMcpServerMain {
965
995
  }
966
996
  }
967
997
  }
998
+
999
+ // Setup command business logic methods
1000
+ getEditorDisplayName(editor) {
1001
+ return _setupUtils().McpSetupUtils.getEditorDisplayName(editor);
1002
+ }
1003
+ async setupEditor(editor, options, workspaceDir) {
1004
+ const supportedEditors = ['vscode', 'cursor', 'windsurf'];
1005
+ const editorLower = editor.toLowerCase();
1006
+ if (!supportedEditors.includes(editorLower)) {
1007
+ throw new Error(`Editor "${editor}" is not supported yet. Currently supported: ${supportedEditors.join(', ')}`);
1008
+ }
1009
+
1010
+ // Add workspaceDir to options if provided
1011
+ const setupOptions = _objectSpread({}, options);
1012
+ if (workspaceDir) {
1013
+ setupOptions.workspaceDir = workspaceDir;
1014
+ }
1015
+ if (editorLower === 'vscode') {
1016
+ await _setupUtils().McpSetupUtils.setupVSCode(setupOptions);
1017
+ } else if (editorLower === 'cursor') {
1018
+ await _setupUtils().McpSetupUtils.setupCursor(setupOptions);
1019
+ } else if (editorLower === 'windsurf') {
1020
+ await _setupUtils().McpSetupUtils.setupWindsurf(setupOptions);
1021
+ }
1022
+ }
968
1023
  static async provider([cli, loggerMain]) {
969
1024
  const logger = loggerMain.createLogger(_cliMcpServer().CliMcpServerAspect.id);
970
1025
  const mcpServer = new CliMcpServerMain(cli, logger);
971
- cli.register(new (_mcpServer().McpServerCmd)(mcpServer));
1026
+ const mcpServerCmd = new (_mcpServer().McpServerCmd)(mcpServer);
1027
+ mcpServerCmd.commands = [new (_mcpServer().McpStartCmd)(mcpServer), new (_setupCmd().McpSetupCmd)(mcpServer)];
1028
+ cli.register(mcpServerCmd);
972
1029
  return mcpServer;
973
1030
  }
974
1031
  }