fix: v0.9.1 — clearer messages for exec/redeploy/check_image_updates

Three live-verified MCP weaknesses (update run 2026-06-22):

- exec_in_container: SYNO.Docker.Container/exec does not exist on this DSM
  firmware (code 103, like pause/unpause). Catch it and return a guiding
  "not supported on this firmware" message instead of the raw DSM error;
  the tool stays available for firmwares that do implement exec.
- redeploy_project: the failure hint suggested stop_project + start_project,
  but start_project does not recreate on a new image (it restarts the old
  one). Both failure hints now point back at redeploy_project and warn about
  parallel pull_image lock contention (DSM 2101/2202).
- check_image_updates: docstring and output now state it only reflects DSM
  digest drift on already-pulled tags and does NOT discover newer version
  tags (use list_image_tags + release notes for that).

Tests updated accordingly; CHANGELOG + version bumped to 0.9.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 16:32:22 +02:00
parent 46b36f6b08
commit 04ffaa457b
9 changed files with 77 additions and 7 deletions
+28
View File
@@ -188,6 +188,34 @@ async def test_exec_in_container_confirmed():
assert "Exit code: 0" in result
@pytest.mark.asyncio
async def test_exec_in_container_unsupported_firmware():
"""DSM code 103 ('Method does not exist') → clear 'not supported' guidance,
not the raw DSM error."""
from mcp_synology_container.dsm_client import SynologyError
from mcp_synology_container.modules.containers import register_containers
client = AsyncMock()
async def mock_request(api, method, **kwargs):
if api == "SYNO.Docker.Container" and method == "list":
return {"containers": []}
if api == "SYNO.Docker.Container" and method == "exec":
raise SynologyError("Method does not exist", code=103)
return {}
client.request.side_effect = mock_request
mcp, tools = make_mock_mcp()
register_containers(mcp, make_config(), client)
result = await tools["exec_in_container"]("myapp_web", "ls /app", confirmed=True)
assert "not supported on this DSM firmware" in result
assert "filestation" in result.lower()
# The raw DSM phrasing must not leak as the only message.
assert not result.startswith("Error executing command")
# ──────────────────────────────────────────────────────────────────────────────
# container_stats
# ──────────────────────────────────────────────────────────────────────────────