@172ai/containers-mcp-server 1.12.2 → 1.12.4
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/dist/auth.d.ts +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +26 -33
- package/dist/auth.js.map +1 -1
- package/dist/cli-tool.js +67 -105
- package/dist/cli-tool.js.map +1 -1
- package/dist/cli.js +4 -37
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -42
- package/dist/config.js.map +1 -1
- package/dist/scripts/test-mcp-tools.js +9 -12
- package/dist/scripts/test-mcp-tools.js.map +1 -1
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +727 -87
- package/dist/server.js.map +1 -1
- package/dist/services/buildService.d.ts +1 -1
- package/dist/services/buildService.d.ts.map +1 -1
- package/dist/services/buildService.js +37 -41
- package/dist/services/buildService.js.map +1 -1
- package/dist/services/capabilityService.d.ts +1 -1
- package/dist/services/capabilityService.d.ts.map +1 -1
- package/dist/services/capabilityService.js +32 -36
- package/dist/services/capabilityService.js.map +1 -1
- package/dist/services/containerService.d.ts +1 -1
- package/dist/services/containerService.d.ts.map +1 -1
- package/dist/services/containerService.js +47 -51
- package/dist/services/containerService.js.map +1 -1
- package/dist/services/executionService.d.ts +1 -1
- package/dist/services/executionService.d.ts.map +1 -1
- package/dist/services/executionService.js +48 -52
- package/dist/services/executionService.js.map +1 -1
- package/dist/services/exportService.d.ts +108 -0
- package/dist/services/exportService.d.ts.map +1 -0
- package/dist/services/exportService.js +659 -0
- package/dist/services/exportService.js.map +1 -0
- package/dist/services/fileService.d.ts +1 -1
- package/dist/services/fileService.d.ts.map +1 -1
- package/dist/services/fileService.js +73 -77
- package/dist/services/fileService.js.map +1 -1
- package/dist/services/importService.d.ts +90 -0
- package/dist/services/importService.d.ts.map +1 -0
- package/dist/services/importService.js +570 -0
- package/dist/services/importService.js.map +1 -0
- package/dist/services/streamingService.js +16 -23
- package/dist/services/streamingService.js.map +1 -1
- package/dist/services/userNotificationManager.d.ts +22 -4
- package/dist/services/userNotificationManager.d.ts.map +1 -1
- package/dist/services/userNotificationManager.js +59 -19
- package/dist/services/userNotificationManager.js.map +1 -1
- package/dist/services/userService.d.ts +1 -5
- package/dist/services/userService.d.ts.map +1 -1
- package/dist/services/userService.js +19 -43
- package/dist/services/userService.js.map +1 -1
- package/dist/setup.js +28 -67
- package/dist/setup.js.map +1 -1
- package/dist/types.d.ts +121 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/enhancedErrorHandler.d.ts +1 -1
- package/dist/utils/enhancedErrorHandler.d.ts.map +1 -1
- package/dist/utils/enhancedErrorHandler.js +47 -52
- package/dist/utils/enhancedErrorHandler.js.map +1 -1
- package/dist/utils/errorHandler.d.ts +1 -1
- package/dist/utils/errorHandler.d.ts.map +1 -1
- package/dist/utils/errorHandler.js +15 -20
- package/dist/utils/errorHandler.js.map +1 -1
- package/dist/utils/logBuffer.js +2 -6
- package/dist/utils/logBuffer.js.map +1 -1
- package/dist/utils/retryHandler.js +7 -13
- package/dist/utils/retryHandler.js.map +1 -1
- package/package.json +2 -1
package/dist/server.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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");
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
8
5
|
// Import our services and utilities
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
6
|
+
import { config } from './config.js';
|
|
7
|
+
import { authManager } from './auth.js';
|
|
8
|
+
import { containerService } from './services/containerService.js';
|
|
9
|
+
import { buildService } from './services/buildService.js';
|
|
10
|
+
import { fileService } from './services/fileService.js';
|
|
11
|
+
import { capabilityService } from './services/capabilityService.js';
|
|
12
|
+
import { executionService } from './services/executionService.js';
|
|
13
|
+
import { importService } from './services/importService.js';
|
|
14
|
+
import { exportService } from './services/exportService.js';
|
|
15
|
+
import { streamingService } from './services/streamingService.js';
|
|
16
|
+
import { userNotificationManager } from './services/userNotificationManager.js';
|
|
17
|
+
import { userService } from './services/userService.js';
|
|
18
|
+
import { ErrorHandler } from './utils/errorHandler.js';
|
|
20
19
|
/**
|
|
21
20
|
* 172.ai Container Management MCP Server
|
|
22
21
|
*
|
|
@@ -25,13 +24,15 @@ const errorHandler_js_1 = require("./utils/errorHandler.js");
|
|
|
25
24
|
*/
|
|
26
25
|
class ContainerMCPServer {
|
|
27
26
|
constructor() {
|
|
28
|
-
this.server = new
|
|
27
|
+
this.server = new Server({
|
|
29
28
|
name: '172ai-containers-mcp-server',
|
|
30
29
|
version: '1.0.0',
|
|
31
30
|
});
|
|
32
31
|
// Initialize MCP server reference for progress notifications
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
buildService.setMCPServer(this.server);
|
|
33
|
+
executionService.setMCPServer(this.server);
|
|
34
|
+
importService.setMCPServer(this.server);
|
|
35
|
+
exportService.setMCPServer(this.server);
|
|
35
36
|
this.setupTools();
|
|
36
37
|
this.setupErrorHandlers();
|
|
37
38
|
this.initializeStreaming();
|
|
@@ -42,7 +43,7 @@ class ContainerMCPServer {
|
|
|
42
43
|
*/
|
|
43
44
|
async initializeStreaming() {
|
|
44
45
|
try {
|
|
45
|
-
const streamingConfig =
|
|
46
|
+
const streamingConfig = config.get('streaming');
|
|
46
47
|
// Check if user-notifications streaming is enabled
|
|
47
48
|
if (!streamingConfig?.enableUserNotifications) {
|
|
48
49
|
console.log('[MCP Server] User-notifications streaming disabled via config');
|
|
@@ -57,10 +58,10 @@ class ContainerMCPServer {
|
|
|
57
58
|
console.log('[MCP Server] Initializing user-notifications streaming...');
|
|
58
59
|
// Get current user ID to initialize the notification stream
|
|
59
60
|
try {
|
|
60
|
-
const userInfo = await
|
|
61
|
+
const userInfo = await userService.getUserProfile();
|
|
61
62
|
const userId = userInfo.id;
|
|
62
63
|
console.log(`[MCP Server] Initializing user-notifications for user ${userId}...`);
|
|
63
|
-
await
|
|
64
|
+
await userNotificationManager.initialize(userId);
|
|
64
65
|
console.log('[MCP Server] ✅ User-notifications streaming initialized and ready');
|
|
65
66
|
}
|
|
66
67
|
catch (error) {
|
|
@@ -94,19 +95,19 @@ class ContainerMCPServer {
|
|
|
94
95
|
*/
|
|
95
96
|
setupContainerTools() {
|
|
96
97
|
// List containers
|
|
97
|
-
this.server.setRequestHandler(
|
|
98
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
98
99
|
return {
|
|
99
100
|
tools: this.getAllTools(),
|
|
100
101
|
};
|
|
101
102
|
});
|
|
102
103
|
// Handle prompts/list requests
|
|
103
|
-
this.server.setRequestHandler(
|
|
104
|
+
this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
104
105
|
return {
|
|
105
106
|
prompts: this.getContainerWorkflowPrompts(),
|
|
106
107
|
};
|
|
107
108
|
});
|
|
108
109
|
// Handle prompts/get requests
|
|
109
|
-
this.server.setRequestHandler(
|
|
110
|
+
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
110
111
|
const { name, arguments: args } = request.params;
|
|
111
112
|
switch (name) {
|
|
112
113
|
case 'container_development_workflow':
|
|
@@ -118,16 +119,16 @@ class ContainerMCPServer {
|
|
|
118
119
|
case 'container_best_practices':
|
|
119
120
|
return this.getContainerBestPracticesContent();
|
|
120
121
|
default:
|
|
121
|
-
throw
|
|
122
|
+
throw ErrorHandler.createValidationError(`Unknown prompt: ${name}`);
|
|
122
123
|
}
|
|
123
124
|
});
|
|
124
125
|
// Handle resources/list requests
|
|
125
|
-
this.server.setRequestHandler(
|
|
126
|
+
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
126
127
|
return {
|
|
127
128
|
resources: [],
|
|
128
129
|
};
|
|
129
130
|
});
|
|
130
|
-
this.server.setRequestHandler(
|
|
131
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
131
132
|
const { name, arguments: args } = request.params;
|
|
132
133
|
try {
|
|
133
134
|
switch (name) {
|
|
@@ -157,6 +158,32 @@ class ContainerMCPServer {
|
|
|
157
158
|
return await this.handleCancelBuildMonitoring(args);
|
|
158
159
|
case 'get_stream_analytics':
|
|
159
160
|
return await this.handleGetStreamAnalytics(args);
|
|
161
|
+
case 'import_container':
|
|
162
|
+
return await this.handleImportContainer(args);
|
|
163
|
+
case 'get_import_status':
|
|
164
|
+
return await this.handleGetImportStatus(args);
|
|
165
|
+
case 'list_import_jobs':
|
|
166
|
+
return await this.handleListImportJobs(args);
|
|
167
|
+
case 'cancel_import_monitoring':
|
|
168
|
+
return await this.handleCancelImportMonitoring(args);
|
|
169
|
+
case 'get_import_stream_analytics':
|
|
170
|
+
return await this.handleGetImportStreamAnalytics(args);
|
|
171
|
+
case 'export_container':
|
|
172
|
+
return await this.handleExportContainer(args);
|
|
173
|
+
case 'get_export_status':
|
|
174
|
+
return await this.handleGetExportStatus(args);
|
|
175
|
+
case 'list_export_jobs':
|
|
176
|
+
return await this.handleListExportJobs(args);
|
|
177
|
+
case 'get_export_download_url':
|
|
178
|
+
return await this.handleGetExportDownloadUrl(args);
|
|
179
|
+
case 'cancel_export_job':
|
|
180
|
+
return await this.handleCancelExportJob(args);
|
|
181
|
+
case 'cancel_export_monitoring':
|
|
182
|
+
return await this.handleCancelExportMonitoring(args);
|
|
183
|
+
case 'get_export_stream_analytics':
|
|
184
|
+
return await this.handleGetExportStreamAnalytics(args);
|
|
185
|
+
case 'get_export_progress_update':
|
|
186
|
+
return await this.handleGetExportProgressUpdate(args);
|
|
160
187
|
case 'list_container_files':
|
|
161
188
|
return await this.handleListContainerFiles(args);
|
|
162
189
|
case 'get_file_content':
|
|
@@ -210,12 +237,12 @@ class ContainerMCPServer {
|
|
|
210
237
|
case 'get_all_progress_updates':
|
|
211
238
|
return await this.handleGetAllProgressUpdates(args);
|
|
212
239
|
default:
|
|
213
|
-
throw
|
|
240
|
+
throw ErrorHandler.createValidationError(`Unknown tool: ${name}`);
|
|
214
241
|
}
|
|
215
242
|
}
|
|
216
243
|
catch (error) {
|
|
217
|
-
const processedError =
|
|
218
|
-
|
|
244
|
+
const processedError = ErrorHandler.processError(error, `Tool: ${name}`);
|
|
245
|
+
ErrorHandler.logError(processedError);
|
|
219
246
|
return {
|
|
220
247
|
content: [
|
|
221
248
|
{
|
|
@@ -738,6 +765,279 @@ Follow same metadata requirements as create_container.`,
|
|
|
738
765
|
}
|
|
739
766
|
}
|
|
740
767
|
},
|
|
768
|
+
// Import Management Tools
|
|
769
|
+
{
|
|
770
|
+
name: 'import_container',
|
|
771
|
+
description: 'Import a container from Docker Hub or GitHub repository with optional progress tracking',
|
|
772
|
+
inputSchema: {
|
|
773
|
+
type: 'object',
|
|
774
|
+
properties: {
|
|
775
|
+
sourceType: {
|
|
776
|
+
type: 'string',
|
|
777
|
+
enum: ['docker', 'git'],
|
|
778
|
+
description: 'Source type: "docker" for Docker Hub or "git" for GitHub repository'
|
|
779
|
+
},
|
|
780
|
+
sourceUrl: {
|
|
781
|
+
type: 'string',
|
|
782
|
+
description: 'Source URL (e.g., "nginx:latest" for Docker or "https://github.com/user/repo" for Git)'
|
|
783
|
+
},
|
|
784
|
+
name: {
|
|
785
|
+
type: 'string',
|
|
786
|
+
description: 'Optional custom name for the imported container'
|
|
787
|
+
},
|
|
788
|
+
dockerfilePath: {
|
|
789
|
+
type: 'string',
|
|
790
|
+
description: 'Optional Dockerfile path for Git imports (default: Dockerfile)'
|
|
791
|
+
},
|
|
792
|
+
dockerHubUsername: {
|
|
793
|
+
type: 'string',
|
|
794
|
+
description: 'Optional Docker Hub username for private images'
|
|
795
|
+
},
|
|
796
|
+
dockerHubToken: {
|
|
797
|
+
type: 'string',
|
|
798
|
+
description: 'Optional Docker Hub access token for private images'
|
|
799
|
+
},
|
|
800
|
+
progressToken: {
|
|
801
|
+
type: 'string',
|
|
802
|
+
description: 'Optional token for receiving real-time progress notifications during import'
|
|
803
|
+
}
|
|
804
|
+
},
|
|
805
|
+
required: ['sourceType', 'sourceUrl']
|
|
806
|
+
}
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
name: 'get_import_status',
|
|
810
|
+
description: 'Get the status of a container import job',
|
|
811
|
+
inputSchema: {
|
|
812
|
+
type: 'object',
|
|
813
|
+
properties: {
|
|
814
|
+
jobId: {
|
|
815
|
+
type: 'string',
|
|
816
|
+
description: 'ID of the import job'
|
|
817
|
+
}
|
|
818
|
+
},
|
|
819
|
+
required: ['jobId']
|
|
820
|
+
}
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
name: 'list_import_jobs',
|
|
824
|
+
description: 'List user\'s container import jobs',
|
|
825
|
+
inputSchema: {
|
|
826
|
+
type: 'object',
|
|
827
|
+
properties: {
|
|
828
|
+
status: {
|
|
829
|
+
type: 'string',
|
|
830
|
+
enum: ['pending', 'queued', 'processing', 'completed', 'failed'],
|
|
831
|
+
description: 'Filter by import status'
|
|
832
|
+
},
|
|
833
|
+
limit: {
|
|
834
|
+
type: 'number',
|
|
835
|
+
minimum: 1,
|
|
836
|
+
maximum: 100,
|
|
837
|
+
description: 'Maximum number of import jobs to return'
|
|
838
|
+
},
|
|
839
|
+
offset: {
|
|
840
|
+
type: 'number',
|
|
841
|
+
minimum: 0,
|
|
842
|
+
description: 'Number of import jobs to skip'
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
name: 'cancel_import_monitoring',
|
|
849
|
+
description: 'Cancel progress monitoring for a specific import using its progress token',
|
|
850
|
+
inputSchema: {
|
|
851
|
+
type: 'object',
|
|
852
|
+
properties: {
|
|
853
|
+
progressToken: {
|
|
854
|
+
type: 'string',
|
|
855
|
+
description: 'Progress token of the import monitoring to cancel'
|
|
856
|
+
},
|
|
857
|
+
reason: {
|
|
858
|
+
type: 'string',
|
|
859
|
+
description: 'Optional reason for cancellation'
|
|
860
|
+
}
|
|
861
|
+
},
|
|
862
|
+
required: ['progressToken']
|
|
863
|
+
}
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
name: 'get_import_stream_analytics',
|
|
867
|
+
description: 'Get real-time analytics and statistics for import streaming operations',
|
|
868
|
+
inputSchema: {
|
|
869
|
+
type: 'object',
|
|
870
|
+
properties: {
|
|
871
|
+
includeActiveMonitors: {
|
|
872
|
+
type: 'boolean',
|
|
873
|
+
description: 'Whether to include details of currently active import monitors'
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
},
|
|
878
|
+
// Export Management Tools
|
|
879
|
+
{
|
|
880
|
+
name: 'export_container',
|
|
881
|
+
description: 'Export a container to Docker Hub, GitHub, or as an archive with optional progress tracking',
|
|
882
|
+
inputSchema: {
|
|
883
|
+
type: 'object',
|
|
884
|
+
properties: {
|
|
885
|
+
containerId: {
|
|
886
|
+
type: 'string',
|
|
887
|
+
description: 'ID of the container to export'
|
|
888
|
+
},
|
|
889
|
+
destinationType: {
|
|
890
|
+
type: 'string',
|
|
891
|
+
enum: ['docker', 'git', 'archive'],
|
|
892
|
+
description: 'Export destination type: "docker" for Docker Hub, "git" for GitHub, "archive" for downloadable tar.gz/zip'
|
|
893
|
+
},
|
|
894
|
+
destination: {
|
|
895
|
+
type: 'object',
|
|
896
|
+
description: 'Destination configuration (registry/repository/tag for Docker, repositoryName/branch/token for GitHub, format for archive)',
|
|
897
|
+
properties: {
|
|
898
|
+
registry: { type: 'string', description: 'Docker registry (e.g., docker.io, gcr.io, ghcr.io)' },
|
|
899
|
+
repository: { type: 'string', description: 'Docker repository (e.g., username/imagename)' },
|
|
900
|
+
tag: { type: 'string', description: 'Docker image tag (e.g., latest, v1.0.0)' },
|
|
901
|
+
username: { type: 'string', description: 'Docker Hub username' },
|
|
902
|
+
token: { type: 'string', description: 'Docker Hub token/password' },
|
|
903
|
+
repositoryName: { type: 'string', description: 'GitHub repository (e.g., username/repo-name)' },
|
|
904
|
+
branch: { type: 'string', description: 'GitHub branch (e.g., main, develop)' },
|
|
905
|
+
githubToken: { type: 'string', description: 'GitHub Personal Access Token' },
|
|
906
|
+
archiveFormat: { type: 'string', enum: ['tar.gz', 'zip'], description: 'Archive format' }
|
|
907
|
+
}
|
|
908
|
+
},
|
|
909
|
+
options: {
|
|
910
|
+
type: 'object',
|
|
911
|
+
description: 'Export options',
|
|
912
|
+
properties: {
|
|
913
|
+
includeDockerfile: { type: 'boolean', description: 'Include Dockerfile in export' },
|
|
914
|
+
includeMetadata: { type: 'boolean', description: 'Include metadata.json in export' }
|
|
915
|
+
}
|
|
916
|
+
},
|
|
917
|
+
progressToken: {
|
|
918
|
+
type: 'string',
|
|
919
|
+
description: 'Optional token for receiving real-time progress notifications during export'
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
required: ['containerId', 'destinationType', 'destination']
|
|
923
|
+
}
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
name: 'get_export_status',
|
|
927
|
+
description: 'Get the status of a container export job',
|
|
928
|
+
inputSchema: {
|
|
929
|
+
type: 'object',
|
|
930
|
+
properties: {
|
|
931
|
+
jobId: {
|
|
932
|
+
type: 'string',
|
|
933
|
+
description: 'ID of the export job'
|
|
934
|
+
}
|
|
935
|
+
},
|
|
936
|
+
required: ['jobId']
|
|
937
|
+
}
|
|
938
|
+
},
|
|
939
|
+
{
|
|
940
|
+
name: 'list_export_jobs',
|
|
941
|
+
description: 'List user\'s container export jobs',
|
|
942
|
+
inputSchema: {
|
|
943
|
+
type: 'object',
|
|
944
|
+
properties: {
|
|
945
|
+
containerId: {
|
|
946
|
+
type: 'string',
|
|
947
|
+
description: 'Filter by container ID (optional)'
|
|
948
|
+
},
|
|
949
|
+
status: {
|
|
950
|
+
type: 'string',
|
|
951
|
+
enum: ['pending', 'validating', 'building', 'preparing', 'authenticating', 'uploading', 'pushing', 'verifying', 'completed', 'failed', 'cancelled'],
|
|
952
|
+
description: 'Filter by export status'
|
|
953
|
+
},
|
|
954
|
+
limit: {
|
|
955
|
+
type: 'number',
|
|
956
|
+
minimum: 1,
|
|
957
|
+
maximum: 100,
|
|
958
|
+
description: 'Maximum number of export jobs to return'
|
|
959
|
+
},
|
|
960
|
+
offset: {
|
|
961
|
+
type: 'number',
|
|
962
|
+
minimum: 0,
|
|
963
|
+
description: 'Number of export jobs to skip'
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
name: 'get_export_download_url',
|
|
970
|
+
description: 'Get download URL for an archive export',
|
|
971
|
+
inputSchema: {
|
|
972
|
+
type: 'object',
|
|
973
|
+
properties: {
|
|
974
|
+
jobId: {
|
|
975
|
+
type: 'string',
|
|
976
|
+
description: 'ID of the export job'
|
|
977
|
+
}
|
|
978
|
+
},
|
|
979
|
+
required: ['jobId']
|
|
980
|
+
}
|
|
981
|
+
},
|
|
982
|
+
{
|
|
983
|
+
name: 'cancel_export_job',
|
|
984
|
+
description: 'Cancel an in-progress export job',
|
|
985
|
+
inputSchema: {
|
|
986
|
+
type: 'object',
|
|
987
|
+
properties: {
|
|
988
|
+
jobId: {
|
|
989
|
+
type: 'string',
|
|
990
|
+
description: 'ID of the export job to cancel'
|
|
991
|
+
}
|
|
992
|
+
},
|
|
993
|
+
required: ['jobId']
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
{
|
|
997
|
+
name: 'cancel_export_monitoring',
|
|
998
|
+
description: 'Cancel progress monitoring for a specific export using its progress token',
|
|
999
|
+
inputSchema: {
|
|
1000
|
+
type: 'object',
|
|
1001
|
+
properties: {
|
|
1002
|
+
progressToken: {
|
|
1003
|
+
type: 'string',
|
|
1004
|
+
description: 'Progress token of the export monitoring to cancel'
|
|
1005
|
+
},
|
|
1006
|
+
reason: {
|
|
1007
|
+
type: 'string',
|
|
1008
|
+
description: 'Optional reason for cancellation'
|
|
1009
|
+
}
|
|
1010
|
+
},
|
|
1011
|
+
required: ['progressToken']
|
|
1012
|
+
}
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
name: 'get_export_stream_analytics',
|
|
1016
|
+
description: 'Get real-time analytics and statistics for export streaming operations',
|
|
1017
|
+
inputSchema: {
|
|
1018
|
+
type: 'object',
|
|
1019
|
+
properties: {
|
|
1020
|
+
includeActiveMonitors: {
|
|
1021
|
+
type: 'boolean',
|
|
1022
|
+
description: 'Whether to include details of currently active export monitors'
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
name: 'get_export_progress_update',
|
|
1029
|
+
description: 'Get the latest progress update for an export progress token',
|
|
1030
|
+
inputSchema: {
|
|
1031
|
+
type: 'object',
|
|
1032
|
+
properties: {
|
|
1033
|
+
progressToken: {
|
|
1034
|
+
type: 'string',
|
|
1035
|
+
description: 'Progress token to check for updates'
|
|
1036
|
+
}
|
|
1037
|
+
},
|
|
1038
|
+
required: ['progressToken']
|
|
1039
|
+
}
|
|
1040
|
+
},
|
|
741
1041
|
// File Management Tools
|
|
742
1042
|
{
|
|
743
1043
|
name: 'list_container_files',
|
|
@@ -1348,23 +1648,23 @@ Follow same metadata requirements as create_container.`,
|
|
|
1348
1648
|
*/
|
|
1349
1649
|
setupErrorHandlers() {
|
|
1350
1650
|
this.server.onerror = (error) => {
|
|
1351
|
-
const processedError =
|
|
1352
|
-
|
|
1651
|
+
const processedError = ErrorHandler.processError(error, 'MCP Server');
|
|
1652
|
+
ErrorHandler.logError(processedError);
|
|
1353
1653
|
};
|
|
1354
1654
|
// Handle uncaught exceptions
|
|
1355
1655
|
process.on('uncaughtException', (error) => {
|
|
1356
|
-
const processedError =
|
|
1357
|
-
|
|
1656
|
+
const processedError = ErrorHandler.processError(error, 'Uncaught Exception');
|
|
1657
|
+
ErrorHandler.logError(processedError);
|
|
1358
1658
|
process.exit(1);
|
|
1359
1659
|
});
|
|
1360
1660
|
process.on('unhandledRejection', (reason) => {
|
|
1361
|
-
const processedError =
|
|
1362
|
-
|
|
1661
|
+
const processedError = ErrorHandler.processError(reason, 'Unhandled Rejection');
|
|
1662
|
+
ErrorHandler.logError(processedError);
|
|
1363
1663
|
});
|
|
1364
1664
|
}
|
|
1365
1665
|
// Tool handler methods
|
|
1366
1666
|
async handleListContainers(args) {
|
|
1367
|
-
const result = await
|
|
1667
|
+
const result = await containerService.listContainers(args);
|
|
1368
1668
|
return {
|
|
1369
1669
|
content: [
|
|
1370
1670
|
{
|
|
@@ -1380,7 +1680,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1380
1680
|
};
|
|
1381
1681
|
}
|
|
1382
1682
|
async handleGetContainer(args) {
|
|
1383
|
-
const result = await
|
|
1683
|
+
const result = await containerService.getContainer(args);
|
|
1384
1684
|
let response = `**Container: ${result.name}**\n\n` +
|
|
1385
1685
|
`ID: ${result.id}\n` +
|
|
1386
1686
|
`Description: ${result.description}\n` +
|
|
@@ -1436,7 +1736,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1436
1736
|
};
|
|
1437
1737
|
}
|
|
1438
1738
|
async handleCreateContainer(args) {
|
|
1439
|
-
const result = await
|
|
1739
|
+
const result = await containerService.createContainer(args);
|
|
1440
1740
|
let response = `Container "${result.name}" created successfully!\n\n` +
|
|
1441
1741
|
`ID: ${result.id}\n` +
|
|
1442
1742
|
`Description: ${result.description}\n`;
|
|
@@ -1464,7 +1764,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1464
1764
|
};
|
|
1465
1765
|
}
|
|
1466
1766
|
async handleUpdateContainer(args) {
|
|
1467
|
-
const result = await
|
|
1767
|
+
const result = await containerService.updateContainer(args);
|
|
1468
1768
|
return {
|
|
1469
1769
|
content: [
|
|
1470
1770
|
{
|
|
@@ -1477,7 +1777,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1477
1777
|
};
|
|
1478
1778
|
}
|
|
1479
1779
|
async handleDeleteContainer(args) {
|
|
1480
|
-
const result = await
|
|
1780
|
+
const result = await containerService.deleteContainer(args);
|
|
1481
1781
|
return {
|
|
1482
1782
|
content: [
|
|
1483
1783
|
{
|
|
@@ -1488,7 +1788,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1488
1788
|
};
|
|
1489
1789
|
}
|
|
1490
1790
|
async handleCopyContainer(args) {
|
|
1491
|
-
const result = await
|
|
1791
|
+
const result = await containerService.copyContainer(args);
|
|
1492
1792
|
return {
|
|
1493
1793
|
content: [
|
|
1494
1794
|
{
|
|
@@ -1502,7 +1802,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1502
1802
|
}
|
|
1503
1803
|
async handleBuildContainer(args) {
|
|
1504
1804
|
const { progressToken, ...buildParams } = args;
|
|
1505
|
-
const result = await
|
|
1805
|
+
const result = await buildService.buildContainer(buildParams, progressToken);
|
|
1506
1806
|
return {
|
|
1507
1807
|
content: [
|
|
1508
1808
|
{
|
|
@@ -1517,7 +1817,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1517
1817
|
};
|
|
1518
1818
|
}
|
|
1519
1819
|
async handleGetBuildStatus(args) {
|
|
1520
|
-
const result = await
|
|
1820
|
+
const result = await buildService.getBuildStatus(args);
|
|
1521
1821
|
return {
|
|
1522
1822
|
content: [
|
|
1523
1823
|
{
|
|
@@ -1535,7 +1835,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1535
1835
|
};
|
|
1536
1836
|
}
|
|
1537
1837
|
async handleListBuilds(args) {
|
|
1538
|
-
const result = await
|
|
1838
|
+
const result = await buildService.listBuilds(args);
|
|
1539
1839
|
return {
|
|
1540
1840
|
content: [
|
|
1541
1841
|
{
|
|
@@ -1551,7 +1851,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1551
1851
|
};
|
|
1552
1852
|
}
|
|
1553
1853
|
async handleGetBuildLogs(args) {
|
|
1554
|
-
const result = await
|
|
1854
|
+
const result = await buildService.getBuildLogs(args.containerId, args.buildId);
|
|
1555
1855
|
return {
|
|
1556
1856
|
content: [
|
|
1557
1857
|
{
|
|
@@ -1564,7 +1864,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1564
1864
|
};
|
|
1565
1865
|
}
|
|
1566
1866
|
async handleExplainBuildLogs(args) {
|
|
1567
|
-
const result = await
|
|
1867
|
+
const result = await buildService.explainBuildLogs(args.containerId, args.buildId, {
|
|
1568
1868
|
verbosity: args.verbosity,
|
|
1569
1869
|
outputFormat: args.outputFormat,
|
|
1570
1870
|
includeRecommendations: args.includeRecommendations,
|
|
@@ -1589,7 +1889,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1589
1889
|
};
|
|
1590
1890
|
}
|
|
1591
1891
|
async handleCancelBuildMonitoring(args) {
|
|
1592
|
-
const success = await
|
|
1892
|
+
const success = await buildService.cancelBuildMonitoring(args.progressToken, args.reason);
|
|
1593
1893
|
return {
|
|
1594
1894
|
content: [
|
|
1595
1895
|
{
|
|
@@ -1602,7 +1902,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1602
1902
|
};
|
|
1603
1903
|
}
|
|
1604
1904
|
async handleGetStreamAnalytics(args) {
|
|
1605
|
-
const analytics =
|
|
1905
|
+
const analytics = buildService.getStreamAnalytics();
|
|
1606
1906
|
const includeMonitors = args.includeActiveMonitors !== false; // Default to true
|
|
1607
1907
|
let analyticsText = `**Build Streaming Analytics**\n\n` +
|
|
1608
1908
|
`📊 **Overview**\n` +
|
|
@@ -1639,8 +1939,347 @@ Follow same metadata requirements as create_container.`,
|
|
|
1639
1939
|
],
|
|
1640
1940
|
};
|
|
1641
1941
|
}
|
|
1942
|
+
// Import handler methods
|
|
1943
|
+
async handleImportContainer(args) {
|
|
1944
|
+
const { progressToken, ...importParams } = args;
|
|
1945
|
+
const result = await importService.importContainer(importParams, progressToken);
|
|
1946
|
+
return {
|
|
1947
|
+
content: [
|
|
1948
|
+
{
|
|
1949
|
+
type: 'text',
|
|
1950
|
+
text: `Container import started successfully!\n\n` +
|
|
1951
|
+
`Job ID: ${result.jobId}\n` +
|
|
1952
|
+
`Source Type: ${result.sourceType}\n` +
|
|
1953
|
+
`Source URL: ${result.sourceUrl}\n` +
|
|
1954
|
+
`Status: ${result.status}\n` +
|
|
1955
|
+
`${result.tokenCost ? `Token Cost: ${result.tokenCost}\n` : ''}` +
|
|
1956
|
+
`${result.estimatedDuration ? `Estimated Duration: ${result.estimatedDuration}\n` : ''}` +
|
|
1957
|
+
`Created: ${result.createdAt}\n` +
|
|
1958
|
+
`${progressToken ? `\n🔄 Progress updates will be sent via notifications using token: ${progressToken}` : ''}`,
|
|
1959
|
+
},
|
|
1960
|
+
],
|
|
1961
|
+
};
|
|
1962
|
+
}
|
|
1963
|
+
async handleGetImportStatus(args) {
|
|
1964
|
+
const result = await importService.getImportStatus(args.jobId);
|
|
1965
|
+
let statusText = `**Import Job Status**\n\n` +
|
|
1966
|
+
`Job ID: ${result.jobId}\n` +
|
|
1967
|
+
`Status: ${result.status}\n` +
|
|
1968
|
+
`Source Type: ${result.sourceType}\n` +
|
|
1969
|
+
`Source URL: ${result.sourceUrl}\n` +
|
|
1970
|
+
`Created: ${result.createdAt}\n` +
|
|
1971
|
+
`${result.updatedAt ? `Updated: ${result.updatedAt}\n` : ''}` +
|
|
1972
|
+
`${result.completedAt ? `Completed: ${result.completedAt}\n` : ''}`;
|
|
1973
|
+
if (result.progress) {
|
|
1974
|
+
statusText += `\n**Progress**\n` +
|
|
1975
|
+
`Step: ${result.progress.step} (${result.progress.stepNumber}/${result.progress.totalSteps})\n` +
|
|
1976
|
+
`Message: ${result.progress.message}\n`;
|
|
1977
|
+
}
|
|
1978
|
+
if (result.containerId) {
|
|
1979
|
+
statusText += `\n✅ **Container Created**: ${result.containerId}\n`;
|
|
1980
|
+
}
|
|
1981
|
+
if (result.errors && result.errors.length > 0) {
|
|
1982
|
+
statusText += `\n❌ **Errors**:\n${result.errors.map(e => ` • ${e}`).join('\n')}\n`;
|
|
1983
|
+
}
|
|
1984
|
+
return {
|
|
1985
|
+
content: [
|
|
1986
|
+
{
|
|
1987
|
+
type: 'text',
|
|
1988
|
+
text: statusText,
|
|
1989
|
+
},
|
|
1990
|
+
],
|
|
1991
|
+
};
|
|
1992
|
+
}
|
|
1993
|
+
async handleListImportJobs(args) {
|
|
1994
|
+
const result = await importService.listImportJobs(args);
|
|
1995
|
+
let listText = `**Import Jobs** (${result.imports.length} found)\n\n`;
|
|
1996
|
+
if (result.imports.length === 0) {
|
|
1997
|
+
listText += `No import jobs found.\n`;
|
|
1998
|
+
}
|
|
1999
|
+
else {
|
|
2000
|
+
result.imports.forEach((job, index) => {
|
|
2001
|
+
listText += `${index + 1}. **${job.jobId}**\n` +
|
|
2002
|
+
` • Status: ${job.status}\n` +
|
|
2003
|
+
` • Source: ${job.sourceType} - ${job.sourceUrl}\n` +
|
|
2004
|
+
` • Created: ${job.createdAt}\n` +
|
|
2005
|
+
` ${job.containerId ? `• Container: ${job.containerId}\n` : ''}` +
|
|
2006
|
+
` ${job.errors && job.errors.length > 0 ? `• Errors: ${job.errors.length}\n` : ''}\n`;
|
|
2007
|
+
});
|
|
2008
|
+
}
|
|
2009
|
+
if (result.pagination) {
|
|
2010
|
+
listText += `\n**Pagination**\n` +
|
|
2011
|
+
`• Showing: ${result.pagination.offset + 1}-${Math.min(result.pagination.offset + result.pagination.limit, result.pagination.total)}\n` +
|
|
2012
|
+
`• Total: ${result.pagination.total}\n` +
|
|
2013
|
+
`• Has More: ${result.pagination.hasMore ? 'Yes' : 'No'}\n`;
|
|
2014
|
+
}
|
|
2015
|
+
return {
|
|
2016
|
+
content: [
|
|
2017
|
+
{
|
|
2018
|
+
type: 'text',
|
|
2019
|
+
text: listText,
|
|
2020
|
+
},
|
|
2021
|
+
],
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
2024
|
+
async handleCancelImportMonitoring(args) {
|
|
2025
|
+
const success = await importService.cancelImportMonitoring(args.progressToken, args.reason);
|
|
2026
|
+
return {
|
|
2027
|
+
content: [
|
|
2028
|
+
{
|
|
2029
|
+
type: 'text',
|
|
2030
|
+
text: success
|
|
2031
|
+
? `✅ Import monitoring cancelled for progress token: ${args.progressToken}\n${args.reason ? `Reason: ${args.reason}` : ''}`
|
|
2032
|
+
: `❌ No active monitoring found for progress token: ${args.progressToken}`,
|
|
2033
|
+
},
|
|
2034
|
+
],
|
|
2035
|
+
};
|
|
2036
|
+
}
|
|
2037
|
+
async handleGetImportStreamAnalytics(args) {
|
|
2038
|
+
const analytics = importService.getStreamAnalytics();
|
|
2039
|
+
const includeMonitors = args.includeActiveMonitors !== false; // Default to true
|
|
2040
|
+
let analyticsText = `**Import Streaming Analytics**\n\n` +
|
|
2041
|
+
`📊 **Overview**\n` +
|
|
2042
|
+
`• Total Imports: ${analytics.totalImports}\n` +
|
|
2043
|
+
`• Active Imports: ${analytics.activeImports}\n` +
|
|
2044
|
+
`• Completed Imports: ${analytics.completedImports}\n` +
|
|
2045
|
+
`• Failed Imports: ${analytics.failedImports}\n` +
|
|
2046
|
+
`• Average Import Time: ${Math.round(analytics.averageImportTime / 1000)}s\n` +
|
|
2047
|
+
`• Notifications Sent: ${analytics.notificationsSent}\n` +
|
|
2048
|
+
`• Errors Encountered: ${analytics.errorsEncountered}\n` +
|
|
2049
|
+
`• Last Activity: ${analytics.lastActivity}\n`;
|
|
2050
|
+
if (includeMonitors && analytics.activeStreams?.length > 0) {
|
|
2051
|
+
analyticsText += `\n🔄 **Active Monitors (${analytics.activeStreams.length})**\n`;
|
|
2052
|
+
analytics.activeStreams.forEach((stream, index) => {
|
|
2053
|
+
const elapsed = Math.round((Date.now() - stream.startTime) / 1000);
|
|
2054
|
+
analyticsText += `${index + 1}. **${stream.jobId}**\n` +
|
|
2055
|
+
` • Source Type: ${stream.sourceType}\n` +
|
|
2056
|
+
` • Source URL: ${stream.sourceUrl}\n` +
|
|
2057
|
+
` • Progress Token: ${stream.progressToken}\n` +
|
|
2058
|
+
` • Status: ${stream.status}\n` +
|
|
2059
|
+
` • Progress: ${stream.lastProgress}%\n` +
|
|
2060
|
+
` • Elapsed: ${elapsed}s\n\n`;
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
2063
|
+
else if (includeMonitors) {
|
|
2064
|
+
analyticsText += `\n✅ **No Active Monitors**\n`;
|
|
2065
|
+
}
|
|
2066
|
+
return {
|
|
2067
|
+
content: [
|
|
2068
|
+
{
|
|
2069
|
+
type: 'text',
|
|
2070
|
+
text: analyticsText,
|
|
2071
|
+
},
|
|
2072
|
+
],
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
2075
|
+
// Export Handler Methods
|
|
2076
|
+
async handleExportContainer(args) {
|
|
2077
|
+
const { progressToken, ...exportParams } = args;
|
|
2078
|
+
const result = await exportService.exportContainer(exportParams, progressToken);
|
|
2079
|
+
return {
|
|
2080
|
+
content: [
|
|
2081
|
+
{
|
|
2082
|
+
type: 'text',
|
|
2083
|
+
text: `Container export started successfully!\n\n` +
|
|
2084
|
+
`Job ID: ${result.jobId}\n` +
|
|
2085
|
+
`Container: ${result.containerName}\n` +
|
|
2086
|
+
`Destination Type: ${result.destinationType}\n` +
|
|
2087
|
+
`Status: ${result.status}\n` +
|
|
2088
|
+
`Token Cost: ${result.tokenCost}\n` +
|
|
2089
|
+
`${result.estimatedDuration ? `Estimated Duration: ${result.estimatedDuration}\n` : ''}` +
|
|
2090
|
+
`Created: ${result.createdAt}\n` +
|
|
2091
|
+
`${progressToken ? `\n🔄 Progress updates will be sent via notifications using token: ${progressToken}` : ''}`,
|
|
2092
|
+
},
|
|
2093
|
+
],
|
|
2094
|
+
};
|
|
2095
|
+
}
|
|
2096
|
+
async handleGetExportStatus(args) {
|
|
2097
|
+
const result = await exportService.getExportStatus(args.jobId);
|
|
2098
|
+
let statusText = `**Export Job Status**\n\n` +
|
|
2099
|
+
`Job ID: ${result.jobId}\n` +
|
|
2100
|
+
`Container: ${result.containerName}\n` +
|
|
2101
|
+
`Status: ${result.status}\n` +
|
|
2102
|
+
`Destination Type: ${result.destinationType}\n` +
|
|
2103
|
+
`Token Cost: ${result.tokenCost}\n` +
|
|
2104
|
+
`Created: ${result.createdAt}\n` +
|
|
2105
|
+
`${result.updatedAt ? `Updated: ${result.updatedAt}\n` : ''}` +
|
|
2106
|
+
`${result.completedAt ? `Completed: ${result.completedAt}\n` : ''}`;
|
|
2107
|
+
if (result.progress) {
|
|
2108
|
+
statusText += `\n**Progress**\n` +
|
|
2109
|
+
`Stage: ${result.progress.stage} (${result.progress.stageNumber}/${result.progress.totalStages})\n` +
|
|
2110
|
+
`Progress: ${result.progress.percent}%\n` +
|
|
2111
|
+
`Message: ${result.progress.message}\n`;
|
|
2112
|
+
}
|
|
2113
|
+
if (result.result) {
|
|
2114
|
+
statusText += `\n✅ **Export Result**:\n`;
|
|
2115
|
+
if (result.result.imageUrl) {
|
|
2116
|
+
statusText += ` • Image URL: ${result.result.imageUrl}\n`;
|
|
2117
|
+
statusText += ` • Digest: ${result.result.digest || 'N/A'}\n`;
|
|
2118
|
+
statusText += ` • Registry: ${result.result.registry || 'N/A'}\n`;
|
|
2119
|
+
}
|
|
2120
|
+
if (result.result.repositoryUrl) {
|
|
2121
|
+
statusText += ` • Repository: ${result.result.repositoryUrl}\n`;
|
|
2122
|
+
statusText += ` • Branch: ${result.result.branch || 'N/A'}\n`;
|
|
2123
|
+
statusText += ` • Commit: ${result.result.commit || 'N/A'}\n`;
|
|
2124
|
+
}
|
|
2125
|
+
if (result.result.downloadUrl) {
|
|
2126
|
+
statusText += ` • Download URL: ${result.result.downloadUrl}\n`;
|
|
2127
|
+
statusText += ` • Expires: ${result.result.expiresAt || 'N/A'}\n`;
|
|
2128
|
+
statusText += ` • Format: ${result.result.format || 'N/A'}\n`;
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
if (result.errors && result.errors.length > 0) {
|
|
2132
|
+
statusText += `\n❌ **Errors**:\n${result.errors.map(e => ` • ${e}`).join('\n')}\n`;
|
|
2133
|
+
}
|
|
2134
|
+
return {
|
|
2135
|
+
content: [
|
|
2136
|
+
{
|
|
2137
|
+
type: 'text',
|
|
2138
|
+
text: statusText,
|
|
2139
|
+
},
|
|
2140
|
+
],
|
|
2141
|
+
};
|
|
2142
|
+
}
|
|
2143
|
+
async handleListExportJobs(args) {
|
|
2144
|
+
const result = await exportService.listExportJobs(args);
|
|
2145
|
+
let listText = `**Export Jobs** (${result.exports.length} found)\n\n`;
|
|
2146
|
+
if (result.exports.length === 0) {
|
|
2147
|
+
listText += `No export jobs found.\n`;
|
|
2148
|
+
}
|
|
2149
|
+
else {
|
|
2150
|
+
result.exports.forEach((job, index) => {
|
|
2151
|
+
listText += `${index + 1}. **${job.jobId}**\n` +
|
|
2152
|
+
` • Container: ${job.containerName}\n` +
|
|
2153
|
+
` • Status: ${job.status}\n` +
|
|
2154
|
+
` • Destination: ${job.destinationType}\n` +
|
|
2155
|
+
` • Progress: ${job.progress.percent}%\n` +
|
|
2156
|
+
` • Created: ${job.createdAt}\n` +
|
|
2157
|
+
` ${job.errors && job.errors.length > 0 ? `• Errors: ${job.errors.length}\n` : ''}\n`;
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
if (result.pagination) {
|
|
2161
|
+
listText += `\n**Pagination**\n` +
|
|
2162
|
+
`• Showing: ${result.pagination.offset + 1}-${Math.min(result.pagination.offset + result.pagination.limit, result.pagination.total)}\n` +
|
|
2163
|
+
`• Total: ${result.pagination.total}\n` +
|
|
2164
|
+
`• Has More: ${result.pagination.hasMore ? 'Yes' : 'No'}\n`;
|
|
2165
|
+
}
|
|
2166
|
+
return {
|
|
2167
|
+
content: [
|
|
2168
|
+
{
|
|
2169
|
+
type: 'text',
|
|
2170
|
+
text: listText,
|
|
2171
|
+
},
|
|
2172
|
+
],
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
async handleGetExportDownloadUrl(args) {
|
|
2176
|
+
const result = await exportService.getExportDownloadUrl(args.jobId);
|
|
2177
|
+
return {
|
|
2178
|
+
content: [
|
|
2179
|
+
{
|
|
2180
|
+
type: 'text',
|
|
2181
|
+
text: `**Export Download URL**\n\n` +
|
|
2182
|
+
`Download URL: ${result.downloadUrl}\n` +
|
|
2183
|
+
`Expires: ${result.expiresAt}\n` +
|
|
2184
|
+
`Format: ${result.format}\n` +
|
|
2185
|
+
`Size: ${result.size} bytes\n`,
|
|
2186
|
+
},
|
|
2187
|
+
],
|
|
2188
|
+
};
|
|
2189
|
+
}
|
|
2190
|
+
async handleCancelExportJob(args) {
|
|
2191
|
+
const result = await exportService.cancelExportJob(args.jobId);
|
|
2192
|
+
return {
|
|
2193
|
+
content: [
|
|
2194
|
+
{
|
|
2195
|
+
type: 'text',
|
|
2196
|
+
text: `✅ Export job cancelled\n\n` +
|
|
2197
|
+
`Job ID: ${result.jobId}\n` +
|
|
2198
|
+
`Status: ${result.status}\n` +
|
|
2199
|
+
`Updated: ${result.updatedAt}`,
|
|
2200
|
+
},
|
|
2201
|
+
],
|
|
2202
|
+
};
|
|
2203
|
+
}
|
|
2204
|
+
async handleCancelExportMonitoring(args) {
|
|
2205
|
+
const success = await exportService.cancelExportMonitoring(args.progressToken, args.reason);
|
|
2206
|
+
return {
|
|
2207
|
+
content: [
|
|
2208
|
+
{
|
|
2209
|
+
type: 'text',
|
|
2210
|
+
text: success
|
|
2211
|
+
? `✅ Export monitoring cancelled for progress token: ${args.progressToken}\n${args.reason ? `Reason: ${args.reason}` : ''}`
|
|
2212
|
+
: `❌ No active monitoring found for progress token: ${args.progressToken}`,
|
|
2213
|
+
},
|
|
2214
|
+
],
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
async handleGetExportStreamAnalytics(args) {
|
|
2218
|
+
const analytics = exportService.getStreamAnalytics();
|
|
2219
|
+
const includeMonitors = args.includeActiveMonitors !== false; // Default to true
|
|
2220
|
+
let analyticsText = `**Export Streaming Analytics**\n\n` +
|
|
2221
|
+
`📊 **Overview**\n` +
|
|
2222
|
+
`• Total Exports: ${analytics.totalExports}\n` +
|
|
2223
|
+
`• Active Exports: ${analytics.activeExports}\n` +
|
|
2224
|
+
`• Completed Exports: ${analytics.completedExports}\n` +
|
|
2225
|
+
`• Failed Exports: ${analytics.failedExports}\n` +
|
|
2226
|
+
`• Average Export Time: ${Math.round(analytics.averageExportTime / 1000)}s\n` +
|
|
2227
|
+
`• Notifications Sent: ${analytics.notificationsSent}\n` +
|
|
2228
|
+
`• Errors Encountered: ${analytics.errorsEncountered}\n` +
|
|
2229
|
+
`• Last Activity: ${analytics.lastActivity}\n`;
|
|
2230
|
+
if (includeMonitors && analytics.activeStreams?.length > 0) {
|
|
2231
|
+
analyticsText += `\n🔄 **Active Monitors (${analytics.activeStreams.length})**\n`;
|
|
2232
|
+
analytics.activeStreams.forEach((stream, index) => {
|
|
2233
|
+
const elapsed = Math.round((Date.now() - stream.startTime) / 1000);
|
|
2234
|
+
analyticsText += `${index + 1}. **${stream.jobId}**\n` +
|
|
2235
|
+
` • Container: ${stream.containerName}\n` +
|
|
2236
|
+
` • Destination: ${stream.destinationType}\n` +
|
|
2237
|
+
` • Progress Token: ${stream.progressToken}\n` +
|
|
2238
|
+
` • Status: ${stream.status}\n` +
|
|
2239
|
+
` • Progress: ${stream.lastProgress}%\n` +
|
|
2240
|
+
` • Elapsed: ${elapsed}s\n\n`;
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
2243
|
+
else if (includeMonitors) {
|
|
2244
|
+
analyticsText += `\n✅ **No Active Monitors**\n`;
|
|
2245
|
+
}
|
|
2246
|
+
return {
|
|
2247
|
+
content: [
|
|
2248
|
+
{
|
|
2249
|
+
type: 'text',
|
|
2250
|
+
text: analyticsText,
|
|
2251
|
+
},
|
|
2252
|
+
],
|
|
2253
|
+
};
|
|
2254
|
+
}
|
|
2255
|
+
async handleGetExportProgressUpdate(args) {
|
|
2256
|
+
const update = exportService.getProgressUpdate(args.progressToken);
|
|
2257
|
+
if (!update) {
|
|
2258
|
+
return {
|
|
2259
|
+
content: [
|
|
2260
|
+
{
|
|
2261
|
+
type: 'text',
|
|
2262
|
+
text: `No progress update available for token: ${args.progressToken}`,
|
|
2263
|
+
},
|
|
2264
|
+
],
|
|
2265
|
+
};
|
|
2266
|
+
}
|
|
2267
|
+
return {
|
|
2268
|
+
content: [
|
|
2269
|
+
{
|
|
2270
|
+
type: 'text',
|
|
2271
|
+
text: `**Export Progress Update**\n\n` +
|
|
2272
|
+
`Progress Token: ${args.progressToken}\n` +
|
|
2273
|
+
`Status: ${update.status || 'unknown'}\n` +
|
|
2274
|
+
`Progress: ${update.progress || 0}%\n` +
|
|
2275
|
+
`Message: ${update.message || 'No message'}\n` +
|
|
2276
|
+
`Timestamp: ${update.timestamp || new Date().toISOString()}`,
|
|
2277
|
+
},
|
|
2278
|
+
],
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
1642
2281
|
async handleListContainerFiles(args) {
|
|
1643
|
-
const result = await
|
|
2282
|
+
const result = await fileService.listContainerFiles(args);
|
|
1644
2283
|
return {
|
|
1645
2284
|
content: [
|
|
1646
2285
|
{
|
|
@@ -1655,7 +2294,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1655
2294
|
};
|
|
1656
2295
|
}
|
|
1657
2296
|
async handleGetFileContent(args) {
|
|
1658
|
-
const result = await
|
|
2297
|
+
const result = await fileService.getFileContent(args);
|
|
1659
2298
|
return {
|
|
1660
2299
|
content: [
|
|
1661
2300
|
{
|
|
@@ -1671,7 +2310,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1671
2310
|
};
|
|
1672
2311
|
}
|
|
1673
2312
|
async handleUploadFile(args) {
|
|
1674
|
-
const result = await
|
|
2313
|
+
const result = await fileService.uploadFile(args);
|
|
1675
2314
|
return {
|
|
1676
2315
|
content: [
|
|
1677
2316
|
{
|
|
@@ -1686,7 +2325,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1686
2325
|
};
|
|
1687
2326
|
}
|
|
1688
2327
|
async handleUpdateFile(args) {
|
|
1689
|
-
const result = await
|
|
2328
|
+
const result = await fileService.updateFile(args);
|
|
1690
2329
|
return {
|
|
1691
2330
|
content: [
|
|
1692
2331
|
{
|
|
@@ -1701,7 +2340,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1701
2340
|
};
|
|
1702
2341
|
}
|
|
1703
2342
|
async handleDeleteFile(args) {
|
|
1704
|
-
const result = await
|
|
2343
|
+
const result = await fileService.deleteFile(args.containerId, args.filePath);
|
|
1705
2344
|
return {
|
|
1706
2345
|
content: [
|
|
1707
2346
|
{
|
|
@@ -1712,7 +2351,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1712
2351
|
};
|
|
1713
2352
|
}
|
|
1714
2353
|
async handleListCapabilities(args) {
|
|
1715
|
-
const result = await
|
|
2354
|
+
const result = await capabilityService.listCapabilities(args);
|
|
1716
2355
|
return {
|
|
1717
2356
|
content: [
|
|
1718
2357
|
{
|
|
@@ -1728,7 +2367,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1728
2367
|
};
|
|
1729
2368
|
}
|
|
1730
2369
|
async handleGetCapability(args) {
|
|
1731
|
-
const result = await
|
|
2370
|
+
const result = await capabilityService.getCapability(args);
|
|
1732
2371
|
return {
|
|
1733
2372
|
content: [
|
|
1734
2373
|
{
|
|
@@ -1746,7 +2385,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1746
2385
|
};
|
|
1747
2386
|
}
|
|
1748
2387
|
async handleSearchCapabilities(args) {
|
|
1749
|
-
const result = await
|
|
2388
|
+
const result = await capabilityService.searchCapabilities(args.query, args.category, args.limit);
|
|
1750
2389
|
return {
|
|
1751
2390
|
content: [
|
|
1752
2391
|
{
|
|
@@ -1762,7 +2401,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1762
2401
|
// Execution handler methods
|
|
1763
2402
|
async handleStartExecution(args) {
|
|
1764
2403
|
const { progressToken, ...executionParams } = args;
|
|
1765
|
-
const result = await
|
|
2404
|
+
const result = await executionService.startExecution(executionParams, progressToken);
|
|
1766
2405
|
return {
|
|
1767
2406
|
content: [
|
|
1768
2407
|
{
|
|
@@ -1781,7 +2420,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1781
2420
|
};
|
|
1782
2421
|
}
|
|
1783
2422
|
async handleStopExecution(args) {
|
|
1784
|
-
const result = await
|
|
2423
|
+
const result = await executionService.stopExecution(args);
|
|
1785
2424
|
return {
|
|
1786
2425
|
content: [
|
|
1787
2426
|
{
|
|
@@ -1794,7 +2433,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1794
2433
|
};
|
|
1795
2434
|
}
|
|
1796
2435
|
async handleGetExecutionStatus(args) {
|
|
1797
|
-
const result = await
|
|
2436
|
+
const result = await executionService.getExecutionStatus(args);
|
|
1798
2437
|
return {
|
|
1799
2438
|
content: [
|
|
1800
2439
|
{
|
|
@@ -1816,7 +2455,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1816
2455
|
};
|
|
1817
2456
|
}
|
|
1818
2457
|
async handleListExecutions(args) {
|
|
1819
|
-
const result = await
|
|
2458
|
+
const result = await executionService.listExecutions(args);
|
|
1820
2459
|
return {
|
|
1821
2460
|
content: [
|
|
1822
2461
|
{
|
|
@@ -1837,7 +2476,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1837
2476
|
};
|
|
1838
2477
|
}
|
|
1839
2478
|
async handleGetExecutionProgress(args) {
|
|
1840
|
-
const result = await
|
|
2479
|
+
const result = await executionService.getExecutionProgress(args);
|
|
1841
2480
|
return {
|
|
1842
2481
|
content: [
|
|
1843
2482
|
{
|
|
@@ -1855,7 +2494,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1855
2494
|
};
|
|
1856
2495
|
}
|
|
1857
2496
|
async handleGetExecutionLogs(args) {
|
|
1858
|
-
const result = await
|
|
2497
|
+
const result = await executionService.getExecutionLogs(args);
|
|
1859
2498
|
// Format logs properly - handle both string logs and log objects
|
|
1860
2499
|
const formatLog = (log, index) => {
|
|
1861
2500
|
if (typeof log === 'string') {
|
|
@@ -1892,7 +2531,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1892
2531
|
};
|
|
1893
2532
|
}
|
|
1894
2533
|
async handleExplainRuntimeLogs(args) {
|
|
1895
|
-
const result = await
|
|
2534
|
+
const result = await executionService.explainRuntimeLogs(args.executionId, {
|
|
1896
2535
|
verbosity: args.verbosity,
|
|
1897
2536
|
outputFormat: args.outputFormat,
|
|
1898
2537
|
includeContext: args.includeContext,
|
|
@@ -1917,7 +2556,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1917
2556
|
};
|
|
1918
2557
|
}
|
|
1919
2558
|
async handleExplainDeploymentLogs(args) {
|
|
1920
|
-
const result = await
|
|
2559
|
+
const result = await executionService.explainDeploymentLogs(args.executionId, {
|
|
1921
2560
|
verbosity: args.verbosity,
|
|
1922
2561
|
outputFormat: args.outputFormat,
|
|
1923
2562
|
includeContext: args.includeContext,
|
|
@@ -1941,7 +2580,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1941
2580
|
};
|
|
1942
2581
|
}
|
|
1943
2582
|
async handleExtendExecution(args) {
|
|
1944
|
-
const result = await
|
|
2583
|
+
const result = await executionService.extendExecution(args);
|
|
1945
2584
|
return {
|
|
1946
2585
|
content: [
|
|
1947
2586
|
{
|
|
@@ -1954,7 +2593,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1954
2593
|
};
|
|
1955
2594
|
}
|
|
1956
2595
|
async handleGetExecutionHistory(args) {
|
|
1957
|
-
const result = await
|
|
2596
|
+
const result = await executionService.getExecutionHistory(args.containerId, args.limit);
|
|
1958
2597
|
return {
|
|
1959
2598
|
content: [
|
|
1960
2599
|
{
|
|
@@ -1974,7 +2613,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1974
2613
|
};
|
|
1975
2614
|
}
|
|
1976
2615
|
async handleGetCostEstimate(args) {
|
|
1977
|
-
const result = await
|
|
2616
|
+
const result = await executionService.getCostEstimate(args);
|
|
1978
2617
|
return {
|
|
1979
2618
|
content: [
|
|
1980
2619
|
{
|
|
@@ -1998,7 +2637,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
1998
2637
|
};
|
|
1999
2638
|
}
|
|
2000
2639
|
async handleGetExtensionCostEstimate(args) {
|
|
2001
|
-
const result = await
|
|
2640
|
+
const result = await executionService.getExtensionCostEstimate(args);
|
|
2002
2641
|
return {
|
|
2003
2642
|
content: [
|
|
2004
2643
|
{
|
|
@@ -2021,7 +2660,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
2021
2660
|
};
|
|
2022
2661
|
}
|
|
2023
2662
|
async handleGetContainerMetrics(args) {
|
|
2024
|
-
const metrics = await
|
|
2663
|
+
const metrics = await executionService.getExecutionMetrics(args);
|
|
2025
2664
|
const formatMetric = (value, unit = '') => {
|
|
2026
2665
|
return value !== null ? `${value}${unit}` : 'N/A';
|
|
2027
2666
|
};
|
|
@@ -2059,7 +2698,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
2059
2698
|
};
|
|
2060
2699
|
}
|
|
2061
2700
|
async handleCancelExecutionMonitoring(args) {
|
|
2062
|
-
const success = await
|
|
2701
|
+
const success = await executionService.cancelExecutionMonitoring(args.progressToken, args.reason);
|
|
2063
2702
|
return {
|
|
2064
2703
|
content: [
|
|
2065
2704
|
{
|
|
@@ -2072,7 +2711,7 @@ Follow same metadata requirements as create_container.`,
|
|
|
2072
2711
|
};
|
|
2073
2712
|
}
|
|
2074
2713
|
async handleGetExecutionStreamAnalytics(args) {
|
|
2075
|
-
const analytics =
|
|
2714
|
+
const analytics = executionService.getExecutionStreamAnalytics();
|
|
2076
2715
|
const includeMonitors = args.includeActiveMonitors !== false; // Default to true
|
|
2077
2716
|
let analyticsText = `**Execution Streaming Analytics**\n\n` +
|
|
2078
2717
|
`📊 **Overview**\n` +
|
|
@@ -2115,9 +2754,9 @@ Follow same metadata requirements as create_container.`,
|
|
|
2115
2754
|
async handleGetBuildProgressUpdate(args) {
|
|
2116
2755
|
const { progressToken } = args;
|
|
2117
2756
|
if (!progressToken) {
|
|
2118
|
-
throw
|
|
2757
|
+
throw ErrorHandler.createValidationError('Progress token is required');
|
|
2119
2758
|
}
|
|
2120
|
-
const progressUpdate =
|
|
2759
|
+
const progressUpdate = buildService.getProgressUpdate(progressToken);
|
|
2121
2760
|
if (!progressUpdate) {
|
|
2122
2761
|
return {
|
|
2123
2762
|
content: [
|
|
@@ -2148,9 +2787,9 @@ Follow same metadata requirements as create_container.`,
|
|
|
2148
2787
|
async handleGetExecutionProgressUpdate(args) {
|
|
2149
2788
|
const { progressToken } = args;
|
|
2150
2789
|
if (!progressToken) {
|
|
2151
|
-
throw
|
|
2790
|
+
throw ErrorHandler.createValidationError('Progress token is required');
|
|
2152
2791
|
}
|
|
2153
|
-
const progressUpdate =
|
|
2792
|
+
const progressUpdate = executionService.getProgressUpdate(progressToken);
|
|
2154
2793
|
if (!progressUpdate) {
|
|
2155
2794
|
return {
|
|
2156
2795
|
content: [
|
|
@@ -2179,8 +2818,8 @@ Follow same metadata requirements as create_container.`,
|
|
|
2179
2818
|
* Get all progress updates for debugging
|
|
2180
2819
|
*/
|
|
2181
2820
|
async handleGetAllProgressUpdates(args) {
|
|
2182
|
-
const buildUpdates =
|
|
2183
|
-
const executionUpdates =
|
|
2821
|
+
const buildUpdates = buildService.getAllProgressUpdates();
|
|
2822
|
+
const executionUpdates = executionService.getAllProgressUpdates();
|
|
2184
2823
|
let responseText = `**All Progress Updates**\n\n`;
|
|
2185
2824
|
const buildTokens = Object.keys(buildUpdates);
|
|
2186
2825
|
const executionTokens = Object.keys(executionUpdates);
|
|
@@ -2735,24 +3374,24 @@ Follow these best practices to create robust, secure, and efficient containerize
|
|
|
2735
3374
|
try {
|
|
2736
3375
|
// Test authentication
|
|
2737
3376
|
console.error('🔑 Testing authentication...');
|
|
2738
|
-
const isAuthenticated = await
|
|
3377
|
+
const isAuthenticated = await authManager.testAuthentication();
|
|
2739
3378
|
if (!isAuthenticated) {
|
|
2740
3379
|
throw new Error('Authentication failed. Please check your API credentials.');
|
|
2741
3380
|
}
|
|
2742
3381
|
console.error('✅ Authentication successful');
|
|
2743
3382
|
// Start the server
|
|
2744
|
-
const transport = new
|
|
3383
|
+
const transport = new StdioServerTransport();
|
|
2745
3384
|
await this.server.connect(transport);
|
|
2746
3385
|
// Set up graceful shutdown to cleanup streaming connections
|
|
2747
3386
|
process.on('SIGINT', () => this.shutdown('SIGINT'));
|
|
2748
3387
|
process.on('SIGTERM', () => this.shutdown('SIGTERM'));
|
|
2749
3388
|
console.error('🚀 172.ai Container MCP Server started successfully');
|
|
2750
|
-
console.error(`📋 Configuration: ${
|
|
3389
|
+
console.error(`📋 Configuration: ${config.get('baseUrl')} (${config.get('environment')})`);
|
|
2751
3390
|
console.error('🔧 Available tools: container management, builds, files, capabilities, executions');
|
|
2752
3391
|
}
|
|
2753
3392
|
catch (error) {
|
|
2754
|
-
const processedError =
|
|
2755
|
-
|
|
3393
|
+
const processedError = ErrorHandler.processError(error, 'Server startup');
|
|
3394
|
+
ErrorHandler.logError(processedError);
|
|
2756
3395
|
console.error('❌ Failed to start MCP server:', processedError.message);
|
|
2757
3396
|
process.exit(1);
|
|
2758
3397
|
}
|
|
@@ -2764,7 +3403,7 @@ Follow these best practices to create robust, secure, and efficient containerize
|
|
|
2764
3403
|
console.error(`[MCP Server] Received ${signal}, shutting down gracefully...`);
|
|
2765
3404
|
try {
|
|
2766
3405
|
// Disconnect from all streaming channels
|
|
2767
|
-
await
|
|
3406
|
+
await streamingService.disconnect();
|
|
2768
3407
|
console.error('[MCP Server] ✅ Streaming connections closed');
|
|
2769
3408
|
// Close server
|
|
2770
3409
|
await this.server.close();
|
|
@@ -2777,5 +3416,6 @@ Follow these best practices to create robust, secure, and efficient containerize
|
|
|
2777
3416
|
}
|
|
2778
3417
|
}
|
|
2779
3418
|
}
|
|
2780
|
-
|
|
3419
|
+
// Note: Server startup is now handled by cli.ts
|
|
3420
|
+
export { ContainerMCPServer };
|
|
2781
3421
|
//# sourceMappingURL=server.js.map
|