Skip to main content
Glama

undo

Restore previous file states by undoing the latest checkpoint. Repeatedly invoke to step back through changes, enabling safe experimentation with AI-driven edits in Claude Code.

Instructions

Undo the last checkpoint (pops from stack and restores files). Each call removes the latest checkpoint from the stack. To undo multiple changes, call this function repeatedly until the desired state is reached.

Input Schema

NameRequiredDescriptionDefault

No arguments

Input Schema (JSON Schema)

{ "properties": {}, "type": "object" }

Implementation Reference

  • Core implementation of the undo tool. Pops the latest checkpoint from the stack, restores the contents of modified files to their checkpoint state, deletes files created after the checkpoint, handles partial failures by restoring the checkpoint, and returns success status with restored files list.
    async undo(): Promise<{ success: boolean; message?: string; restoredFiles?: string[]; description?: string; }> { // Deduplicate checkpoints before proceeding this.deduplicateCheckpoints(); if (this.undoStack.length === 0) { return { success: false, message: "No checkpoints to undo" }; } const checkpoint = this.undoStack.pop()!; const restoredFiles: string[] = []; const errors: string[] = []; console.error(`[DEBUG] Starting undo for checkpoint: ${checkpoint.description}`); console.error(`[DEBUG] Files to restore: ${Array.from(checkpoint.files.keys()).join(', ')}`); console.error(`[DEBUG] Files to remove: ${Array.from(checkpoint.createdFiles).join(', ') || 'none'}`); try { // First, restore existing files for (const [filepath, content] of checkpoint.files.entries()) { try { console.error(`[DEBUG] Restoring file: ${filepath}`); console.error(`[DEBUG] Content length: ${content.length}`); // If file doesn't exist, it was deleted - restore it const wasDeleted = !existsSync(filepath); if (wasDeleted) { console.error(`[DEBUG] File was deleted, restoring: ${filepath}`); // Ensure directory exists before creating file const dir = dirname(filepath); if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }); } } writeFileSync(filepath, content, "utf-8"); restoredFiles.push(wasDeleted ? `${filepath} (restored from deletion)` : filepath); console.error(`[DEBUG] Successfully restored: ${filepath}`); } catch (fileError) { const errorMsg = `Failed to restore ${filepath}: ${fileError}`; errors.push(errorMsg); console.error(`[DEBUG] Error restoring ${filepath}:`, fileError); console.error(`[DEBUG] Full error details:`, { filepath, contentLength: content.length, fileExists: existsSync(filepath), dirExists: existsSync(dirname(filepath)), error: fileError }); } } // Then, remove files that were created (undo file creation) for (const filepath of checkpoint.createdFiles) { try { console.error(`[DEBUG] Removing created file: ${filepath}`); if (existsSync(filepath)) { unlinkSync(filepath); restoredFiles.push(`${filepath} (deleted)`); console.error(`[DEBUG] Successfully removed: ${filepath}`); } else { console.error(`[DEBUG] Created file ${filepath} already doesn't exist`); } } catch (fileError) { errors.push(`Failed to remove created file ${filepath}: ${fileError}`); console.error(`[DEBUG] Error removing ${filepath}:`, fileError); } } if (errors.length > 0) { // Put checkpoint back if any files failed this.undoStack.push(checkpoint); return { success: false, message: `Some files failed to restore: ${errors.join('; ')}`, }; } console.error(`[DEBUG] Undo completed successfully. Restored ${restoredFiles.length} files`); return { success: true, restoredFiles, description: checkpoint.description, }; } catch (error) { // Put checkpoint back if restore failed this.undoStack.push(checkpoint); console.error(`[DEBUG] Undo failed with error:`, error); return { success: false, message: `Failed to restore checkpoint: ${error}`, }; } }
  • src/index.ts:45-52 (registration)
    Registers the 'undo' tool in the server's TOOLS list, providing name, description, and input schema for the MCP ListToolsRequest.
    { name: "undo", description: "Undo the last checkpoint (pops from stack and restores files). Each call removes the latest checkpoint from the stack. To undo multiple changes, call this function repeatedly until the desired state is reached.", inputSchema: { type: "object", properties: {}, }, },
  • Server-side handler for CallToolRequest of 'undo': invokes changeTracker.undo() and formats the MCP response with success message and list of restored files.
    case "undo": { const result = await changeTracker.undo(); return { content: [ { type: "text", text: result.success ? `✅ Undone: "${result.description}"\nRestored files:\n${result.restoredFiles?.map(f => ` - ${f}`).join('\n')}` : result.message || "Failed to undo", }, ], }; }
  • Defines the input schema for the 'undo' tool, which requires no parameters (empty properties).
    inputSchema: { type: "object", properties: {}, },
  • Type definition for UndoCheckpoint, which stores file states (contents, created files) for each undoable state.
    interface UndoCheckpoint { files: Map<string, string>; // filepath -> content createdFiles: Set<string>; // files that were created (didn't exist before) timestamp: Date; description: string; }

Other Tools

Related Tools

Latest Blog Posts

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/khalilbalaree/undo-mcp'

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