# mcp-synology-filestation MCP server that exposes a **Synology NAS FileStation** as tools for Claude Desktop (and any other MCP client). All 26 tools are production-tested against DSM 7.x. --- ## Features 26 tools covering the full FileStation surface: | Group | Tools | |-------|-------| | **Browse** | `list_shares`, `list_dir`, `get_info`, `check_exist`, `search` | | **Transfer** | `download`, `upload`, `get_thumbnail` | | **Organise** | `create_folder`, `rename`, `copy`, `move`, `delete`, `compress`, `extract` | | **Analyse** | `dir_size`, `get_md5`, `check_permission` | | **Sharing** | `create_sharing_link`, `list_sharing_links`, `delete_sharing_link` | | **Favorites** | `list_favorites`, `add_favorite`, `delete_favorite` | | **System** | `background_tasks`, `list_snapshots` | --- ## Requirements - Python 3.12+ - [`uv`](https://docs.astral.sh/uv/) (recommended) or pip - Synology NAS running DSM 7.x with FileStation enabled - A DSM user account with FileStation access --- ## Installation ### From Gitea ```bash uv tool install git+https://gitea.gecheckt.de/marcus/mcp-synology-filestation.git ``` ### Reinstall (upgrade) ```bash uv tool install --reinstall git+https://gitea.gecheckt.de/marcus/mcp-synology-filestation.git ``` > **Windows / Claude Desktop:** close Claude Desktop before reinstalling — Windows holds > file locks on running executables. --- ## Setup Run the interactive wizard once to configure the NAS connection and store credentials securely in the OS keyring: ```bash mcp-synology-filestation setup ``` The wizard will: 1. Ask for your NAS host, port, and HTTPS settings 2. Ask for your DSM username and password (stored in OS keyring — never written to disk) 3. Handle 2FA / device token if required 4. Verify the FileStation API is reachable 5. Print a ready-to-paste Claude Desktop config snippet ### Verify the setup ```bash mcp-synology-filestation check ``` --- ## Claude Desktop integration Add the server to `claude_desktop_config.json`: ```json { "mcpServers": { "synology-filestation": { "command": "mcp-synology-filestation", "args": ["serve"] } } } ``` The server uses **stdio transport** and is fully compatible with Claude Desktop on Windows, macOS, and Linux. ### Environment variable overrides | Variable | Purpose | |----------|---------| | `SYNOLOGY_HOST` | Override NAS hostname | | `SYNOLOGY_USERNAME` | Override DSM username | | `SYNOLOGY_PASSWORD` | Override DSM password (not stored) | --- ## Tool reference ### Browse #### `list_shares` List all shared folders with volume usage (total / used / %). #### `list_dir` List a directory's contents with pagination and sorting. | Parameter | Default | Description | |-----------|---------|-------------| | `path` | — | Share-relative path (e.g. `/docker`, `/data/photos`) | | `offset` | 0 | Items to skip | | `limit` | 100 | Max items (hard cap: 500) | | `sort_by` | `name` | `name` \| `size` \| `user` \| `group` \| `mtime` \| `atime` \| `crtime` \| `type` | | `sort_direction` | `asc` | `asc` \| `desc` | #### `get_info` Detailed metadata (size, owner, permissions, timestamps) for one or more paths. Accepts comma-separated paths. #### `check_exist` Yes/No existence check for one or more comma-separated paths. #### `search` Glob-pattern search across a directory tree with async DSM polling. | Parameter | Default | Description | |-----------|---------|-------------| | `path` | — | Root directory | | `pattern` | — | Filename glob, e.g. `*.log` | | `recursive` | `true` | Search subdirectories | | `max_results` | 200 | Cap on returned matches | --- ### Transfer #### `download` Download a file as base64-encoded content. Files > 10 MB are rejected. Returns JSON: `{filename, size, content_base64}` #### `upload` Upload base64-encoded content to the NAS. Files > 50 MB are rejected. | Parameter | Default | Description | |-----------|---------|-------------| | `path` | — | Destination directory | | `filename` | — | Name for the new file | | `content_base64` | — | Base64-encoded bytes | | `overwrite` | `false` | ⚠ Overwrites existing file if `true` | | `create_parents` | `true` | Create missing parent directories | #### `get_thumbnail` Fetch a JPEG thumbnail for an image or video file. | Parameter | Default | Description | |-----------|---------|-------------| | `path` | — | Share-relative file path | | `size` | `small` | `small` \| `medium` \| `large` \| `original` | Returns JSON: `{filename, size_bytes, content_base64}`. A `"warning"` field is added when the thumbnail exceeds ~500 KB base64. Thumbnails > ~2 MB base64 are rejected with an error — use `size=small` in that case. > **Note:** The DSM `quality` parameter has no effect — DSM ignores it. `size=small` is > the default and recommended value; larger sizes can exceed MCP buffer limits. --- ### Organise #### `create_folder` Create a folder. Set `create_parents=true` to create intermediate directories. #### `rename` Rename a file or folder. `new_name` is a bare name (not a full path). #### `copy` / `move` Async copy or move. Default `overwrite=false`. #### `delete` **Irreversible.** Requires `confirmed=true`. Without it, returns a preview of what would be deleted — nothing is removed. #### `compress` Compress one or more paths into a ZIP or 7z archive (async DSM task). | Parameter | Default | Description | |-----------|---------|-------------| | `paths` | — | List of source paths | | `dest_file_path` | — | Output archive path including filename | | `level` | `moderate` | `store` \| `fastest` \| `fast` \| `normal` \| `moderate` \| `maximum` | | `format` | `zip` | `zip` \| `7z` | | `password` | `""` | Archive password | #### `extract` Extract a ZIP or 7z archive to a destination folder (async DSM task). | Parameter | Default | Description | |-----------|---------|-------------| | `file_path` | — | Archive path on NAS | | `dest_folder_path` | — | Destination directory | | `overwrite` | `false` | ⚠ Overwrite existing files if `true` | | `keep_dir` | `true` | Preserve directory structure | | `create_subfolder` | `false` | Extract into a new subfolder | | `password` | `""` | Archive password | --- ### Analyse #### `dir_size` Total size, file count, and folder count for one or more directories (comma-separated). #### `get_md5` Compute the MD5 checksum of a file. #### `check_permission` Check whether the current DSM user can write a given filename into a directory. --- ### Sharing #### `create_sharing_link` Create a public sharing link with optional password and expiry date (`YYYY-MM-DD`). #### `list_sharing_links` Paginated table of all sharing links (ID, URL, path, owner, expiry, status). #### `delete_sharing_link` Delete a sharing link by its ID (from `list_sharing_links`). --- ### Favorites #### `list_favorites` List all FileStation user favorites (name, path, type, status, real path, modified). #### `add_favorite` Pin a path as a FileStation favorite with a display label. #### `delete_favorite` Remove a favorite by its path. --- ### System #### `background_tasks` Paginated list of active/recent FileStation background tasks (copy, move, delete, extract, compress) with type, status, path, and file progress. > Only the `list` method is available on DSM 7.x — tasks cannot be cancelled via this API. #### `list_snapshots` List Btrfs snapshots for a shared folder (snapshot ID, creation time, description, locked). > Requires a Btrfs-formatted volume. Returns a clear error on ext4/non-Btrfs shares > ("requires Btrfs-formatted volume"). --- ## Development ```bash # Install with dev dependencies uv sync --dev # Format uv run ruff format src/ tests/ # Lint uv run ruff check src/ tests/ # Tests (113 tests) uv run pytest # Run server locally (stdio) uv run mcp-synology-filestation serve ``` See [CLAUDE.md](CLAUDE.md) for the full development context and [SPEC.md](SPEC.md) for DSM API call details and quirks. --- ## Security - Passwords are stored in the **OS keyring only** — never in the config file or logs. - Session IDs and credentials are masked in all debug output. - The `delete` tool requires explicit `confirmed=true` to prevent accidents. --- ## License MIT