Skip to main content
Glama
KazKozDev
by KazKozDev

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
NameRequiredDescriptionDefault
file_pathYes
countNo

Implementation Reference

  • 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",
                },
            },
        },
    ),
  • 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

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/KazKozDev/markdown-editor-mcp-server'

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