Skip to main content
Glama

1MCP Server

backups.ts7.6 kB
import { cleanupOldBackups, findBackupByMetaPath, listAppBackups, verifyBackupIntegrity, } from '@src/domains/backup/backupManager.js'; import { getAppPreset } from '@src/domains/discovery/appPresets.js'; import { GlobalOptions } from '@src/globalOptions.js'; import type { Argv } from 'yargs'; /** * Backups command - Manage and list backup files. * * Provides backup management functionality including listing, * verification, and cleanup of old backup files. */ interface BackupsOptions extends GlobalOptions { 'app-name'?: string; cleanup?: number; verify: boolean; } /** * Build the backups command configuration */ export function buildBackupsCommand(yargs: Argv) { return yargs .positional('app-name', { describe: 'Show backups for specific app only', type: 'string', }) .option('cleanup', { describe: 'Remove backups older than specified days', type: 'number', }) .option('verify', { describe: 'Verify backup file integrity', type: 'boolean', default: false, }) .example([ ['$0 app backups', 'List all available backups'], ['$0 app backups claude-desktop', 'List backups for specific app'], ['$0 app backups --cleanup=30', 'Remove backups older than 30 days'], ['$0 app backups --verify', 'Verify backup integrity'], ]); } /** * Main backups command handler */ export async function backupsCommand(options: BackupsOptions): Promise<void> { console.log('💾 MCP Configuration Backup Management\n'); // Cleanup mode if (options.cleanup !== undefined) { await cleanupBackups(options.cleanup); return; } // List and optionally verify backups await listBackupsWithDetails(options['app-name'], options.verify); } /** * List backups with detailed information */ async function listBackupsWithDetails(appName?: string, verify: boolean = false): Promise<void> { const backups = listAppBackups(appName); if (backups.length === 0) { if (appName) { console.log(`📭 No backups found for ${appName}.`); } else { console.log('📭 No backups found.'); } console.log('\n💡 Backups are created automatically during consolidation.'); return; } if (appName) { const preset = getAppPreset(appName); console.log(`📋 Backups for ${preset?.displayName || appName}:\n`); } else { console.log('📋 All Available Backups:\n'); } // Group by application const groupedBackups = backups.reduce( (groups, backup) => { if (!groups[backup.app]) { groups[backup.app] = []; } groups[backup.app].push(backup); return groups; }, {} as Record<string, typeof backups>, ); let totalSize = 0; let verifiedCount = 0; let corruptedCount = 0; for (const [app, appBackups] of Object.entries(groupedBackups)) { const preset = getAppPreset(app); console.log(`📱 ${preset?.displayName || app} (${app}):`); for (const backup of appBackups) { const backupInfo = findBackupByMetaPath(backup.metaPath); console.log(` 🕐 ${backup.age} - ${backup.operation} operation`); console.log(` 📁 ${backup.backupPath}`); console.log(` 🔧 ${backup.serverCount} servers backed up`); if (backupInfo) { const fileSizeKB = Math.round(backupInfo.metadata.fileSize / 1024); totalSize += backupInfo.metadata.fileSize; console.log(` 📊 Size: ${fileSizeKB} KB`); // Verify integrity if requested if (verify) { const isValid = verifyBackupIntegrity(backupInfo); if (isValid) { console.log(` ✅ Integrity: Valid`); verifiedCount++; } else { console.log(` ❌ Integrity: Corrupted`); corruptedCount++; } } } console.log(` 📝 Metadata: ${backup.metaPath}`); console.log(); } } // Summary const totalSizeMB = Math.round((totalSize / (1024 * 1024)) * 100) / 100; console.log('📊 Backup Summary:'); console.log(` 📦 Total backups: ${backups.length}`); console.log(` 📱 Applications: ${Object.keys(groupedBackups).length}`); console.log(` 💽 Total size: ${totalSizeMB} MB`); if (verify) { console.log(` ✅ Verified: ${verifiedCount}`); if (corruptedCount > 0) { console.log(` ❌ Corrupted: ${corruptedCount}`); } } // Show oldest and newest if (backups.length > 1) { const oldest = backups[backups.length - 1]; const newest = backups[0]; console.log(` 🕐 Oldest: ${oldest.age} (${getAppPreset(oldest.app)?.displayName || oldest.app})`); console.log(` 🕐 Newest: ${newest.age} (${getAppPreset(newest.app)?.displayName || newest.app})`); } // Usage recommendations console.log('\n💡 Management Commands:'); console.log(' 📋 List app backups: npx @1mcp/agent app backups <app-name>'); console.log(' 🔍 Verify integrity: npx @1mcp/agent app backups --verify'); console.log(' 🧹 Cleanup old: npx @1mcp/agent app backups --cleanup=30'); console.log(' 🔄 Restore: npx @1mcp/agent app restore <app-name>'); if (corruptedCount > 0) { console.log('\n⚠️ Warning: Some backups failed integrity verification.'); console.log(' Consider creating fresh backups for affected applications.'); } } /** * Cleanup old backups */ async function cleanupBackups(maxAgeDays: number): Promise<void> { console.log(`🧹 Cleaning up backups older than ${maxAgeDays} days...\n`); if (maxAgeDays < 1) { console.error('❌ Invalid age: must be at least 1 day.'); process.exit(1); } // Show what will be deleted first const allBackups = listAppBackups(); const cutoffTime = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000; const oldBackups = allBackups.filter((backup) => backup.timestamp < cutoffTime); if (oldBackups.length === 0) { console.log(`✅ No backups older than ${maxAgeDays} days found.`); return; } console.log(`📋 Found ${oldBackups.length} backups to delete:\n`); const groupedOld = oldBackups.reduce( (groups, backup) => { if (!groups[backup.app]) { groups[backup.app] = []; } groups[backup.app].push(backup); return groups; }, {} as Record<string, typeof oldBackups>, ); Object.entries(groupedOld).forEach(([app, appBackups]) => { const preset = getAppPreset(app); console.log(`📱 ${preset?.displayName || app}: ${appBackups.length} backups`); appBackups.forEach((backup) => { console.log(` 🕐 ${backup.age} - ${backup.operation}`); }); }); // Perform cleanup console.log('\n🗑️ Deleting old backups...'); const deletedCount = cleanupOldBackups(maxAgeDays); if (deletedCount > 0) { console.log(`✅ Successfully deleted ${deletedCount} old backups.`); // Show remaining backups const remainingBackups = listAppBackups(); console.log(`📦 Remaining backups: ${remainingBackups.length}`); if (remainingBackups.length > 0) { const totalSize = remainingBackups.reduce((sum, backup) => { const backupInfo = findBackupByMetaPath(backup.metaPath); return sum + (backupInfo?.metadata.fileSize || 0); }, 0); const totalSizeMB = Math.round((totalSize / (1024 * 1024)) * 100) / 100; console.log(`💽 Total size: ${totalSizeMB} MB`); } } else { console.log('⚠️ No backups were deleted (they may have been removed already).'); } console.log('\n💡 To see remaining backups: npx @1mcp/agent app backups'); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/1mcp-app/agent'

If you have feedback or need assistance with the MCP directory API, please join our Discord server