Uvilo OS Plan Trash MCP
Purpose
Provide safe “delete” operations for the assistant by moving items to a trash directory instead of permanently deleting them, with the ability to restore.
Trash Location
/workspace/erik/uvilo-os/.trash/ (already exists, already gitignored)
Key Design: Path Hierarchy Preservation
When trashing a file, recreate its relative path from the repo root inside .trash/.
Example:
- Trashing
/workspace/erik/uvilo-os/Architecture/Old_Doc.md - Moves to:
/workspace/erik/uvilo-os/.trash/Architecture/Old_Doc__2026-03-14T18-30-00.md
This means:
- You always know where a trashed item came from (its restore path)
- No filename collisions — every trash operation produces a unique name
- Restore is straightforward — strip the timestamp suffix and reverse the move
Timestamp in Filename
Every trashed item gets a timestamp suffix appended to its name:
Examples:
Old_Doc.md→Old_Doc__2026-03-14T18-30-00.mdScripts/→Scripts__2026-03-14T18-30-00/Makefile(no ext) →Makefile__2026-03-14T18-30-00
Format: __YYYY-MM-DDTHH-MM-SS (double underscore delimiter, hyphens instead of colons
for filesystem safety)
Benefits:
- Trash date is visible at a glance — no manifest or metadata file needed
- Collision handling comes for free
- Age-based
empty_trash(older_than_days=N)is trivial — parse the filename - No external state to keep in sync
Tradeoff:
- Untrash must strip the timestamp suffix to restore the original name
Tools (6)
1. trash_file(path: str) → str
- Validates path is within the repo and is a file
- Validates it’s not inside
.trash/,.git/, or other protected paths - Computes relative path from repo root
- Appends timestamp suffix to filename (before extension)
- Creates parent directories in
.trash/as needed - Moves file to
.trash/<relative_path_with_timestamp> - Returns confirmation with original and trash paths
2. trash_directory(path: str) → str
- Same as trash_file but for directories
- Appends timestamp suffix to the directory name
- Moves the entire directory tree
- Validates it’s not a protected path (
.trash/,.git/,.internal/) - Returns confirmation with item count
3. untrash_file(trash_path: str) → str
- Takes a path within
.trash/ - Strips the timestamp suffix to derive the original filename
- Derives the original location from the relative path
- Validates the original location doesn’t already have a file (error if so)
- Moves file back to original location
- Cleans up empty parent dirs in
.trash/ - Returns confirmation
4. untrash_directory(trash_path: str) → str
- Same as untrash_file but for directories
- Strips timestamp suffix from directory name
- Validates target doesn’t already exist
- Moves directory back, cleans up empty parents in
.trash/
5. list_trash(path: str = "") → str
- Lists contents of
.trash/, optionally filtered to a subdirectory - Shows each item with its original name, trash date (parsed from suffix), and size
- Useful before calling untrash or empty_trash
6. empty_trash(older_than_days: int = 30) → str
- Permanently deletes items trashed more than N days ago (default: 30 days) (parsed from the timestamp suffix in each filename)
- Pass
older_than_days=0to delete ALL items regardless of age - Returns summary: number of items deleted, space freed
- Irreversible — the assistant should confirm with the user before calling
Implementation Details
- Language: Python (matches uvilo-git-push.py pattern)
- Framework:
FastMCP(frommcppackage, same as git-push server) - Transport: stdio
- File location:
/workspace/uvilo-trash.py(alongside uvilo-git-push.py) - Repo root constant:
/workspace/erik/uvilo-os - Trash root constant:
/workspace/erik/uvilo-os/.trash - Protected paths: Refuse to trash
.git/,.trash/,.internal/node_modules/,.internal/dist/,.internal/.astro/ - No shell dependency — uses Python’s
shutil.move,shutil.rmtree,os.makedirs,pathlib, etc. - Timestamp parsing regex:
__(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2})to extract the trash date from any filename
LibreChat Config Addition
Migration
Empty the current .trash/ directory (3 stale flat files with no hierarchy or timestamps).
Just delete them during implementation — they’re throwaway.