@172ai/containers-mcp-server 1.0.0

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 (43) hide show
  1. package/.env.example +43 -0
  2. package/README.md +366 -0
  3. package/dist/auth.d.ts +57 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +192 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/config.d.ts +84 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +246 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/server.d.ts +63 -0
  12. package/dist/server.d.ts.map +1 -0
  13. package/dist/server.js +886 -0
  14. package/dist/server.js.map +1 -0
  15. package/dist/services/buildService.d.ts +51 -0
  16. package/dist/services/buildService.d.ts.map +1 -0
  17. package/dist/services/buildService.js +268 -0
  18. package/dist/services/buildService.js.map +1 -0
  19. package/dist/services/capabilityService.d.ts +62 -0
  20. package/dist/services/capabilityService.d.ts.map +1 -0
  21. package/dist/services/capabilityService.js +240 -0
  22. package/dist/services/capabilityService.js.map +1 -0
  23. package/dist/services/containerService.d.ts +52 -0
  24. package/dist/services/containerService.d.ts.map +1 -0
  25. package/dist/services/containerService.js +251 -0
  26. package/dist/services/containerService.js.map +1 -0
  27. package/dist/services/fileService.d.ts +65 -0
  28. package/dist/services/fileService.d.ts.map +1 -0
  29. package/dist/services/fileService.js +330 -0
  30. package/dist/services/fileService.js.map +1 -0
  31. package/dist/setup.d.ts +30 -0
  32. package/dist/setup.d.ts.map +1 -0
  33. package/dist/setup.js +328 -0
  34. package/dist/setup.js.map +1 -0
  35. package/dist/types.d.ts +229 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +4 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/utils/errorHandler.d.ts +78 -0
  40. package/dist/utils/errorHandler.d.ts.map +1 -0
  41. package/dist/utils/errorHandler.js +269 -0
  42. package/dist/utils/errorHandler.js.map +1 -0
  43. package/package.json +81 -0
