@teambit/cli-mcp-server 0.0.0-00149e000ea14bbdcb0391c0d576b4a2b40f8cde

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.
@@ -0,0 +1,740 @@
1
+ "use strict";
2
+
3
+ function _chai() {
4
+ const data = require("chai");
5
+ _chai = function () {
6
+ return data;
7
+ };
8
+ return data;
9
+ }
10
+ function _index() {
11
+ const data = require("@modelcontextprotocol/sdk/client/index.js");
12
+ _index = function () {
13
+ return data;
14
+ };
15
+ return data;
16
+ }
17
+ function _stdio() {
18
+ const data = require("@modelcontextprotocol/sdk/client/stdio.js");
19
+ _stdio = function () {
20
+ return data;
21
+ };
22
+ return data;
23
+ }
24
+ function _workspaceTesting() {
25
+ const data = require("@teambit/workspace.testing.mock-workspace");
26
+ _workspaceTesting = function () {
27
+ return data;
28
+ };
29
+ return data;
30
+ }
31
+ function _componentTesting() {
32
+ const data = require("@teambit/component.testing.mock-components");
33
+ _componentTesting = function () {
34
+ return data;
35
+ };
36
+ return data;
37
+ }
38
+ function _harmonyTesting() {
39
+ const data = require("@teambit/harmony.testing.load-aspect");
40
+ _harmonyTesting = function () {
41
+ return data;
42
+ };
43
+ return data;
44
+ }
45
+ function _fsExtra() {
46
+ const data = _interopRequireDefault(require("fs-extra"));
47
+ _fsExtra = function () {
48
+ return data;
49
+ };
50
+ return data;
51
+ }
52
+ function _path() {
53
+ const data = _interopRequireDefault(require("path"));
54
+ _path = function () {
55
+ return data;
56
+ };
57
+ return data;
58
+ }
59
+ function _cliMcpServer() {
60
+ const data = require("./cli-mcp-server.aspect");
61
+ _cliMcpServer = function () {
62
+ return data;
63
+ };
64
+ return data;
65
+ }
66
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
67
+ /* eslint-disable import/extensions */
68
+ /* eslint-disable import/no-unresolved */
69
+
70
+ /** Parse JSON from an MCP tool response, providing a clear error when the server returned a non-JSON error string. */
71
+ function parseToolJson(result) {
72
+ const text = result.content[0].text;
73
+ try {
74
+ return JSON.parse(text);
75
+ } catch {
76
+ throw new Error(`Expected JSON response from MCP tool but got: ${text.slice(0, 200)}`);
77
+ }
78
+ }
79
+ describe.skip('CliMcpServer Integration Tests', function () {
80
+ this.timeout(30000); // Increased timeout for MCP server operations
81
+
82
+ let workspaceData;
83
+ let mcpClient;
84
+ let workspacePath;
85
+ before(async () => {
86
+ // Set up mock workspace with components
87
+ workspaceData = (0, _workspaceTesting().mockWorkspace)();
88
+ workspacePath = workspaceData.workspacePath;
89
+ await (0, _componentTesting().mockComponents)(workspacePath);
90
+ });
91
+ after(async () => {
92
+ await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
93
+ });
94
+ beforeEach(async () => {
95
+ // Create MCP client and connect directly to the MCP server command
96
+ const transport = new (_stdio().StdioClientTransport)({
97
+ command: 'bit',
98
+ args: ['mcp-server', 'start'],
99
+ cwd: workspacePath
100
+ });
101
+ mcpClient = new (_index().Client)({
102
+ name: 'test-client',
103
+ version: '1.0.0'
104
+ }, {
105
+ capabilities: {}
106
+ });
107
+ await mcpClient.connect(transport);
108
+ });
109
+ afterEach(async () => {
110
+ // Clean up MCP client
111
+ if (mcpClient) {
112
+ await mcpClient.close();
113
+ }
114
+ });
115
+ describe('MCP Server Protocol', () => {
116
+ it('should list available tools', async () => {
117
+ const response = await mcpClient.listTools();
118
+ (0, _chai().expect)(response.tools).to.be.an('array');
119
+ (0, _chai().expect)(response.tools.length).to.be.greaterThan(0);
120
+
121
+ // Check for essential MCP tools
122
+ const toolNames = response.tools.map(tool => tool.name);
123
+ (0, _chai().expect)(toolNames).to.include('bit_workspace_info');
124
+ (0, _chai().expect)(toolNames).to.include('bit_component_details');
125
+ (0, _chai().expect)(toolNames).to.include('bit_commands_list');
126
+ (0, _chai().expect)(toolNames).to.include('bit_query');
127
+ (0, _chai().expect)(toolNames).to.include('bit_execute');
128
+ });
129
+ });
130
+ describe('Consumer Project Mode', () => {
131
+ let consumerProjectClient;
132
+ beforeEach(async () => {
133
+ // Create MCP client for consumer project mode
134
+ const transport = new (_stdio().StdioClientTransport)({
135
+ command: 'bit',
136
+ args: ['mcp-server', 'start', '--consumer-project'],
137
+ cwd: workspacePath
138
+ });
139
+ consumerProjectClient = new (_index().Client)({
140
+ name: 'test-consumer-client',
141
+ version: '1.0.0'
142
+ }, {
143
+ capabilities: {}
144
+ });
145
+ await consumerProjectClient.connect(transport);
146
+ });
147
+ afterEach(async () => {
148
+ if (consumerProjectClient) {
149
+ await consumerProjectClient.close();
150
+ }
151
+ });
152
+ it('should only enable bit_remote_search and bit_remote_component_details tools', async () => {
153
+ const response = await consumerProjectClient.listTools();
154
+ (0, _chai().expect)(response.tools).to.be.an('array');
155
+ const toolNames = response.tools.map(tool => tool.name);
156
+
157
+ // Should include only these two tools
158
+ (0, _chai().expect)(toolNames).to.include('bit_remote_search');
159
+ (0, _chai().expect)(toolNames).to.include('bit_remote_component_details');
160
+
161
+ // Should NOT include these tools that are available in regular mode
162
+ (0, _chai().expect)(toolNames).to.not.include('bit_workspace_info');
163
+ (0, _chai().expect)(toolNames).to.not.include('bit_component_details');
164
+ (0, _chai().expect)(toolNames).to.not.include('bit_commands_list');
165
+ (0, _chai().expect)(toolNames).to.not.include('bit_command_help');
166
+ (0, _chai().expect)(toolNames).to.not.include('bit_query');
167
+ (0, _chai().expect)(toolNames).to.not.include('bit_execute');
168
+
169
+ // Should NOT include the old separate tools
170
+ (0, _chai().expect)(toolNames).to.not.include('bit_show');
171
+ (0, _chai().expect)(toolNames).to.not.include('bit_schema');
172
+
173
+ // Should have exactly 2 tools
174
+ (0, _chai().expect)(toolNames).to.have.lengthOf(2);
175
+ });
176
+ it('should work with bit_remote_search tool', async () => {
177
+ const result = await consumerProjectClient.callTool({
178
+ name: 'bit_remote_search',
179
+ arguments: {
180
+ queries: ['button'],
181
+ cwd: workspacePath
182
+ }
183
+ });
184
+ (0, _chai().expect)(result).to.have.property('content');
185
+ (0, _chai().expect)(result.content).to.be.an('array');
186
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
187
+ });
188
+ });
189
+ describe('bit_workspace_info tool', () => {
190
+ it('should get workspace information', async () => {
191
+ const result = await mcpClient.callTool({
192
+ name: 'bit_workspace_info',
193
+ arguments: {
194
+ cwd: workspacePath,
195
+ includeStatus: true,
196
+ includeList: true
197
+ }
198
+ });
199
+ (0, _chai().expect)(result).to.have.property('content');
200
+ (0, _chai().expect)(result.content).to.be.an('array');
201
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
202
+ const content = parseToolJson(result);
203
+ (0, _chai().expect)(content).to.have.property('status');
204
+ (0, _chai().expect)(content).to.have.property('list');
205
+ });
206
+ it('should handle workspace info without optional parameters', async () => {
207
+ const result = await mcpClient.callTool({
208
+ name: 'bit_workspace_info',
209
+ arguments: {
210
+ cwd: workspacePath
211
+ }
212
+ });
213
+ (0, _chai().expect)(result).to.have.property('content');
214
+ (0, _chai().expect)(result.content).to.be.an('array');
215
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
216
+ const content = parseToolJson(result);
217
+ (0, _chai().expect)(content).to.have.property('status');
218
+ });
219
+ });
220
+ describe('bit_component_details tool', () => {
221
+ it('should get component details for multiple components', async () => {
222
+ const componentIds = ['comp1', 'comp2'];
223
+ const result = await mcpClient.callTool({
224
+ name: 'bit_component_details',
225
+ arguments: {
226
+ cwd: workspacePath,
227
+ componentIds,
228
+ includeSchema: false
229
+ }
230
+ });
231
+ (0, _chai().expect)(result).to.have.property('content');
232
+ (0, _chai().expect)(result.content).to.be.an('array');
233
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
234
+ const content = parseToolJson(result);
235
+ (0, _chai().expect)(content).to.have.property('summary');
236
+ (0, _chai().expect)(content).to.have.property('components');
237
+ (0, _chai().expect)(content.summary).to.have.property('requested', 2);
238
+ (0, _chai().expect)(content.summary).to.have.property('successful');
239
+ (0, _chai().expect)(content.components).to.be.an('object');
240
+ });
241
+ it('should get component details with schema', async function () {
242
+ this.retries(2); // schema extraction is heavier and may hit transient socket hang-ups in CI
243
+ const componentIds = ['comp1'];
244
+ const result = await mcpClient.callTool({
245
+ name: 'bit_component_details',
246
+ arguments: {
247
+ cwd: workspacePath,
248
+ componentIds,
249
+ includeSchema: true
250
+ }
251
+ });
252
+ (0, _chai().expect)(result).to.have.property('content');
253
+ (0, _chai().expect)(result.content).to.be.an('array');
254
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
255
+ const content = parseToolJson(result);
256
+ (0, _chai().expect)(content).to.have.property('summary');
257
+ (0, _chai().expect)(content).to.have.property('components');
258
+ (0, _chai().expect)(content.summary.includeSchema).to.be.true;
259
+ if (content.summary.successful > 0) {
260
+ const firstComponent = Object.values(content.components)[0];
261
+ (0, _chai().expect)(firstComponent).to.have.property('publicAPI');
262
+ }
263
+ });
264
+ it('should handle non-existent component gracefully', async () => {
265
+ const result = await mcpClient.callTool({
266
+ name: 'bit_component_details',
267
+ arguments: {
268
+ cwd: workspacePath,
269
+ componentIds: ['non-existent/component']
270
+ }
271
+ });
272
+ (0, _chai().expect)(result).to.have.property('content');
273
+ (0, _chai().expect)(result.content).to.be.an('array');
274
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
275
+ const responseText = result.content[0].text;
276
+
277
+ // Try to parse as JSON first
278
+ try {
279
+ const content = JSON.parse(responseText);
280
+ // Should have summary with failed components
281
+ (0, _chai().expect)(content).to.have.property('summary');
282
+ (0, _chai().expect)(content.summary).to.have.property('failed');
283
+ (0, _chai().expect)(content.summary.failed).to.be.greaterThan(0);
284
+ } catch {
285
+ // If not JSON, should be an error message string
286
+ (0, _chai().expect)(responseText).to.be.a('string');
287
+ (0, _chai().expect)(responseText).to.include('Failed to get details for any components');
288
+ }
289
+ });
290
+ it('should reject requests with more than 5 components', async () => {
291
+ const tooManyComponents = ['comp1', 'comp2', 'comp3', 'comp4', 'comp5', 'comp6'];
292
+ const result = await mcpClient.callTool({
293
+ name: 'bit_component_details',
294
+ arguments: {
295
+ cwd: workspacePath,
296
+ componentIds: tooManyComponents
297
+ }
298
+ });
299
+ (0, _chai().expect)(result).to.have.property('content');
300
+ (0, _chai().expect)(result.content).to.be.an('array');
301
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
302
+ const content = result.content[0].text;
303
+ (0, _chai().expect)(content).to.include('Too many components requested');
304
+ (0, _chai().expect)(content).to.include('Maximum allowed is 5');
305
+ });
306
+ it('should require componentIds parameter', async () => {
307
+ const result = await mcpClient.callTool({
308
+ name: 'bit_component_details',
309
+ arguments: {
310
+ cwd: workspacePath
311
+ // Missing componentIds parameter
312
+ }
313
+ });
314
+
315
+ // With new SDK (1.22+), validation errors are returned in result with isError flag
316
+ (0, _chai().expect)(result).to.have.property('isError', true);
317
+ (0, _chai().expect)(result.content).to.be.an('array');
318
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
319
+ const errorText = result.content[0].text;
320
+ (0, _chai().expect)(errorText).to.include('componentIds');
321
+ (0, _chai().expect)(errorText).to.include('Required');
322
+ });
323
+ });
324
+ describe('bit_commands_list tool', () => {
325
+ it('should get basic commands list', async () => {
326
+ const result = await mcpClient.callTool({
327
+ name: 'bit_commands_list',
328
+ arguments: {}
329
+ });
330
+ (0, _chai().expect)(result).to.have.property('content');
331
+ (0, _chai().expect)(result.content).to.be.an('array');
332
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
333
+ const content = parseToolJson(result);
334
+ (0, _chai().expect)(content).to.have.property('commands');
335
+ (0, _chai().expect)(content.commands).to.be.an('array');
336
+ (0, _chai().expect)(content.commands.length).to.be.greaterThan(0);
337
+
338
+ // Check command structure
339
+ const firstCommand = content.commands[0];
340
+ (0, _chai().expect)(firstCommand).to.have.property('name');
341
+ (0, _chai().expect)(firstCommand).to.have.property('description');
342
+ });
343
+ it('should get commands info with extended description', async () => {
344
+ const result = await mcpClient.callTool({
345
+ name: 'bit_commands_list',
346
+ arguments: {
347
+ extendedDescription: true,
348
+ internal: false
349
+ }
350
+ });
351
+ (0, _chai().expect)(result).to.have.property('content');
352
+ (0, _chai().expect)(result.content).to.be.an('array');
353
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
354
+ const content = parseToolJson(result);
355
+ (0, _chai().expect)(content).to.have.property('commands');
356
+ (0, _chai().expect)(content.commands).to.be.an('array');
357
+ (0, _chai().expect)(content.commands.length).to.be.greaterThan(0);
358
+ });
359
+ });
360
+ describe('bit_command_help tool', () => {
361
+ it('should get help for a main command', async () => {
362
+ const result = await mcpClient.callTool({
363
+ name: 'bit_command_help',
364
+ arguments: {
365
+ command: 'status'
366
+ }
367
+ });
368
+ (0, _chai().expect)(result).to.have.property('content');
369
+ (0, _chai().expect)(result.content).to.be.an('array');
370
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
371
+ const content = parseToolJson(result);
372
+ (0, _chai().expect)(content).to.have.property('name', 'status');
373
+ (0, _chai().expect)(content).to.have.property('description');
374
+ (0, _chai().expect)(content).to.have.property('options');
375
+ });
376
+ it('should get help for lane switch subcommand (private command)', async () => {
377
+ const result = await mcpClient.callTool({
378
+ name: 'bit_command_help',
379
+ arguments: {
380
+ command: 'lane',
381
+ subcommand: 'switch'
382
+ }
383
+ });
384
+ (0, _chai().expect)(result).to.have.property('content');
385
+ (0, _chai().expect)(result.content).to.be.an('array');
386
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
387
+ const content = parseToolJson(result);
388
+ (0, _chai().expect)(content).to.have.property('name', 'lane switch');
389
+ (0, _chai().expect)(content).to.have.property('description');
390
+ (0, _chai().expect)(content.description).to.include('switch to the specified lane');
391
+ (0, _chai().expect)(content).to.have.property('arguments');
392
+ (0, _chai().expect)(content.arguments).to.be.an('array');
393
+ (0, _chai().expect)(content.arguments[0]).to.have.property('name', 'lane');
394
+ (0, _chai().expect)(content.arguments[0]).to.have.property('description');
395
+ });
396
+ it('should get help for a subcommand that exists', async () => {
397
+ const result = await mcpClient.callTool({
398
+ name: 'bit_command_help',
399
+ arguments: {
400
+ command: 'lane',
401
+ subcommand: 'show'
402
+ }
403
+ });
404
+ (0, _chai().expect)(result).to.have.property('content');
405
+ (0, _chai().expect)(result.content).to.be.an('array');
406
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
407
+ const content = parseToolJson(result);
408
+ (0, _chai().expect)(content).to.have.property('name', 'lane show');
409
+ (0, _chai().expect)(content).to.have.property('description');
410
+ });
411
+ it('should return error for non-existent command', async () => {
412
+ const result = await mcpClient.callTool({
413
+ name: 'bit_command_help',
414
+ arguments: {
415
+ command: 'nonexistent'
416
+ }
417
+ });
418
+ (0, _chai().expect)(result).to.have.property('content');
419
+ (0, _chai().expect)(result.content).to.be.an('array');
420
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
421
+ const content = result.content[0].text;
422
+ (0, _chai().expect)(content).to.include('Command not found: nonexistent');
423
+ });
424
+ it('should return error for non-existent subcommand', async () => {
425
+ const result = await mcpClient.callTool({
426
+ name: 'bit_command_help',
427
+ arguments: {
428
+ command: 'lane',
429
+ subcommand: 'nonexistent'
430
+ }
431
+ });
432
+ (0, _chai().expect)(result).to.have.property('content');
433
+ (0, _chai().expect)(result.content).to.be.an('array');
434
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
435
+ const content = result.content[0].text;
436
+ (0, _chai().expect)(content).to.include('Command not found: lane nonexistent');
437
+ });
438
+ });
439
+ describe('bit_query tool', () => {
440
+ it('should execute read-only commands', async () => {
441
+ const result = await mcpClient.callTool({
442
+ name: 'bit_query',
443
+ arguments: {
444
+ cwd: workspacePath,
445
+ command: 'status'
446
+ }
447
+ });
448
+ (0, _chai().expect)(result).to.have.property('content');
449
+ (0, _chai().expect)(result.content).to.be.an('array');
450
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
451
+
452
+ // Should return command output
453
+ const content = result.content[0].text;
454
+ (0, _chai().expect)(content).to.be.a('string');
455
+ });
456
+ it('should handle commands with arguments and flags', async () => {
457
+ const result = await mcpClient.callTool({
458
+ name: 'bit_query',
459
+ arguments: {
460
+ cwd: workspacePath,
461
+ command: 'list',
462
+ args: [],
463
+ flags: {
464
+ json: true
465
+ }
466
+ }
467
+ });
468
+ (0, _chai().expect)(result).to.have.property('content');
469
+ (0, _chai().expect)(result.content).to.be.an('array');
470
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
471
+ const content = result.content[0].text;
472
+ (0, _chai().expect)(content).to.be.a('string');
473
+ });
474
+ });
475
+ describe('Error Handling', () => {
476
+ it('should handle invalid tool calls gracefully', async () => {
477
+ try {
478
+ await mcpClient.callTool({
479
+ name: 'non_existent_tool',
480
+ arguments: {}
481
+ });
482
+ _chai().expect.fail('Should have thrown an error for non-existent tool');
483
+ } catch (error) {
484
+ (0, _chai().expect)(error).to.exist;
485
+ }
486
+ });
487
+ it('should handle invalid workspace directory', async () => {
488
+ const result = await mcpClient.callTool({
489
+ name: 'bit_workspace_info',
490
+ arguments: {
491
+ cwd: '/non/existent/path'
492
+ }
493
+ });
494
+ (0, _chai().expect)(result).to.have.property('content');
495
+ (0, _chai().expect)(result.content).to.be.an('array');
496
+ (0, _chai().expect)(result.content[0]).to.have.property('type', 'text');
497
+
498
+ // Should return error information
499
+ const content = result.content[0].text;
500
+ (0, _chai().expect)(content).to.be.a('string');
501
+ });
502
+ });
503
+ });
504
+ describe.skip('CliMcpServer Direct Aspect Tests', function () {
505
+ this.timeout(30000);
506
+ let workspaceData;
507
+ let mcpServer;
508
+ let workspacePath;
509
+ before(async () => {
510
+ // Set up mock workspace with components
511
+ workspaceData = (0, _workspaceTesting().mockWorkspace)();
512
+ workspacePath = workspaceData.workspacePath;
513
+ await (0, _componentTesting().mockComponents)(workspacePath);
514
+
515
+ // Load the aspect directly
516
+ mcpServer = await (0, _harmonyTesting().loadAspect)(_cliMcpServer().CliMcpServerAspect, workspacePath);
517
+ });
518
+ after(async () => {
519
+ await (0, _workspaceTesting().destroyWorkspace)(workspaceData);
520
+ });
521
+ describe('Setup Editor Methods', () => {
522
+ let setupWorkspaceData;
523
+ let setupWorkspacePath;
524
+ let setupMcpServer;
525
+ beforeEach(async () => {
526
+ // Create a separate mock workspace for setup testing
527
+ setupWorkspaceData = (0, _workspaceTesting().mockWorkspace)();
528
+ setupWorkspacePath = setupWorkspaceData.workspacePath;
529
+ await (0, _componentTesting().mockComponents)(setupWorkspacePath);
530
+
531
+ // Load the aspect for this workspace
532
+ setupMcpServer = await (0, _harmonyTesting().loadAspect)(_cliMcpServer().CliMcpServerAspect, setupWorkspacePath);
533
+ });
534
+ afterEach(async () => {
535
+ // Clean up the setup workspace
536
+ if (setupWorkspaceData) {
537
+ await (0, _workspaceTesting().destroyWorkspace)(setupWorkspaceData);
538
+ }
539
+ });
540
+ it('should handle unsupported editor gracefully', async () => {
541
+ try {
542
+ await mcpServer.setupEditor('unsupported-editor', {
543
+ isGlobal: false
544
+ });
545
+ _chai().expect.fail('Should have thrown an error for unsupported editor');
546
+ } catch (error) {
547
+ (0, _chai().expect)(error).to.exist;
548
+ (0, _chai().expect)(error.message).to.include('Editor "unsupported-editor" is not supported yet');
549
+ (0, _chai().expect)(error.message).to.include('Currently supported: vscode, cursor, windsurf, roo, cline');
550
+ }
551
+ });
552
+ it('should setup VS Code integration directly', async () => {
553
+ await setupMcpServer.setupEditor('vscode', {
554
+ isGlobal: false
555
+ }, setupWorkspacePath);
556
+
557
+ // Verify that the mcp.json file was created in the workspace directory
558
+ const vscodeMcpPath = _path().default.join(setupWorkspacePath, '.vscode', 'mcp.json');
559
+ const mcpExists = await _fsExtra().default.pathExists(vscodeMcpPath);
560
+ (0, _chai().expect)(mcpExists).to.be.true;
561
+
562
+ // Verify the content of the mcp.json file
563
+ const mcpConfig = await _fsExtra().default.readJson(vscodeMcpPath);
564
+ (0, _chai().expect)(mcpConfig).to.have.property('servers');
565
+ (0, _chai().expect)(mcpConfig.servers).to.have.property('bit-cli');
566
+ (0, _chai().expect)(mcpConfig.servers['bit-cli']).to.deep.equal({
567
+ type: 'stdio',
568
+ command: 'bit',
569
+ args: ['mcp-server', 'start']
570
+ });
571
+ });
572
+ it('should setup VS Code integration with consumer project options', async () => {
573
+ await setupMcpServer.setupEditor('vscode', {
574
+ consumerProject: true,
575
+ includeAdditional: 'status,list',
576
+ isGlobal: false
577
+ }, setupWorkspacePath);
578
+ const vscodeMcpPath = _path().default.join(setupWorkspacePath, '.vscode', 'mcp.json');
579
+ const mcpConfig = await _fsExtra().default.readJson(vscodeMcpPath);
580
+ (0, _chai().expect)(mcpConfig.servers['bit-cli'].args).to.include('--consumer-project');
581
+ (0, _chai().expect)(mcpConfig.servers['bit-cli'].args).to.include('--include-additional');
582
+ (0, _chai().expect)(mcpConfig.servers['bit-cli'].args).to.include('status,list');
583
+ });
584
+ it('should setup Cursor integration directly', async () => {
585
+ await setupMcpServer.setupEditor('cursor', {
586
+ isGlobal: false
587
+ }, setupWorkspacePath);
588
+
589
+ // Verify that the mcp.json file was created in the workspace directory
590
+ const cursorConfigPath = _path().default.join(setupWorkspacePath, '.cursor', 'mcp.json');
591
+ const configExists = await _fsExtra().default.pathExists(cursorConfigPath);
592
+ (0, _chai().expect)(configExists).to.be.true;
593
+
594
+ // Verify the content of the config file
595
+ const config = await _fsExtra().default.readJson(cursorConfigPath);
596
+ (0, _chai().expect)(config).to.have.property('mcpServers');
597
+ (0, _chai().expect)(config.mcpServers).to.have.property('bit');
598
+ (0, _chai().expect)(config.mcpServers.bit).to.deep.equal({
599
+ type: 'stdio',
600
+ command: 'bit',
601
+ args: ['mcp-server', 'start']
602
+ });
603
+ });
604
+ it('should setup Windsurf integration directly', async () => {
605
+ await setupMcpServer.setupEditor('windsurf', {
606
+ isGlobal: false
607
+ }, setupWorkspacePath);
608
+
609
+ // Verify that the mcp.json file was created in the workspace directory
610
+ const windsurfConfigPath = _path().default.join(setupWorkspacePath, '.windsurf', 'mcp.json');
611
+ const configExists = await _fsExtra().default.pathExists(windsurfConfigPath);
612
+ (0, _chai().expect)(configExists).to.be.true;
613
+
614
+ // Verify the content of the config file
615
+ const config = await _fsExtra().default.readJson(windsurfConfigPath);
616
+ (0, _chai().expect)(config).to.have.property('mcpServers');
617
+ (0, _chai().expect)(config.mcpServers).to.have.property('bit');
618
+ (0, _chai().expect)(config.mcpServers.bit).to.deep.equal({
619
+ type: 'stdio',
620
+ command: 'bit',
621
+ args: ['mcp-server', 'start']
622
+ });
623
+ });
624
+ it('should setup Roo Code integration directly', async () => {
625
+ await setupMcpServer.setupEditor('roo', {
626
+ isGlobal: false
627
+ }, setupWorkspacePath);
628
+
629
+ // Verify that the mcp.json file was created in the workspace directory
630
+ const rooConfigPath = _path().default.join(setupWorkspacePath, '.roo', 'mcp.json');
631
+ const configExists = await _fsExtra().default.pathExists(rooConfigPath);
632
+ (0, _chai().expect)(configExists).to.be.true;
633
+
634
+ // Verify the content of the config file
635
+ const config = await _fsExtra().default.readJson(rooConfigPath);
636
+ (0, _chai().expect)(config).to.have.property('mcpServers');
637
+ (0, _chai().expect)(config.mcpServers).to.have.property('bit');
638
+ (0, _chai().expect)(config.mcpServers.bit).to.deep.equal({
639
+ type: 'stdio',
640
+ command: 'bit',
641
+ args: ['mcp-server', 'start']
642
+ });
643
+ });
644
+ it('should throw error when trying to setup Roo Code globally', async () => {
645
+ try {
646
+ await setupMcpServer.setupEditor('roo', {
647
+ isGlobal: true
648
+ }, setupWorkspacePath);
649
+ _chai().expect.fail('Should have thrown an error for global Roo Code setup');
650
+ } catch (error) {
651
+ (0, _chai().expect)(error).to.exist;
652
+ (0, _chai().expect)(error.message).to.include('Roo Code global configuration is not supported');
653
+ (0, _chai().expect)(error.message).to.include('VS Code internal storage that cannot be accessed');
654
+ }
655
+ });
656
+ it('should merge with existing VS Code mcp.json config', async () => {
657
+ // First, create existing MCP config
658
+ const vscodeMcpPath = _path().default.join(setupWorkspacePath, '.vscode', 'mcp.json');
659
+ await _fsExtra().default.ensureDir(_path().default.dirname(vscodeMcpPath));
660
+ await _fsExtra().default.writeJson(vscodeMcpPath, {
661
+ servers: {
662
+ 'existing-server': {
663
+ type: 'stdio',
664
+ command: 'some-other-command',
665
+ args: ['start']
666
+ }
667
+ }
668
+ });
669
+
670
+ // Run setup
671
+ await setupMcpServer.setupEditor('vscode', {
672
+ isGlobal: false
673
+ }, setupWorkspacePath);
674
+
675
+ // Verify that existing MCP config is preserved and Bit config is added
676
+ const mcpConfig = await _fsExtra().default.readJson(vscodeMcpPath);
677
+ (0, _chai().expect)(mcpConfig.servers).to.have.property('existing-server');
678
+ (0, _chai().expect)(mcpConfig.servers['existing-server']).to.deep.equal({
679
+ type: 'stdio',
680
+ command: 'some-other-command',
681
+ args: ['start']
682
+ });
683
+ (0, _chai().expect)(mcpConfig.servers).to.have.property('bit-cli');
684
+ (0, _chai().expect)(mcpConfig.servers['bit-cli']).to.deep.equal({
685
+ type: 'stdio',
686
+ command: 'bit',
687
+ args: ['mcp-server', 'start']
688
+ });
689
+ });
690
+ });
691
+ describe('Rules Methods', () => {
692
+ it('should get rules content without error', async () => {
693
+ // This test reproduces the bug where bit-rules-template.md was not found
694
+ const rulesContent = await mcpServer.getRulesContent(false);
695
+ (0, _chai().expect)(rulesContent).to.be.a('string');
696
+ (0, _chai().expect)(rulesContent).to.contain('# Bit MCP Agent Instructions');
697
+ (0, _chai().expect)(rulesContent).to.contain('Core Objectives');
698
+ });
699
+ it('should get consumer project rules content without error', async () => {
700
+ const rulesContent = await mcpServer.getRulesContent(true);
701
+ (0, _chai().expect)(rulesContent).to.be.a('string');
702
+ (0, _chai().expect)(rulesContent).to.contain('## How to Install and Use Bit Components');
703
+ (0, _chai().expect)(rulesContent).to.contain('Bit Components are reusable pieces of code');
704
+ });
705
+ it('should write rules file for VS Code without error', async () => {
706
+ await mcpServer.writeRulesFile('vscode', {
707
+ isGlobal: false,
708
+ consumerProject: false
709
+ }, workspacePath);
710
+
711
+ // Check that the rules file was created
712
+ const rulesPath = _path().default.join(workspacePath, '.github', 'instructions', 'bit.instructions.md');
713
+ const rulesExists = await _fsExtra().default.pathExists(rulesPath);
714
+ (0, _chai().expect)(rulesExists).to.be.true;
715
+
716
+ // Check content
717
+ const rulesContent = await _fsExtra().default.readFile(rulesPath, 'utf8');
718
+ (0, _chai().expect)(rulesContent).to.contain('# Bit MCP Agent Instructions');
719
+ (0, _chai().expect)(rulesContent).to.contain('Core Objectives');
720
+ });
721
+ it('should write consumer project rules file without error', async () => {
722
+ await mcpServer.writeRulesFile('vscode', {
723
+ isGlobal: false,
724
+ consumerProject: true
725
+ }, workspacePath);
726
+
727
+ // Check that the rules file was created
728
+ const rulesPath = _path().default.join(workspacePath, '.github', 'instructions', 'bit.instructions.md');
729
+ const rulesExists = await _fsExtra().default.pathExists(rulesPath);
730
+ (0, _chai().expect)(rulesExists).to.be.true;
731
+
732
+ // Check content is different for consumer project
733
+ const rulesContent = await _fsExtra().default.readFile(rulesPath, 'utf8');
734
+ (0, _chai().expect)(rulesContent).to.contain('## How to Install and Use Bit Components');
735
+ (0, _chai().expect)(rulesContent).to.contain('Bit Components are reusable pieces of code');
736
+ });
737
+ });
738
+ });
739
+
740
+ //# sourceMappingURL=cli-mcp-server.spec.js.map