{"id":"faa1301c-0887-4633-b28f-1c9418f5fb51","slug":"kridaydave-file-organizer-mcp","kind":"mcp","name":"File-Organizer-MCP","summary":"This MCP server will organize your files using connections to MCP using clients like Claude, Cursor and Gemini Cli","owner":"kridaydave","repoUrl":"https://github.com/kridaydave/File-Organizer-MCP","license":"MIT","licenseTier":"permissive","trust":"community","stars":46,"match":null,"fewStars":false,"format":"mcp","createdAt":"2025-10-17T16:11:11.000Z","addedAt":"2026-10-14T10:54:10.192Z","logoUrl":"https://avatars.githubusercontent.com/u/195733480?u=13073cafbe1e286eb8539063d93af7260b55fc37&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["files-documents","cloud-infra"],"tags":[],"runtime":"node","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-14T20:17:21.709Z","sample":false,"url":"https://conduits.dev/tools/kridaydave-file-organizer-mcp","language":"TypeScript","transports":["stdio"],"install":{"npm":"file-organizer-mcp"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# File Organizer MCP Server\n\nVersion 5.0.0 | MCP protocol 2026-07-28 (stateless) | Node.js 20+\n\n[![npm version](https://img.shields.io/badge/npm-v5.0.0-blue.svg)](https://www.npmjs.com/package/file-organizer-mcp)\n[![npm downloads](https://img.shields.io/npm/dm/file-organizer-mcp.svg)](https://www.npmjs.com/package/file-organizer-mcp)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Tests](https://img.shields.io/badge/tests-835%20passing-success.svg)](tests/)\n\nA Model Context Protocol (MCP) server that organizes files. It gives a Claude-style assistant a single atomic operation to categorize, sort, dedupe, and rename files, instead of making it chain dozens of primitive `read`, `write`, and `rename` calls.\n\n- [Why](#why)\n- [Quick start](#quick-start)\n- [Features](#features)\n- [Tools](#tools)\n- [File categories](#file-categories)\n- [Example workflows](#example-workflows)\n- [Security](#security-configuration)\n- [Troubleshooting](#troubleshooting)\n- [Architecture](#architecture)\n- [Documentation](#documentation)\n\n---\n\n## Why\n\nA filesystem MCP server built only on `read`, `write`, `make`, and `delete` forces an assistant to plan every move and rename as a separate step. Each step costs tokens, and more steps means more chances to get the path wrong.\n\nFile Organizer MCP replaces those chains with one call:\n\n| Primitive approach                     | File Organizer MCP                                |\n| -------------------------------------- | ------------------------------------------------- |\n| Many `read` / `write` / `rename` calls | `organize_files()` runs the whole move atomically |\n| Dozens of reasoning steps              | One reasoning step                                |\n| High token use                         | Minimal token use                                 |\n| Easy to corrupt on partial failure     | Rollback-safe operations                          |\n\n---\n\n## Quick start\n\n### One-command setup\n\n```bash\nnpx file-organizer-mcp --setup\n```\n\nThe wizard detects installed AI clients (Claude Desktop, Cursor, Windsurf, Cline, and others), configures them, and walks you through folder selection and preferences.\n\n### Requirements\n\nNode.js 20 or newer.\n\n### After setup\n\nYou can ask the assistant things like:\n\n- \"Organize my Downloads folder\"\n- \"Find duplicate files in my Documents\"\n- \"Show me my largest files\"\n- \"Which categories take up the most space in my Downloads?\"\n\n### Install methods\n\n| Method | Command                             | Use case                    |\n| ------ | ----------------------------------- | --------------------------- |\n| npx    | `npx file-organizer-mcp --setup`    | Occasional use or a trial   |\n| Global | `npm install -g file-organizer-mcp` | Regular use, faster startup |\n\n---\n\n## Features\n\n- Categorization into 12 or more file types.\n- Cron-based automatic organization and directory watch mode.\n- Duplicate detection by SHA-256 content hash.\n- Disk usage per category: which file types hold the space, in bytes and as a share.\n- Metadata extraction: EXIF for photos, ID3 for audio.\n- Smart organization that picks the right strategy per file type.\n- Date sorting into `YYYY/MM` folders from EXIF date taken (photos) or file mtime, reporting which date each file used.\n- Dry-run preview, atomic moves, and rollback.\n- Plan validation before you organize: name collisions, occupied destinations, cross-device moves, and files the sensitive-file gate blocks.\n- Path traversal protection, TOCTOU mitigation.\n- Windows, macOS, and Linux.\n\n---\n\n## Tools\n\n### Core tools\n\n- `file_organizer_scan_directory` - List a directory with detailed file info. `directory` is required; `include_subdirs` toggles recursion.\n- `file_organizer_read_file` - Read a file through the validated path pipeline. `path` is required; `encoding` is utf-8, base64, or binary.\n- `file_organizer_batch_rename` - Rename many files by pattern, regex, or numbering. Checks the whole plan for name collisions first: if a real run would put two files on one name, or overwrite a name a different file already holds, the batch is rejected before anything moves and the conflicts come back as structured data.\n- `file_organizer_undo_last_operation` - Reverse the most recent organization.\n- `file_organizer_quarantine_files` - Set flagged files aside for review, reversibly. See below.\n- `file_organizer_restore_quarantine` - Put quarantined files back where they came from.\n- `file_organizer_search_history` - Filter the history by path glob (`path_glob`), date range (`from`/`to`), or operation type. Every filter is optional and they combine, so a long history stays queryable instead of one flat list.\n- `file_organizer_export_report` - Write a health report for a directory in one call: totals, space per category, duplicate groups, largest files. Pass `output_path` to leave a file behind, or leave it out and nothing is written. See below.\n\n### Full tool list (37 tools)\n<!-- BEGIN GENERATED TOOL LIST -->\n- `file_organizer_analyze_duplicates`\n- `file_organizer_batch_read_files`\n- `file_organizer_batch_rename`\n- `file_organizer_categorize_by_type`\n- `file_organizer_delete_duplicates`\n- `file_organizer_disk_usage_by_category`\n- `file_organizer_doctor`\n- `file_organizer_export_config`\n- `file_organizer_export_report`\n- `file_organizer_find_broken_symlinks`\n- `file_organizer_find_duplicate_files`\n- `file_organizer_find_empty_directories`\n- `file_organizer_find_largest_files`\n- `file_organizer_find_old_files`\n- `file_organizer_get_categories`\n- `file_organizer_inspect_metadata`\n- `file_organizer_list_files`\n- `file_organizer_organize_by_date`\n- `file_organizer_organize_by_project`\n- `file_organizer_organize_files`\n- `file_organizer_organize_music`\n- `file_organizer_organize_photos`\n- `file_organizer_preview_delete_duplicates`\n- `file_organizer_preview_organization`\n- `file_organizer_quarantine_files`\n- `file_organizer_read_file`\n- `file_organizer_restore_quarantine`\n- `file_organizer_scan_directory`\n- `file_organizer_search_history`\n- `file_organizer_sensitive_scan`\n- `file_organizer_set_custom_rules`\n- `file_organizer_smart_suggest`\n- `file_organizer_system_organize`\n- `file_organizer_undo_last_operation`\n- `file_organizer_validate_organization_plan`\n- `file_organizer_verify_integrity`\n- `file_organizer_view_history`\n<!-- END GENERATED TOOL LIST -->\n\nFor parameters and return shapes, see [API.md](API.md).\n\n### Quarantine: set files aside without losing them\n\nScanning flags a suspicious file. Deleting it is not reversible. Quarantine is\nthe middle option: the file is **moved** into a hidden quarantine directory\ninside the directory you named, and it stays readable on disk.\n\n```text\nfile_organizer_quarantine_files({\n  directory: \"~/Downloads\",\n  files: [\"~/Downloads/invoice.exe\"],\n  reason: \"flags as executable content\",\n})\n```\n\nReversibility is the whole point, so it comes back two ways:\n\n- `file_organizer_undo_last_operation` — the existing undo path. Quarantine\n  writes the same rollback manifest the organizer writes, so undo is the same\n  call you already use.\n- `file_organizer_restore_quarantine` — reads that manifest and puts every file\n  back at the exact path it was taken from. The restore writes a manifest of\n  its own, so the restore is reversible too.\n\nWhat to know before you move something:\n\n- **Dry run by default.** A bare call lists what *would* be quarantined and\n  moves nothing. Pass `dry_run: false` to apply it.\n- **Nothing is deleted.** No file is removed from disk by quarantine. Only its\n  location changes.\n- **The quarantine directory is derived, not hardcoded.** By default it is\n  `.file-organizer-quarantine` inside the `directory` you passed, which means it\n  inherits that directory's access grant. Set `quarantine_dir` to move it\n  elsewhere — it goes through the same path validation as any other directory,\n  so it cannot be pointed outside your allowed directories.\n- **Same names do not collide.** Two files called `notes.txt` become\n  `notes.txt` and `notes_1.txt`. Neither overwrites the other, and a restore\n  puts each back at its own original path.\n- **One batch at a time.** Every listed file must live inside `directory`. If any\n  path is outside it, nothing moves.\n- **Paths in the result are absolute**, like `organize_files`. They are\n  canonicalised, so they differ in spelling by platform — Windows expands 8.3\n  short names (`RUNNER~1` becomes `runneradmin`) and macOS rewrites `/var` to\n  `/private/var`. Compare basenames, or normalise both sides, instead of\n  comparing raw path strings.\n\n### Scheduled organization (separate process)\n\nThe stdio MCP server stays stateless — cron-based watching runs as its own\nprocess:\n\n```bash\nfile-organizer-watch add ~/Downloads \"0 10 * * *\"   # daily at 10am\nfile-organizer-watch list\nfile-organizer-watch                                # start the daemon\n```\n\nWatches are stored in the shared user config, so `add`/`remove` work even\nwhile the daemon is running (restart it to pick up changes).\n\n#### Single pass from an OS timer\n\n`once` runs one organization pass and exits, holding no watcher, no timer, and\nno open handle. That is the mode cron, launchd, a systemd timer, or Task\nScheduler drives:\n\n```bash\nfile-organizer-watch once ~/Downloads              # dry run, writes nothing\nfile-organizer-watch once ~/Downloads --apply      # move, then exit\nfile-organizer-watch once . --apply --recursive --json\n```\n\n##### Exit codes\n\n| Code | Meaning                                                    |\n| ---- | ---------------------------------------------------------- |\n| `0`  | Pass finished, moved nothing — empty dir or dry run        |\n| `1`  | Failed: bad flags, refused path, per-file errors, or abort |\n| `2`  | Pass finished clean and moved at least one file            |\n\n`1` wins over `2` even when files moved, so a partial pass never looks like\nsuccess.\n\n##### `--json`\n\n`--json` prints exactly one JSON object on stdout and nothing else. Logs,\nusage, and failure text go to stderr, so stdout stays parseable whether the\nrun succeeded or not.\n\n```json\n{\n  \"ok\": true,\n  \"exitCode\": 2,\n  \"directory\": \"/home/you/Downloads\",\n  \"dryRun\": false,\n  \"scanned\": 12,\n  \"planned\": 8,\n  \"moved\": 8,\n  \"skipped\": 4,\n  \"historyLogged\": true,\n  \"aborted\": false,\n  \"errors\": []\n}\n```\n\nEvery key is always present, including on failure — a refused path reports the\nsame shape with `ok` false, `exitCode` 1, and the reason in `errors`. `ok` is\ntrue for exit codes 0 and 2. `historyLogged: false` on an applied pass means\nno history row was written for the moves: nothing names that pass in history\nand there is no id to undo it by, though the manifest may still be on disk.\nWhen it is `true`, the row carries the rollback manifest id whenever the pass\nmanaged to write one, so `file_organizer_undo_last_operation` can reverse the\npass file by file. A pass whose manifest write failed has a row with no id:\nthe pass is in history, but it cannot be undone by handle.\n\nOn a pass that ran, `directory` is the **resolved** path, not the argument\nverbatim — the same convention every tool uses (`file_organizer_organize_files`\nreports the directory its path validator approved). It is the path the gate\nchecked and the pass scanned, so symlinks are already followed and `~` is\nexpanded. The two forms differ on macOS (`/var/folders/...` →\n`/private/var/folders/...`) and on Windows (an 8.3 short name like `RUNNER~1`\nexpands to the long name), so a caller must not string-compare it against what\nit passed in.\n\nThe one exception is a failure that never reached a scan — a path the gate\nrefused, or a thrown error. There is no approved path to report, so `directory`\ncarries the original argument exactly as typed. Key your reports on `exitCode`\nand `errors`, not on `directory`.\n\nWhen scripting a pipeline, keep the CLI's exit code — without `pipefail` the\npipeline reports `jq`'s status, and a pass that moved files and then failed\nwould look like success:\n\n```bash\nset -o pipefail\n\n# alert only when files moved AND the pass was clean.\n# .ok rejects a partial pass that moved files but then failed.\nfile-organizer-watch once ~/Downloads --apply --json \\\n  | jq -e '.ok and (.moved > 0)' >/dev/null && echo \"organized\"\n```\n\nFor a read-only sweep — scan plus `preview_organization` on a timer, no moves —\nsee [examples/scheduling](examples/scheduling/README.md). It has ready-to-copy\nrecipes for three surfaces:\n\n| Surface        | Trigger                     | Config                                                                                           |\n| -------------- | --------------------------- | ------------------------------------------------------------------------------------------------ |\n| Claude Desktop | headless `claude -p`        | [claude-desktop.config.json](examples/scheduling/claude-desktop.config.json)                     |\n| Codex          | `codex exec`                | [codex.config.toml](examples/scheduling/codex.config.toml)                                       |\n| cron / systemd | `file-organizer-watch once` | [crontab.example](examples/scheduling/crontab.example), [systemd/](examples/scheduling/systemd/) |\n\n---\n\n## File categories\n\n| Category    | Typical extensions                           |\n| ----------- | -------------------------------------------- |\n| Executables | `.exe`, `.msi`, `.bat`, `.sh`                |\n| Videos      | `.mp4`, `.avi`, `.mkv`, `.mov`               |\n| Documents   | `.pdf`, `.doc`, `.docx`, `.txt`, `.md`       |\n| Images      | `.jpg`, `.jpeg`, `.png`, `.gif`, `.webp`     |\n| Audio       | `.mp3`, `.wav`, `.flac`, `.m4a`              |\n| Archives    | `.zip`, `.rar`, `.7z`, `.tar.gz`             |\n| Code        | `.py`, `.js`, `.ts`, `.java`, `.go`, `.json` |\n\n---\n\n## Example workflows\n\n### Clean up a Downloads folder\n\n1. Scan the folder and review the file distribution and space use.\n2. Identify duplicates and stale files.\n3. Preview the moves and conflicts.\n4. Confirm, then organize into category folders.\n\nResult: a sorted folder, duplicates flagged, and reclaimed space.\n\n### Organize a project\n\nThe assistant scans the project, splits files into Code, Assets, and Docs, keeps the `src/` tree intact, and moves loose config files, readmes, and screenshots into their proper folders.\n\n### Find and handle duplicates\n\nThe assistant hashes files, groups duplicates, scores each copy by location, name quality, and age, and recommends which to keep and which to delete. It reports the wasted space. You decide whether to delete.\n\n### Discover large files\n\nPoint it at a folder and it lists the largest files by size, flags old backups you can archive, and notes any large duplicates.\n\n### Organize music\n\nIt reads ID3 tags and rebuilds the folder as `Artist / Album / Title.mp3`.\n\n```\nBefore:\nDownloads/\n  song1.mp3\n  track02.mp3\n  music_file.mp3\n\nAfter:\nMusic/\n  Coldplay/\n    A Rush of Blood to the Head/\n      Clocks.mp3\n      The Scientist.mp3\n  Radiohead/\n    OK Computer/\n      Paranoid Android.mp3\n      Karma Police.mp3\n```\n\n### Organize photos\n\nIt reads the capture date from EXIF and sorts photos into date-based folders. The default `date_format` is `YYYY/MM`; the example below uses `YYYY/MM/DD`.\n\n```\nBefore:\nPictures/\n  IMG_001.jpg\n  photo123.png\n  DSC_4567.raw\n\nAfter:\nPictures/\n  2023/\n    12/\n      25/\n        IMG_001.jpg\n      31/\n        photo123.png\n  2024/\n    01/\n      15/\n        DSC_4567.raw\n```\n\n### Security-screen a folder\n\n`file_organizer_sensitive_scan` reads the metadata block of every JPEG and TIFF in a\nfolder and scores each one 0-100 for the risk of sharing it. It flags EXIF GPS\ncoordinates and altitude, GPS fix timestamps, owner and artist names, camera and\nlens serial numbers, camera or computer make and model, copyright lines,\ncapture/editing software, and free-text notes. Each score arrives with the\nindividual findings and the weight each one added, so the number is a sum of\nstated causes:\n\n```json\n{\n  \"name\": \"IMG_4471.jpg\",\n  \"risk_score\": 70,\n  \"risk_level\": \"high\",\n  \"reasons\": [\n    { \"kind\": \"gps_coordinates\", \"weight\": 40, \"exif_tags\": [\"GPSLatitude\", \"GPSLongitude\"], \"value\": \"51.5073, -0.1277\" },\n    { \"kind\": \"owner_name\", \"weight\": 30, \"exif_tags\": [\"OwnerName\"], \"value\": \"Jane Q Public\" }\n  ]\n}\n```\n\n**A score of 0 is not a clearance to share the file.** The detection is\nheuristic and the tool never modifies anything: it reports what it recognizes,\nand it does not look at PDF annotations, XMP, IPTC, embedded thumbnails, file\nnames, or what is visible in the picture. Files outside JPEG and TIFF are listed\nunder `skipped` with a reason. Treat the scan output itself as sensitive, since\nit echoes the values it found.\n\n### Set up automatic organization\n\nRegister a directory with a cron schedule:\n\n```json\n{\n  \"directory\": \"/Users/john/Downloads\",\n  \"schedule\": \"0 9 * * *\",\n  \"rules\": {\n    \"auto_organize\": true,\n    \"min_file_age_minutes\": 5\n  }\n}\n```\n\nThe server organizes the folder on that schedule. Add more watches for other directories.\n\n---\n\n## Security configuration\n\nAccess is restricted to a whitelist of user directories by default. System directories stay blocked.\n\n### Allowed by default\n\nThe server enables these locations if they exist on the machine:\n\n| Platform | Allowed directories                                                                                                                          |\n| -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |\n| Windows  | Desktop, Documents, Downloads, Pictures, Videos, Music, Projects, Workspace, workspace, Development, Code, OneDrive (if set)                 |\n| macOS    | Desktop, Documents, Downloads, Pictures, Videos, Music, Projects, Workspace, workspace, Development, Code, Movies, iCloud Drive, /Volumes    |\n| Linux    | Desktop, Documents, Downloads, Pictures, Videos, Music, Projects, Workspace, workspace, Development, Code, `~/dev`, /mnt, /media, /run/media |\n\nOnly directories that exist and are not symlinks are returned.\n\n### Always blocked\n\nThese paths stay blocked even if you add them to the config:\n\n- Windows: `C:\\Windows`, Program Files, AppData, `$Recycle.Bin`\n- macOS: `/System`, `/Library`, `/Applications`, `/private`, `/usr`\n- Linux: `/etc`, `/usr`, `/var`, `/root`, `/sys`, `/proc`\n- Everywhere: `node_modules`, `.git`, `.vscode`, `.idea`, `dist`, `build`\n\n### Custom configuration\n\nEdit the user config file:\n\n- Windows: `%APPDATA%\\file-organizer-mcp\\config.json`\n- macOS: `$HOME/Library/Application Support/file-organizer-mcp/config.json`\n- Linux: `$HOME/.config/file-organizer-mcp/config.json`\n\nAdd paths to `customAllowedDirectories`:\n\n```json\n{\n  \"customAllowedDirectories\": [\n    \"C:\\\\Users\\\\Name\\\\My Special Folder\",\n    \"D:\\\\Backups\"\n  ]\n}\n```\n\nYou can paste a folder path straight from your file explorer's address bar.\n\n### External drives and network mounts\n\nPaths outside your home directory are blocked unless you opt in. To allow an external volume such as `/Volumes/My Drive` on macOS or `/media/user/usb` on Linux, set `allowExternalVolumes` to true:\n\n```json\n{\n  \"allowExternalVolumes\": true,\n  \"customAllowedDirectories\": [\n    \"/Volumes/MyExternalDrive\",\n    \"/Volumes/Photography Backup\"\n  ]\n}\n```\n\nWindows drive letters like `D:\\` work without this flag.\n\nRestart the client after editing the config.\n\n### Moving your config to another machine\n\n`file_organizer_export_config` bundles the whole user config — allowed\ndirectories, custom rules, conflict strategy, watch entries, auto-organize and\nhistory settings — into one JSON document you can copy to a laptop or a fresh\ninstall:\n\n```typescript\n// writes the bundle; refuses to overwrite an existing file\nfile_organizer_export_config({ output_path: \"~/fom-config-bundle.json\" });\n// omit output_path to get the bundle in the reply without writing one\n```\n\nRules, strategies and schedules mean the same thing anywhere. Directory paths\ndo not: they are absolute paths of the machine that exported them, so they will\nnot exist on the target and they do describe your directory layout. The reply\nalways says so:\n\n- **absolute mode** (the default) exports the paths exactly as configured and\n  lists every field to edit by hand in `requires_editing`.\n- **rebased mode** takes a `rebase_root` — normally the home directory — and\n  rewrites each path under it as `~/relative`, which follows the target\n  machine's home. A path outside that root cannot be rebased; it is exported\n  unchanged and named in `non_portable_paths`.\n\n```typescript\nfile_organizer_export_config({\n  rebase_root: \"~\",\n  response_format: \"json\",\n});\n// → requires_editing: [], directories exported as [\"~/Documents\", \"~/Downloads\"]\n```\n\nCopy the bundle to the other machine, apply the edits it names, and merge its\n`config` into that machine's `config.json`. The tool never writes the config\nfile itself, and the bundle file is the only thing it writes.\n\n### Conflict strategy\n\n```json\n{\n  \"conflictStrategy\": \"rename\"\n}\n```\n\n- `rename` (default) - Append a suffix to the new file, for example `file (1).txt`.\n- `skip` - Keep the existing file and skip the new one.\n- `overwrite` - Replace the existing file, after writing a backup.\n\n### Legacy auto-organize schedule\n\nFor a simple hourly, daily, or weekly schedule:\n\n```json\n{\n  \"autoOrganize\": {\n    \"enabled\": true,\n    \"schedule\": \"daily\"\n  }\n}\n```\n\nFor anything more granular, run `file-organizer-watch add <directory> \"<cron>\"`.\n\n### Defenses\n\n| Attack type         | Protection                                     |\n| ------------------- | ---------------------------------------------- |\n| Unauthorized access | Whitelist plus blacklist enforcement           |\n| Path traversal      | validatePathBase, see ARCHITECTURE.md         |\n| Symlink attacks     | Real path resolution                           |\n| DoS                 | Resource limits on file count, depth, and size |\n\n---\n\n## Troubleshooting\n\n### The MCP server does not appear\n\n1. Check the config file path is correct.\n2. Confirm Node.js 20 or newer: `node --version`.\n3. Fully restart the client.\n4. Check the path in the client config file.\n\n### Permission errors\n\n- Windows: run the client as Administrator.\n- macOS/Linux: check folder permissions with `ls -la`.\n- Confirm the target directory is writable.\n\n### Files are not moving\n\n1. Make sure `dry_run` is not enabled.\n2. Close programs that may be locking the files.\n3. Check for sufficient disk space.\n4. Read the operation summary for error messages.\n\n### Custom rules are missing after a restart\n\n`file_organizer_set_custom_rules` saves the accepted rules to `config.json` in your\nOS config directory and every later request reads them from there. Three things\nto know:\n\n- The call replaces the whole saved set, so it is not a per-rule merge.\n- Rules with an unknown category or a rejected pattern are skipped; the reply\n  says how many were applied.\n- If the write itself fails — read-only config directory, missing permissions —\n  the call returns an error instead of a success message, and the server log\n  holds the cause. Nothing is persisted in that case.\n\n---\n\n## Architecture\n\nThe server is stateless: each JSON-RPC request gets a fresh context (`config`, history logger) routed through an explicit tool registry into pure service modules under `src/core/`. The pipeline is `scan → categorize → plan → move`, every path passes `validatePathBase` before any `fs` call, and all side effects are file-backed (history, rollback manifests), so nothing survives a restart except what you can undo.\n\nScheduled organization runs as a separate process (`file-organizer-watch`) so the stdio server stays request/response.\n\nSee [ARCHITECTURE.md](ARCHITECTURE.md) for the diagram and design notes.\n\n---\n\n## Documentation\n\n- [API.md](API.md) - Complete tool reference\n- [ARCHITECTURE.md](ARCHITECTURE.md) - Design and architecture\n- [examples/scheduling](examples/scheduling/README.md) - Scan + preview sweep recipes for Claude Desktop, Codex, cron, and systemd\n- [CONTRIBUTING.md](CONTRIBUTING.md) - Contribution guidelines\n- [MIGRATION.md](MIGRATION.md) - v2 to v3 upgrade guide\n- [CHANGELOG.md](CHANGELOG.md) - Version history\n- [SECURITY.md](SECURITY.md) - Security model and reporting\n\n---\n\n## Contributing\n\nRead [CONTRIBUTING.md](CONTRIBUTING.md), then clone and build:\n\n```bash\ngit clone https://github.com/kridaydave/File-Organizer-MCP.git\ncd File-Organizer-MCP\nnpm install\nnpm run build\nnpm test\n```\n\n### Adding a tool: one file, one line\n\n1. Create `src/tools/my-tool.ts` exporting a `ToolDefinition` (name, Zod input schema, annotations, formats) and its handler.\n2. Add an import and one `reg()` entry in `src/mcp/registry.ts`.\n\nThat's it. The registry is the single source of truth: the server registers from it, routing is pure, and no other file changes. Schemas shared across tools live in `src/schemas/` (`common`, `scan`, `organize`, `system`). If your tool takes a path, it goes through `validateStrictPath` before touching `fs`, and errors go through `sanitizeErrorMessage`. See [ARCHITECTURE.md](ARCHITECTURE.md) for the contract details.\n\nReport bugs and feature requests on [GitHub Issues](https://github.com/kridaydave/File-Organizer-MCP/issues). For a security vulnerability, email technocratix902@gmail.com.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n"}