package/dist/server.js ADDED
@@ -0,0 +1,886 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.ContainerMCPServer = void 0;
5
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
6
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
7
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
8
+ // Import our services and utilities
9
+ const config_js_1 = require("./config.js");
10
+ const auth_js_1 = require("./auth.js");
11
+ const containerService_js_1 = require("./services/containerService.js");
12
+ const buildService_js_1 = require("./services/buildService.js");
13
+ const fileService_js_1 = require("./services/fileService.js");
14
+ const capabilityService_js_1 = require("./services/capabilityService.js");
15
+ const errorHandler_js_1 = require("./utils/errorHandler.js");
16
+ /**
17
+ * 172.ai Container Management MCP Server
18
+ *
19
+ * Provides AI assistants with access to container management functionality
20
+ * through the Model Context Protocol (MCP).
21
+ */
22
+ class ContainerMCPServer {
23
+ constructor() {
24
+ this.server = new index_js_1.Server({
25
+ name: '172ai-containers-mcp-server',
26
+ version: '1.0.0',
27
+ });
28
+ this.setupTools();
29
+ this.setupErrorHandlers();
30
+ }
31
+ /**
32
+ * Set up all available tools
33
+ */
34
+ setupTools() {
35
+ // Container Management Tools
36
+ this.setupContainerTools();
37
+ // Build Management Tools
38
+ this.setupBuildTools();
39
+ // File Management Tools
40
+ this.setupFileTools();
41
+ // Capability Management Tools
42
+ this.setupCapabilityTools();
43
+ }
44
+ /**
45
+ * Set up container management tools
46
+ */
47
+ setupContainerTools() {
48
+ // List containers
49
+ this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
50
+ return {
51
+ tools: this.getAllTools(),
52
+ };
53
+ });
54
+ this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
55
+ const { name, arguments: args } = request.params;
56
+ try {
57
+ switch (name) {
58
+ case 'list_containers':
59
+ return await this.handleListContainers(args);
60
+ case 'get_container':
61
+ return await this.handleGetContainer(args);
62
+ case 'create_container':
63
+ return await this.handleCreateContainer(args);
64
+ case 'update_container':
65
+ return await this.handleUpdateContainer(args);
66
+ case 'delete_container':
67
+ return await this.handleDeleteContainer(args);
68
+ case 'copy_container':
69
+ return await this.handleCopyContainer(args);
70
+ case 'build_container':
71
+ return await this.handleBuildContainer(args);
72
+ case 'get_build_status':
73
+ return await this.handleGetBuildStatus(args);
74
+ case 'list_builds':
75
+ return await this.handleListBuilds(args);
76
+ case 'get_build_logs':
77
+ return await this.handleGetBuildLogs(args);
78
+ case 'list_container_files':
79
+ return await this.handleListContainerFiles(args);
80
+ case 'get_file_content':
81
+ return await this.handleGetFileContent(args);
82
+ case 'upload_file':
83
+ return await this.handleUploadFile(args);
84
+ case 'update_file':
85
+ return await this.handleUpdateFile(args);
86
+ case 'delete_file':
87
+ return await this.handleDeleteFile(args);
88
+ case 'list_capabilities':
89
+ return await this.handleListCapabilities(args);
90
+ case 'get_capability':
91
+ return await this.handleGetCapability(args);
92
+ case 'search_capabilities':
93
+ return await this.handleSearchCapabilities(args);
94
+ default:
95
+ throw errorHandler_js_1.ErrorHandler.createValidationError(`Unknown tool: ${name}`);
96
+ }
97
+ }
98
+ catch (error) {
99
+ const processedError = errorHandler_js_1.ErrorHandler.processError(error, `Tool: ${name}`);
100
+ errorHandler_js_1.ErrorHandler.logError(processedError);
101
+ return {
102
+ content: [
103
+ {
104
+ type: 'text',
105
+ text: `Error: ${processedError.message}`,
106
+ },
107
+ ],
108
+ isError: true,
109
+ };
110
+ }
111
+ });
112
+ }
113
+ /**
114
+ * Get all available tools
115
+ */
116
+ getAllTools() {
117
+ return [
118
+ // Container Management Tools
119
+ {
120
+ name: 'list_containers',
121
+ description: 'List available containers with optional filtering',
122
+ inputSchema: {
123
+ type: 'object',
124
+ properties: {
125
+ scope: {
126
+ type: 'string',
127
+ enum: ['public', 'myCollection', 'all'],
128
+ description: 'Filter containers by scope'
129
+ },
130
+ limit: {
131
+ type: 'number',
132
+ minimum: 1,
133
+ maximum: 100,
134
+ description: 'Maximum number of containers to return'
135
+ },
136
+ offset: {
137
+ type: 'number',
138
+ minimum: 0,
139
+ description: 'Number of containers to skip'
140
+ },
141
+ query: {
142
+ type: 'string',
143
+ description: 'Search query to filter containers'
144
+ }
145
+ }
146
+ }
147
+ },
148
+ {
149
+ name: 'get_container',
150
+ description: 'Get detailed information about a specific container',
151
+ inputSchema: {
152
+ type: 'object',
153
+ properties: {
154
+ containerId: {
155
+ type: 'string',
156
+ description: 'ID of the container to retrieve'
157
+ }
158
+ },
159
+ required: ['containerId']
160
+ }
161
+ },
162
+ {
163
+ name: 'create_container',
164
+ description: 'Create a new container template',
165
+ inputSchema: {
166
+ type: 'object',
167
+ properties: {
168
+ name: {
169
+ type: 'string',
170
+ description: 'Name of the container'
171
+ },
172
+ description: {
173
+ type: 'string',
174
+ description: 'Description of the container'
175
+ },
176
+ dockerfile: {
177
+ type: 'string',
178
+ description: 'Dockerfile content'
179
+ },
180
+ tags: {
181
+ type: 'array',
182
+ items: { type: 'string' },
183
+ description: 'Tags for the container'
184
+ },
185
+ isPrivate: {
186
+ type: 'boolean',
187
+ description: 'Whether the container is private'
188
+ },
189
+ envVars: {
190
+ type: 'object',
191
+ additionalProperties: { type: 'string' },
192
+ description: 'Environment variables'
193
+ }
194
+ },
195
+ required: ['name', 'description', 'dockerfile']
196
+ }
197
+ },
198
+ {
199
+ name: 'update_container',
200
+ description: 'Update an existing container configuration',
201
+ inputSchema: {
202
+ type: 'object',
203
+ properties: {
204
+ containerId: {
205
+ type: 'string',
206
+ description: 'ID of the container to update'
207
+ },
208
+ name: {
209
+ type: 'string',
210
+ description: 'New name for the container'
211
+ },
212
+ description: {
213
+ type: 'string',
214
+ description: 'New description for the container'
215
+ },
216
+ dockerfile: {
217
+ type: 'string',
218
+ description: 'New Dockerfile content'
219
+ },
220
+ tags: {
221
+ type: 'array',
222
+ items: { type: 'string' },
223
+ description: 'New tags for the container'
224
+ },
225
+ isPrivate: {
226
+ type: 'boolean',
227
+ description: 'Whether the container should be private'
228
+ },
229
+ envVars: {
230
+ type: 'object',
231
+ additionalProperties: { type: 'string' },
232
+ description: 'New environment variables'
233
+ }
234
+ },
235
+ required: ['containerId']
236
+ }
237
+ },
238
+ {
239
+ name: 'delete_container',
240
+ description: 'Delete a container',
241
+ inputSchema: {
242
+ type: 'object',
243
+ properties: {
244
+ containerId: {
245
+ type: 'string',
246
+ description: 'ID of the container to delete'
247
+ }
248
+ },
249
+ required: ['containerId']
250
+ }
251
+ },
252
+ {
253
+ name: 'copy_container',
254
+ description: 'Create a copy of an existing container',
255
+ inputSchema: {
256
+ type: 'object',
257
+ properties: {
258
+ containerId: {
259
+ type: 'string',
260
+ description: 'ID of the container to copy'
261
+ },
262
+ newName: {
263
+ type: 'string',
264
+ description: 'Name for the new container'
265
+ }
266
+ },
267
+ required: ['containerId', 'newName']
268
+ }
269
+ },
270
+ // Build Management Tools
271
+ {
272
+ name: 'build_container',
273
+ description: 'Start building a container',
274
+ inputSchema: {
275
+ type: 'object',
276
+ properties: {
277
+ containerId: {
278
+ type: 'string',
279
+ description: 'ID of the container to build'
280
+ },
281
+ buildArgs: {
282
+ type: 'object',
283
+ additionalProperties: { type: 'string' },
284
+ description: 'Build arguments'
285
+ },
286
+ target: {
287
+ type: 'string',
288
+ description: 'Build target stage'
289
+ }
290
+ },
291
+ required: ['containerId']
292
+ }
293
+ },
294
+ {
295
+ name: 'get_build_status',
296
+ description: 'Get the status of a container build',
297
+ inputSchema: {
298
+ type: 'object',
299
+ properties: {
300
+ containerId: {
301
+ type: 'string',
302
+ description: 'ID of the container'
303
+ },
304
+ buildId: {
305
+ type: 'string',
306
+ description: 'ID of the specific build (optional, gets latest if not provided)'
307
+ }
308
+ },
309
+ required: ['containerId']
310
+ }
311
+ },
312
+ {
313
+ name: 'list_builds',
314
+ description: 'List builds for a container or all builds',
315
+ inputSchema: {
316
+ type: 'object',
317
+ properties: {
318
+ containerId: {
319
+ type: 'string',
320
+ description: 'ID of the container (optional, lists all builds if not provided)'
321
+ },
322
+ status: {
323
+ type: 'string',
324
+ enum: ['pending', 'running', 'completed', 'failed', 'cancelled'],
325
+ description: 'Filter by build status'
326
+ },
327
+ limit: {
328
+ type: 'number',
329
+ minimum: 1,
330
+ maximum: 100,
331
+ description: 'Maximum number of builds to return'
332
+ },
333
+ offset: {
334
+ type: 'number',
335
+ minimum: 0,
336
+ description: 'Number of builds to skip'
337
+ }
338
+ }
339
+ }
340
+ },
341
+ {
342
+ name: 'get_build_logs',
343
+ description: 'Get build logs for a container',
344
+ inputSchema: {
345
+ type: 'object',
346
+ properties: {
347
+ containerId: {
348
+ type: 'string',
349
+ description: 'ID of the container'
350
+ },
351
+ buildId: {
352
+ type: 'string',
353
+ description: 'ID of the specific build (optional, gets latest if not provided)'
354
+ }
355
+ },
356
+ required: ['containerId']
357
+ }
358
+ },
359
+ // File Management Tools
360
+ {
361
+ name: 'list_container_files',
362
+ description: 'List files in a container',
363
+ inputSchema: {
364
+ type: 'object',
365
+ properties: {
366
+ containerId: {
367
+ type: 'string',
368
+ description: 'ID of the container'
369
+ },
370
+ path: {
371
+ type: 'string',
372
+ description: 'Path within the container (optional, defaults to root)'
373
+ }
374
+ },
375
+ required: ['containerId']
376
+ }
377
+ },
378
+ {
379
+ name: 'get_file_content',
380
+ description: 'Get the content of a file in a container',
381
+ inputSchema: {
382
+ type: 'object',
383
+ properties: {
384
+ containerId: {
385
+ type: 'string',
386
+ description: 'ID of the container'
387
+ },
388
+ filePath: {
389
+ type: 'string',
390
+ description: 'Path to the file within the container'
391
+ }
392
+ },
393
+ required: ['containerId', 'filePath']
394
+ }
395
+ },
396
+ {
397
+ name: 'upload_file',
398
+ description: 'Upload a file to a container',
399
+ inputSchema: {
400
+ type: 'object',
401
+ properties: {
402
+ containerId: {
403
+ type: 'string',
404
+ description: 'ID of the container'
405
+ },
406
+ filePath: {
407
+ type: 'string',
408
+ description: 'Path where the file should be uploaded'
409
+ },
410
+ content: {
411
+ type: 'string',
412
+ description: 'Content of the file'
413
+ },
414
+ mimeType: {
415
+ type: 'string',
416
+ description: 'MIME type of the file'
417
+ },
418
+ encoding: {
419
+ type: 'string',
420
+ enum: ['utf8', 'base64'],
421
+ description: 'Encoding of the content'
422
+ }
423
+ },
424
+ required: ['containerId', 'filePath', 'content']
425
+ }
426
+ },
427
+ {
428
+ name: 'update_file',
429
+ description: 'Update the content of an existing file in a container',
430
+ inputSchema: {
431
+ type: 'object',
432
+ properties: {
433
+ containerId: {
434
+ type: 'string',
435
+ description: 'ID of the container'
436
+ },
437
+ filePath: {
438
+ type: 'string',
439
+ description: 'Path to the file within the container'
440
+ },
441
+ content: {
442
+ type: 'string',
443
+ description: 'New content of the file'
444
+ },
445
+ mimeType: {
446
+ type: 'string',
447
+ description: 'MIME type of the file'
448
+ },
449
+ encoding: {
450
+ type: 'string',
451
+ enum: ['utf8', 'base64'],
452
+ description: 'Encoding of the content'
453
+ }
454
+ },
455
+ required: ['containerId', 'filePath', 'content']
456
+ }
457
+ },
458
+ {
459
+ name: 'delete_file',
460
+ description: 'Delete a file from a container',
461
+ inputSchema: {
462
+ type: 'object',
463
+ properties: {
464
+ containerId: {
465
+ type: 'string',
466
+ description: 'ID of the container'
467
+ },
468
+ filePath: {
469
+ type: 'string',
470
+ description: 'Path to the file within the container'
471
+ }
472
+ },
473
+ required: ['containerId', 'filePath']
474
+ }
475
+ },
476
+ // Capability Management Tools
477
+ {
478
+ name: 'list_capabilities',
479
+ description: 'List available capabilities',
480
+ inputSchema: {
481
+ type: 'object',
482
+ properties: {
483
+ category: {
484
+ type: 'string',
485
+ description: 'Filter capabilities by category'
486
+ },
487
+ limit: {
488
+ type: 'number',
489
+ minimum: 1,
490
+ maximum: 100,
491
+ description: 'Maximum number of capabilities to return'
492
+ },
493
+ offset: {
494
+ type: 'number',
495
+ minimum: 0,
496
+ description: 'Number of capabilities to skip'
497
+ },
498
+ query: {
499
+ type: 'string',
500
+ description: 'Search query to filter capabilities'
501
+ }
502
+ }
503
+ }
504
+ },
505
+ {
506
+ name: 'get_capability',
507
+ description: 'Get detailed information about a specific capability',
508
+ inputSchema: {
509
+ type: 'object',
510
+ properties: {
511
+ capabilityId: {
512
+ type: 'string',
513
+ description: 'ID of the capability to retrieve'
514
+ }
515
+ },
516
+ required: ['capabilityId']
517
+ }
518
+ },
519
+ {
520
+ name: 'search_capabilities',
521
+ description: 'Search capabilities by name or description',
522
+ inputSchema: {
523
+ type: 'object',
524
+ properties: {
525
+ query: {
526
+ type: 'string',
527
+ description: 'Search query'
528
+ },
529
+ category: {
530
+ type: 'string',
531
+ description: 'Filter by category'
532
+ },
533
+ limit: {
534
+ type: 'number',
535
+ minimum: 1,
536
+ maximum: 100,
537
+ description: 'Maximum number of results'
538
+ }
539
+ },
540
+ required: ['query']
541
+ }
542
+ }
543
+ ];
544
+ }
545
+ /**
546
+ * Set up build management tools handlers
547
+ */
548
+ setupBuildTools() {
549
+ // Build tools are handled in the main CallToolRequestSchema handler
550
+ }
551
+ /**
552
+ * Set up file management tools handlers
553
+ */
554
+ setupFileTools() {
555
+ // File tools are handled in the main CallToolRequestSchema handler
556
+ }
557
+ /**
558
+ * Set up capability management tools handlers
559
+ */
560
+ setupCapabilityTools() {
561
+ // Capability tools are handled in the main CallToolRequestSchema handler
562
+ }
563
+ /**
564
+ * Set up error handlers
565
+ */
566
+ setupErrorHandlers() {
567
+ this.server.onerror = (error) => {
568
+ const processedError = errorHandler_js_1.ErrorHandler.processError(error, 'MCP Server');
569
+ errorHandler_js_1.ErrorHandler.logError(processedError);
570
+ };
571
+ // Handle uncaught exceptions
572
+ process.on('uncaughtException', (error) => {
573
+ const processedError = errorHandler_js_1.ErrorHandler.processError(error, 'Uncaught Exception');
574
+ errorHandler_js_1.ErrorHandler.logError(processedError);
575
+ process.exit(1);
576
+ });
577
+ process.on('unhandledRejection', (reason) => {
578
+ const processedError = errorHandler_js_1.ErrorHandler.processError(reason, 'Unhandled Rejection');
579
+ errorHandler_js_1.ErrorHandler.logError(processedError);
580
+ });
581
+ }
582
+ // Tool handler methods
583
+ async handleListContainers(args) {
584
+ const result = await containerService_js_1.containerService.listContainers(args);
585
+ return {
586
+ content: [
587
+ {
588
+ type: 'text',
589
+ text: `Found ${result.containers.length} containers (${result.total} total):\n\n` +
590
+ result.containers.map(c => `**${c.name}** (${c.id})\n` +
591
+ `Description: ${c.description}\n` +
592
+ `Tags: ${c.tags?.join(', ') || 'None'}\n` +
593
+ `Private: ${c.isPrivate ? 'Yes' : 'No'}\n` +
594
+ `Created: ${c.createdAt}\n`).join('\n'),
595
+ },
596
+ ],
597
+ };
598
+ }
599
+ async handleGetContainer(args) {
600
+ const result = await containerService_js_1.containerService.getContainer(args);
601
+ return {
602
+ content: [
603
+ {
604
+ type: 'text',
605
+ text: `**Container: ${result.name}**\n\n` +
606
+ `ID: ${result.id}\n` +
607
+ `Description: ${result.description}\n` +
608
+ `Tags: ${result.tags?.join(', ') || 'None'}\n` +
609
+ `Private: ${result.isPrivate ? 'Yes' : 'No'}\n` +
610
+ `Created: ${result.createdAt}\n` +
611
+ `Updated: ${result.updatedAt}\n\n` +
612
+ `**Dockerfile:**\n\`\`\`dockerfile\n${result.dockerfile}\n\`\`\`\n\n` +
613
+ `**Environment Variables:**\n${Object.entries(result.envVars || {}).map(([k, v]) => `${k}=${v}`).join('\n') || 'None'}`,
614
+ },
615
+ ],
616
+ };
617
+ }
618
+ async handleCreateContainer(args) {
619
+ const result = await containerService_js_1.containerService.createContainer(args);
620
+ return {
621
+ content: [
622
+ {
623
+ type: 'text',
624
+ text: `Container "${result.name}" created successfully!\n\n` +
625
+ `ID: ${result.id}\n` +
626
+ `Description: ${result.description}\n` +
627
+ `Created: ${result.createdAt}`,
628
+ },
629
+ ],
630
+ };
631
+ }
632
+ async handleUpdateContainer(args) {
633
+ const result = await containerService_js_1.containerService.updateContainer(args);
634
+ return {
635
+ content: [
636
+ {
637
+ type: 'text',
638
+ text: `Container "${result.name}" updated successfully!\n\n` +
639
+ `ID: ${result.id}\n` +
640
+ `Updated: ${result.updatedAt}`,
641
+ },
642
+ ],
643
+ };
644
+ }
645
+ async handleDeleteContainer(args) {
646
+ const result = await containerService_js_1.containerService.deleteContainer(args);
647
+ return {
648
+ content: [
649
+ {
650
+ type: 'text',
651
+ text: result.message,
652
+ },
653
+ ],
654
+ };
655
+ }
656
+ async handleCopyContainer(args) {
657
+ const result = await containerService_js_1.containerService.copyContainer(args);
658
+ return {
659
+ content: [
660
+ {
661
+ type: 'text',
662
+ text: `Container copied successfully!\n\n` +
663
+ `New container: "${result.name}" (${result.id})\n` +
664
+ `Created: ${result.createdAt}`,
665
+ },
666
+ ],
667
+ };
668
+ }
669
+ async handleBuildContainer(args) {
670
+ const result = await buildService_js_1.buildService.buildContainer(args);
671
+ return {
672
+ content: [
673
+ {
674
+ type: 'text',
675
+ text: `Build started for container ${args.containerId}!\n\n` +
676
+ `Build ID: ${result.id}\n` +
677
+ `Status: ${result.status}\n` +
678
+ `Started: ${result.startTime}`,
679
+ },
680
+ ],
681
+ };
682
+ }
683
+ async handleGetBuildStatus(args) {
684
+ const result = await buildService_js_1.buildService.getBuildStatus(args);
685
+ return {
686
+ content: [
687
+ {
688
+ type: 'text',
689
+ text: `**Build Status**\n\n` +
690
+ `Build ID: ${result.id}\n` +
691
+ `Container: ${result.containerId}\n` +
692
+ `Status: ${result.status}\n` +
693
+ `Started: ${result.startTime}\n` +
694
+ `${result.endTime ? `Ended: ${result.endTime}\n` : ''}` +
695
+ `${result.progress ? `Progress: ${result.progress}%\n` : ''}` +
696
+ `${result.error ? `Error: ${result.error}\n` : ''}`,
697
+ },
698
+ ],
699
+ };
700
+ }
701
+ async handleListBuilds(args) {
702
+ const result = await buildService_js_1.buildService.listBuilds(args);
703
+ return {
704
+ content: [
705
+ {
706
+ type: 'text',
707
+ text: `Found ${result.builds.length} builds (${result.total} total):\n\n` +
708
+ result.builds.map(b => `**Build ${b.id}**\n` +
709
+ `Container: ${b.containerId}\n` +
710
+ `Status: ${b.status}\n` +
711
+ `Started: ${b.startTime}\n` +
712
+ `${b.endTime ? `Ended: ${b.endTime}\n` : ''}\n`).join('\n'),
713
+ },
714
+ ],
715
+ };
716
+ }
717
+ async handleGetBuildLogs(args) {
718
+ const result = await buildService_js_1.buildService.getBuildLogs(args.containerId, args.buildId);
719
+ return {
720
+ content: [
721
+ {
722
+ type: 'text',
723
+ text: result.length === 0 ? 'No build logs available yet.' :
724
+ `**Build Logs**\n\n` +
725
+ result.map(log => `[${log.timestamp}] ${log.level.toUpperCase()}: ${log.message}`).join('\n'),
726
+ },
727
+ ],
728
+ };
729
+ }
730
+ async handleListContainerFiles(args) {
731
+ const result = await fileService_js_1.fileService.listContainerFiles(args);
732
+ return {
733
+ content: [
734
+ {
735
+ type: 'text',
736
+ text: `Files in ${result.path} (${result.total} total):\n\n` +
737
+ result.files.map(f => `${f.type === 'directory' ? '📁' : '📄'} **${f.name}**\n` +
738
+ `Path: ${f.path}\n` +
739
+ `${f.size ? `Size: ${f.size} bytes\n` : ''}` +
740
+ `${f.lastModified ? `Modified: ${f.lastModified}\n` : ''}\n`).join('\n'),
741
+ },
742
+ ],
743
+ };
744
+ }
745
+ async handleGetFileContent(args) {
746
+ const result = await fileService_js_1.fileService.getFileContent(args);
747
+ return {
748
+ content: [
749
+ {
750
+ type: 'text',
751
+ text: `**File: ${result.name}**\n\n` +
752
+ `Path: ${result.path}\n` +
753
+ `${result.size ? `Size: ${result.size} bytes\n` : ''}` +
754
+ `${result.mimeType ? `Type: ${result.mimeType}\n` : ''}` +
755
+ `${result.lastModified ? `Modified: ${result.lastModified}\n` : ''}\n\n` +
756
+ `**Content:**\n\`\`\`\n${result.content || 'No content available'}\n\`\`\``,
757
+ },
758
+ ],
759
+ };
760
+ }
761
+ async handleUploadFile(args) {
762
+ const result = await fileService_js_1.fileService.uploadFile(args);
763
+ return {
764
+ content: [
765
+ {
766
+ type: 'text',
767
+ text: `File uploaded successfully!\n\n` +
768
+ `Path: ${result.path}\n` +
769
+ `Name: ${result.name}\n` +
770
+ `Size: ${result.size} bytes\n` +
771
+ `Uploaded: ${result.uploadedAt}`,
772
+ },
773
+ ],
774
+ };
775
+ }
776
+ async handleUpdateFile(args) {
777
+ const result = await fileService_js_1.fileService.updateFile(args);
778
+ return {
779
+ content: [
780
+ {
781
+ type: 'text',
782
+ text: `File updated successfully!\n\n` +
783
+ `Path: ${result.path}\n` +
784
+ `Name: ${result.name}\n` +
785
+ `${result.size ? `Size: ${result.size} bytes\n` : ''}` +
786
+ `${result.lastModified ? `Modified: ${result.lastModified}` : ''}`,
787
+ },
788
+ ],
789
+ };
790
+ }
791
+ async handleDeleteFile(args) {
792
+ const result = await fileService_js_1.fileService.deleteFile(args.containerId, args.filePath);
793
+ return {
794
+ content: [
795
+ {
796
+ type: 'text',
797
+ text: result.message,
798
+ },
799
+ ],
800
+ };
801
+ }
802
+ async handleListCapabilities(args) {
803
+ const result = await capabilityService_js_1.capabilityService.listCapabilities(args);
804
+ return {
805
+ content: [
806
+ {
807
+ type: 'text',
808
+ text: `Found ${result.capabilities.length} capabilities (${result.total} total):\n\n` +
809
+ result.capabilities.map(c => `**${c.name}** (${c.id})\n` +
810
+ `Description: ${c.description}\n` +
811
+ `Category: ${c.category}\n` +
812
+ `Version: ${c.version}\n` +
813
+ `Active: ${c.isActive ? 'Yes' : 'No'}\n\n`).join(''),
814
+ },
815
+ ],
816
+ };
817
+ }
818
+ async handleGetCapability(args) {
819
+ const result = await capabilityService_js_1.capabilityService.getCapability(args);
820
+ return {
821
+ content: [
822
+ {
823
+ type: 'text',
824
+ text: `**Capability: ${result.name}**\n\n` +
825
+ `ID: ${result.id}\n` +
826
+ `Description: ${result.description}\n` +
827
+ `Category: ${result.category}\n` +
828
+ `Version: ${result.version}\n` +
829
+ `Active: ${result.isActive ? 'Yes' : 'No'}\n` +
830
+ `${result.dependencies?.length ? `Dependencies: ${result.dependencies.join(', ')}\n` : ''}` +
831
+ `${result.configuration ? `Configuration: ${JSON.stringify(result.configuration, null, 2)}` : ''}`,
832
+ },
833
+ ],
834
+ };
835
+ }
836
+ async handleSearchCapabilities(args) {
837
+ const result = await capabilityService_js_1.capabilityService.searchCapabilities(args.query, args.category, args.limit);
838
+ return {
839
+ content: [
840
+ {
841
+ type: 'text',
842
+ text: `Search results for "${args.query}" (${result.length} found):\n\n` +
843
+ result.map(c => `**${c.name}** (${c.id})\n` +
844
+ `Description: ${c.description}\n` +
845
+ `Category: ${c.category}\n\n`).join(''),
846
+ },
847
+ ],
848
+ };
849
+ }
850
+ /**
851
+ * Start the MCP server
852
+ */
853
+ async start() {
854
+ try {
855
+ // Test authentication
856
+ console.error('🔑 Testing authentication...');
857
+ const isAuthenticated = await auth_js_1.authManager.testAuthentication();
858
+ if (!isAuthenticated) {
859
+ throw new Error('Authentication failed. Please check your API credentials.');
860
+ }
861
+ console.error('✅ Authentication successful');
862
+ // Start the server
863
+ const transport = new stdio_js_1.StdioServerTransport();
864
+ await this.server.connect(transport);
865
+ console.error('🚀 172.ai Container MCP Server started successfully');
866
+ console.error(`📋 Configuration: ${config_js_1.config.get('baseUrl')} (${config_js_1.config.get('environment')})`);
867
+ console.error('🔧 Available tools: container management, builds, files, capabilities');
868
+ }
869
+ catch (error) {
870
+ const processedError = errorHandler_js_1.ErrorHandler.processError(error, 'Server startup');
871
+ errorHandler_js_1.ErrorHandler.logError(processedError);
872
+ console.error('❌ Failed to start MCP server:', processedError.message);
873
+ process.exit(1);
874
+ }
875
+ }
876
+ }
877
+ exports.ContainerMCPServer = ContainerMCPServer;
878
+ // Start the server if this file is run directly
879
+ if (require.main === module) {
880
+ const server = new ContainerMCPServer();
881
+ server.start().catch((error) => {
882
+ console.error('Fatal error:', error);
883
+ process.exit(1);
884
+ });
885
+ }
886
+ //# sourceMappingURL=server.js.map