Files
mcp-synology-container/CLAUDE.md
T
marcus 3f73ed0aef feat: v0.3.2 — delete_project tool
Closes the project lifecycle (create → start/stop/redeploy → delete).
The tool calls SYNO.Docker.Project/delete with the UUID JSON-encoded
as the `id` parameter (per DSM convention) and removes only the
Container Manager registration — the project folder and compose
file remain on the NAS. This mirrors DSM's own "Delete project"
behaviour, not a bug; the success message states the folder was
preserved so the user is not surprised.

Safety:
- Project-name validation runs before any I/O.
- A `_find_project` pre-flight returns "not found" with a clear
  message rather than letting DSM reject an unknown UUID.
- No automatic stop. If the project is RUNNING and DSM rejects
  the delete, the response tells the user to `stop_project` first
  rather than silently halting containers under the guise of a
  "delete" call.
- Requires confirmed=True; preview shows name, UUID, status, full
  path, and share path so the user can verify before deleting.

Tests cover preview-only, not-found, invalid-name, happy path
(verifies the UUID is JSON-encoded in the delete call), and the
running-project rejection path that surfaces the stop_project hint.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 11:29:09 +02:00

101 lines
4.1 KiB
Markdown

# mcp-synology-container
## Project
`mcp-synology-container` is an MCP server for managing Docker projects on a
Synology DiskStation via Container Manager. It exposes tools for projects,
containers, images, compose files, networks, and system housekeeping.
---
## Tech stack
| | |
|---|---|
| **Language** | Python 3.12+, `uv` |
| **Key deps** | MCP SDK, `httpx`, `keyring`, `click`, `rich` |
| **Compose paths** | `/volume1/docker/<project>/` (default Synology layout) |
---
## Deploy workflow (after every code change)
```
1. Claude Code commits and pushes
2. uv tool install --reinstall git+<repo-url>
3. Restart Claude Desktop (tray icon → Quit → relaunch)
```
**Push retry:** the Gitea remote (`gitea.gecheckt.de`) occasionally
returns `Unauthorized` on the first push attempt. If `git push` fails
with an auth error, wait 1 s and retry once before reporting back.
Only a second consecutive failure is treated as a real auth problem.
---
## Implemented tools (25)
| Category | Tools |
|---|---|
| Projects | `list_projects`, `get_project_status`, `start_project`, `stop_project`, `redeploy_project`, `create_project`, `delete_project` |
| Containers | `list_containers`, `get_container_status`, `get_container_logs`, `exec_in_container`, `container_stats`, `delete_container` |
| Compose | `read_compose`, `update_compose`, `update_image_tag`, `update_env_var` |
| Images | `check_image_updates`, `list_images`, `delete_image` |
| Networks | `list_networks`, `create_network`, `delete_network` |
| System | `system_df`, `system_prune` |
---
## DSM API quirks
- **Hash-prefixed container names** — DSM sometimes returns names like
`a1b2c3d4e5f6_myservice` when the compose service name differs from
`container_name`. All container tools strip this prefix transparently via
`_strip_hash_prefix` / `_resolve_container_name`.
- **Async project start** — `SYNO.Docker.Project/start` returns immediately
while containers are still initialising. `redeploy_project` polls
`SYNO.Docker.Project/list` every 2 s for up to 30 s after issuing start.
- **Image delete** — requires a form-encoded POST with a JSON `images` array
(confirmed via browser DevTools); uses `DsmClient.post_request()`.
- **`SYNO.Docker.Image/pull`** — API method exists but behaviour varies by
DSM version; not exposed as a standalone tool.
- **`SYNO.Docker.Volume`** — endpoint does not exist; volume management is
not available via the DSM WebAPI.
- **`SYNO.Docker.Registry/get`** — does not behave as documented; registry
listing omitted.
---
## Implementation rules
- Confirmation required before destructive operations: `stop_project`,
`redeploy_project`, `create_project`, `delete_project`,
`exec_in_container`, `update_image_tag`, `update_env_var`,
`update_compose`, `delete_container`
- After compose changes: suggest `redeploy_project`
- DSM errors → human-readable message, no stack traces
- No secrets in stderr output
- Type hints and docstrings everywhere
- Formatter: `ruff format` · Linter: `ruff check` · Tests: `pytest`
- All text (docstrings, comments, README): English
- **CHANGELOG.md:** every user-visible change (bug fix, new/changed
tool, behavior change, security fix, dependency bump) gets a
`CHANGELOG.md` entry in the same commit — under a `## [Unreleased]`
heading between releases, which becomes `## [X.Y.Z] - YYYY-MM-DD` on
version bump. Pure internal cleanup (renames without external callers,
comment-only edits, ruff autofix) needs no entry. Don't ship a release
with a stale changelog (this was the C-2 gap that caused 0.2.7 and
0.2.8 to ship undocumented).
- **Version consistency:** the package version lives in `pyproject.toml`
and must stay in sync with `uv.lock` and the `[X.Y.Z]` heading in
`CHANGELOG.md`. `src/mcp_synology_container/__init__.py` derives
`__version__` from `importlib.metadata` and is never hand-edited.
Every version bump touches all three files in the same commit.
---
## DSM API reference
- `cmeans/mcp-synology` (GitHub) — auth, keyring, CLI structure
- `N4S4/synology-api` `docker_api.py` (GitHub) — `SYNO.Docker.*` calls