@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.
- package/.env.example +43 -0
- package/README.md +366 -0
- package/dist/auth.d.ts +57 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +192 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +84 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +246 -0
- package/dist/config.js.map +1 -0
- package/dist/server.d.ts +63 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +886 -0
- package/dist/server.js.map +1 -0
- package/dist/services/buildService.d.ts +51 -0
- package/dist/services/buildService.d.ts.map +1 -0
- package/dist/services/buildService.js +268 -0
- package/dist/services/buildService.js.map +1 -0
- package/dist/services/capabilityService.d.ts +62 -0
- package/dist/services/capabilityService.d.ts.map +1 -0
- package/dist/services/capabilityService.js +240 -0
- package/dist/services/capabilityService.js.map +1 -0
- package/dist/services/containerService.d.ts +52 -0
- package/dist/services/containerService.d.ts.map +1 -0
- package/dist/services/containerService.js +251 -0
- package/dist/services/containerService.js.map +1 -0
- package/dist/services/fileService.d.ts +65 -0
- package/dist/services/fileService.d.ts.map +1 -0
- package/dist/services/fileService.js +330 -0
- package/dist/services/fileService.js.map +1 -0
- package/dist/setup.d.ts +30 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +328 -0
- package/dist/setup.js.map +1 -0
- package/dist/types.d.ts +229 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/errorHandler.d.ts +78 -0
- package/dist/utils/errorHandler.d.ts.map +1 -0
- package/dist/utils/errorHandler.js +269 -0
- package/dist/utils/errorHandler.js.map +1 -0
- 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
|