compareBackups
Compare two Heptabase backups by providing backup IDs to analyze differences, enabling users to identify changes and export results for further review.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| backupId1 | Yes | ||
| backupId2 | Yes | ||
| exportPath | No | ||
| whiteboardId | No |
Implementation Reference
- src/tools/analysis.ts:110-219 (handler)Core handler function that implements the compareBackups tool logic: loads two backups, compares data (optionally per whiteboard), calculates differences in counts of whiteboards/cards/connections, formats text output, and optionally exports JSON.export async function compareBackups( dataService: HeptabaseDataService, backupManager: BackupManager, params: z.infer<typeof compareBackupsSchema> ) { // Get backup metadata const backup1 = await backupManager.getBackupMetadata(params.backupId1); const backup2 = await backupManager.getBackupMetadata(params.backupId2); if (!backup1 || !backup2) { throw new Error('One or both backups not found'); } // Load the first backup await backupManager.loadBackup(backup1.backupPath); let data1: any; let data2: any; if (params.whiteboardId) { // Compare specific whiteboard data1 = await dataService.getWhiteboard(params.whiteboardId, { includeCards: true, includeConnections: true }); // Load the second backup await backupManager.loadBackup(backup2.backupPath); data2 = await dataService.getWhiteboard(params.whiteboardId, { includeCards: true, includeConnections: true }); } else { // Compare entire backups data1 = { whiteboards: await dataService.getWhiteboards(), cards: await dataService.getCards(), connections: await dataService.getConnections() }; // Load the second backup await backupManager.loadBackup(backup2.backupPath); data2 = { whiteboards: await dataService.getWhiteboards(), cards: await dataService.getCards(), connections: await dataService.getConnections() }; } // Calculate differences const comparison = { timestamp: new Date().toISOString(), backup1: { id: backup1.backupId, date: backup1.createdDate, size: backup1.fileSize }, backup2: { id: backup2.backupId, date: backup2.createdDate, size: backup2.fileSize }, changes: {} as any }; if (params.whiteboardId) { comparison.changes = { whiteboard: params.whiteboardId, cardsAdded: data2.cards.length - data1.cards.length, connectionsAdded: data2.connections.length - data1.connections.length }; } else { comparison.changes = { whiteboardsAdded: data2.whiteboards.length - data1.whiteboards.length, cardsAdded: data2.cards.length - data1.cards.length, connectionsAdded: data2.connections.length - data1.connections.length }; } // Format response let text = 'Comparison Results\n\n'; text += `Backup 1: ${backup1.backupId} (${backup1.createdDate})\n`; text += `Backup 2: ${backup2.backupId} (${backup2.createdDate})\n\n`; if (params.whiteboardId) { text += `Whiteboard: ${data1.whiteboard.name}\n`; text += `Added: ${comparison.changes.cardsAdded} cards\n`; text += `Added: ${comparison.changes.connectionsAdded} connections\n`; } else { text += `Added: ${comparison.changes.whiteboardsAdded} whiteboards\n`; text += `Added: ${comparison.changes.cardsAdded} cards\n`; text += `Added: ${comparison.changes.connectionsAdded} connections\n`; } // Export if requested if (params.exportPath) { await fs.mkdir(path.dirname(params.exportPath), { recursive: true }); await fs.writeFile(params.exportPath, JSON.stringify(comparison, null, 2), 'utf8'); text += `\nComparison saved to ${params.exportPath}`; } return { content: [{ type: 'text', text }] }; }
- src/tools/analysis.ts:13-18 (schema)Zod schema defining input parameters for compareBackups: required backup IDs, optional whiteboard ID for focused comparison, optional export path.export const compareBackupsSchema = z.object({ backupId1: z.string(), backupId2: z.string(), whiteboardId: z.string().optional(), exportPath: z.string().optional() });
- src/server.ts:714-727 (registration)Registers the compareBackups tool with MCP server: defines internal tool handler wrapper (checks services, calls implementation), and registers with server.tool using schema shape.// compareBackups tool this.tools.compareBackups = { inputSchema: compareBackupsSchema, handler: async (params) => { if (!this.dataService || !this.backupManager) { throw new Error('Services not initialized. Please configure backup path first.'); } return compareBackups(this.dataService, this.backupManager, params); } }; this.server.tool('compareBackups', compareBackupsSchema.shape, async (params: z.infer<typeof compareBackupsSchema>) => { return this.tools.compareBackups.handler(params); });
- src/server.ts:699-700 (registration)Import statement that brings in the compareBackups function and schema from analysis.ts for use in server registration.const { analyzeGraph, compareBackups, analyzeGraphSchema, compareBackupsSchema } = require('./tools/analysis');