undo
Reverts recent editing operations in Markdown documents to correct mistakes or restore previous content states.
Instructions
Reverts the last N operations on the document.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| file_path | Yes | ||
| count | No |
Implementation Reference
- src/markdown_editor/server.py:357-380 (registration)MCP tool registration for 'undo' including input schema (file_path required, count optional) and output schema.Tool( name="undo", title="Undo Last Changes", description="Reverts the last N operations on the document.", inputSchema={ "type": "object", "properties": { "file_path": {"type": "string", "examples": ["./document.md"]}, "count": {"type": "integer", "default": 1, "examples": [1, 2, 5]}, }, "required": ["file_path"], "additionalProperties": False, }, outputSchema={ "type": "object", "properties": { "success": {"type": "boolean"}, "reverted_count": { "type": "integer", "description": "Number of operations reverted", }, }, }, ),
- src/markdown_editor/server.py:645-651 (handler)Dispatch logic in MCP server's call_tool method for the 'undo' tool.elif name == "undo": res = await undo_changes(file_path, arguments.get("count", 1)) return CallToolResult( content=[TextContent(type="text", text="Undo performed")], structuredContent=res, isError="error" in res, )
- Exported async handler function 'undo_changes' called by the MCP server for 'undo' tool invocations.async def undo_changes(file_path: str, count: int = 1): return await _instance.undo(file_path, count)
- EditTool.undo method: handles file locking, invokes Document.undo, performs atomic file write, and manages cache/journal.async def undo(self, file_path: str, count: int = 1) -> Dict[str, Any]: abs_path = resolve_path(file_path) with FileLock(abs_path): doc = self.get_doc(file_path) result = doc.undo(count) if "success" in result: try: self._atomic_write(file_path, doc.get_content()) self._update_cache_mtime(abs_path) doc.confirm_journal() except Exception as e: self.invalidate_cache(file_path) return {"error": f"Failed to write file: {e}"} return result
- Core Document class undo method: reverses the last N journaled operations (replace, delete, insert, metadata) by popping journal and applying inverse actions.def undo(self, count: int = 1) -> Dict[str, Any]: """Undo last operations""" if not self.journal: return {"error": "Journal is empty"} undone = [] errors = [] for _ in range(min(count, len(self.journal))): entry = self.journal.pop() success = False # Apply reverse operation if entry.operation == "replace": # Prefer ID-based lookup for reliability element = None if entry.element_id: element = self.find_by_id(entry.element_id) if not element: element = self.find_by_path(entry.path) if element and entry.old_value is not None: element.content = entry.old_value success = True else: errors.append( f"Cannot undo replace: element not found at {entry.path}" ) elif entry.operation == "delete": # Restore deleted element at its original position success = self._restore_element_at_position(entry) if not success: errors.append( f"Cannot undo delete: failed to restore element at {entry.path}" ) elif entry.operation in ("insert_after", "insert_before"): # Remove the inserted element success = self._remove_inserted_element(entry) if not success: errors.append( f"Cannot undo {entry.operation}: element not found at {entry.path}" ) elif entry.operation == "update_metadata": # Restore old metadata if entry.old_value: try: old_metadata = json.loads(entry.old_value) self.metadata = old_metadata success = True except (json.JSONDecodeError, TypeError): errors.append("Cannot undo update_metadata: invalid old value") else: errors.append("Cannot undo update_metadata: no old value stored") if success: undone.append(entry.operation) self._rebuild_raw_content() self._save_journal() result = {"success": True, "undone_operations": undone} if errors: result["warnings"] = errors return result