@aithr-ai/mcp-server 1.0.14 → 1.0.16
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/index.js +121 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -583,6 +583,33 @@ class MCPServer {
|
|
|
583
583
|
required: ['targetPath'],
|
|
584
584
|
},
|
|
585
585
|
},
|
|
586
|
+
{
|
|
587
|
+
name: 'aether_download_zip',
|
|
588
|
+
description: 'Download all project artifacts as a ZIP file to a local path. Extracts code files from artifacts and saves them in proper directory structure.',
|
|
589
|
+
inputSchema: {
|
|
590
|
+
type: 'object',
|
|
591
|
+
properties: {
|
|
592
|
+
targetPath: {
|
|
593
|
+
type: 'string',
|
|
594
|
+
description: 'Full path where to save the ZIP file (e.g., C:/Users/you/Downloads/project.zip)',
|
|
595
|
+
},
|
|
596
|
+
extractCode: {
|
|
597
|
+
type: 'boolean',
|
|
598
|
+
description: 'Extract code files from artifacts (default: true)',
|
|
599
|
+
},
|
|
600
|
+
includeRaw: {
|
|
601
|
+
type: 'boolean',
|
|
602
|
+
description: 'Include raw artifact markdown files (default: false)',
|
|
603
|
+
},
|
|
604
|
+
artifactIds: {
|
|
605
|
+
type: 'array',
|
|
606
|
+
items: { type: 'string' },
|
|
607
|
+
description: 'Specific artifact IDs to include (optional, includes all if not provided)',
|
|
608
|
+
},
|
|
609
|
+
},
|
|
610
|
+
required: ['targetPath'],
|
|
611
|
+
},
|
|
612
|
+
},
|
|
586
613
|
// =========================================================================
|
|
587
614
|
// Canvas Folder Tools
|
|
588
615
|
// =========================================================================
|
|
@@ -1095,6 +1122,9 @@ class MCPServer {
|
|
|
1095
1122
|
case 'aether_write_local':
|
|
1096
1123
|
result = await this.writeLocal(args);
|
|
1097
1124
|
break;
|
|
1125
|
+
case 'aether_download_zip':
|
|
1126
|
+
result = await this.downloadZip(args);
|
|
1127
|
+
break;
|
|
1098
1128
|
// Canvas Folder Tools
|
|
1099
1129
|
case 'aether_list_folders':
|
|
1100
1130
|
result = await this.listFolders(args);
|
|
@@ -2298,6 +2328,97 @@ class MCPServer {
|
|
|
2298
2328
|
}
|
|
2299
2329
|
}
|
|
2300
2330
|
|
|
2331
|
+
/**
|
|
2332
|
+
* Download all project artifacts as a ZIP file to a local path
|
|
2333
|
+
*/
|
|
2334
|
+
async downloadZip(args) {
|
|
2335
|
+
const projectId = config.projectId;
|
|
2336
|
+
|
|
2337
|
+
if (!projectId) {
|
|
2338
|
+
return { error: 'No project ID configured. Set AETHER_PROJECT_ID environment variable.' };
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
const {
|
|
2342
|
+
targetPath,
|
|
2343
|
+
extractCode = true,
|
|
2344
|
+
includeRaw = false,
|
|
2345
|
+
artifactIds,
|
|
2346
|
+
} = args;
|
|
2347
|
+
|
|
2348
|
+
if (!targetPath) {
|
|
2349
|
+
return { error: 'targetPath is required - specify where to save the ZIP file (e.g., C:/Users/you/Downloads/project.zip)' };
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
// Ensure targetPath ends with .zip
|
|
2353
|
+
const zipPath = targetPath.endsWith('.zip') ? targetPath : `${targetPath}.zip`;
|
|
2354
|
+
|
|
2355
|
+
try {
|
|
2356
|
+
// Build query string
|
|
2357
|
+
const params = new URLSearchParams();
|
|
2358
|
+
params.set('extractCode', String(extractCode));
|
|
2359
|
+
params.set('includeRaw', String(includeRaw));
|
|
2360
|
+
if (artifactIds && artifactIds.length > 0) {
|
|
2361
|
+
params.set('artifactIds', artifactIds.join(','));
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
// Fetch the ZIP from the download endpoint
|
|
2365
|
+
const url = `${config.apiBaseUrl}/api/workspaces/${config.workspaceSlug}/projects/${projectId}/artifacts/download?${params.toString()}`;
|
|
2366
|
+
|
|
2367
|
+
const response = await fetch(url, {
|
|
2368
|
+
headers: {
|
|
2369
|
+
'Authorization': `Bearer ${config.apiKey}`,
|
|
2370
|
+
},
|
|
2371
|
+
});
|
|
2372
|
+
|
|
2373
|
+
if (!response.ok) {
|
|
2374
|
+
const errorText = await response.text();
|
|
2375
|
+
let errorMessage;
|
|
2376
|
+
try {
|
|
2377
|
+
const errorJson = JSON.parse(errorText);
|
|
2378
|
+
errorMessage = errorJson.error || 'Failed to download ZIP';
|
|
2379
|
+
} catch {
|
|
2380
|
+
errorMessage = errorText || 'Failed to download ZIP';
|
|
2381
|
+
}
|
|
2382
|
+
return { error: errorMessage };
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
// Get file info from headers
|
|
2386
|
+
const fileCount = response.headers.get('X-File-Count') || '0';
|
|
2387
|
+
const artifactCount = response.headers.get('X-Artifact-Count') || '0';
|
|
2388
|
+
|
|
2389
|
+
// Get the ZIP data
|
|
2390
|
+
const zipBuffer = await response.arrayBuffer();
|
|
2391
|
+
|
|
2392
|
+
// Ensure the directory exists
|
|
2393
|
+
const path = await import('path');
|
|
2394
|
+
const fs = await import('fs');
|
|
2395
|
+
const dir = path.dirname(zipPath);
|
|
2396
|
+
|
|
2397
|
+
if (!fs.existsSync(dir)) {
|
|
2398
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
// Write the ZIP file
|
|
2402
|
+
fs.writeFileSync(zipPath, Buffer.from(zipBuffer));
|
|
2403
|
+
|
|
2404
|
+
const stats = fs.statSync(zipPath);
|
|
2405
|
+
|
|
2406
|
+
return {
|
|
2407
|
+
success: true,
|
|
2408
|
+
path: zipPath,
|
|
2409
|
+
size: stats.size,
|
|
2410
|
+
sizeFormatted: stats.size > 1024 * 1024
|
|
2411
|
+
? `${(stats.size / (1024 * 1024)).toFixed(2)} MB`
|
|
2412
|
+
: `${(stats.size / 1024).toFixed(2)} KB`,
|
|
2413
|
+
fileCount: parseInt(fileCount, 10),
|
|
2414
|
+
artifactCount: parseInt(artifactCount, 10),
|
|
2415
|
+
message: `ZIP file saved to ${zipPath} (${fileCount} files from ${artifactCount} artifacts)`,
|
|
2416
|
+
};
|
|
2417
|
+
} catch (e) {
|
|
2418
|
+
return { error: e.message };
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2301
2422
|
/**
|
|
2302
2423
|
* Write files directly to local disk (runs in MCP server, not Vercel)
|
|
2303
2424
|
* Fetches files from generatedFiles API in batches and writes them locally
|