Safe, typed Synology DSM administration for humans and AI agents.
dsmctl gives operators and AI agents one DSM-aware control plane for one or
many Synology NAS systems. Reads are explicit, supported changes use a guarded
plan/review/apply workflow, and every surface shares the same typed application
and compatibility layer.
| Surface | Best for | Transport |
|---|---|---|
dsmctl |
Administrators, scripts, and CI jobs | Command line with human or JSON output |
dsmctl-mcp |
A local AI client using the operator's configured profiles | MCP over stdio |
dsmctl-gateway |
A team or operator managing several NAS systems from one service | Streamable HTTP MCP plus a browser Admin console |
- One model across CLI and MCP. Both front ends call the same application operations; MCP never shells out to the CLI and neither surface constructs raw DSM requests.
- Safe changes by default. A mutation first produces a state-bound plan for review. Apply re-reads DSM state, rejects stale or modified plans, performs a typed operation, and verifies the result.
- Independent multi-NAS trust. Each profile has its own DSM URL, TLS trust, session, stored credentials, revision, and remote-client allowlist.
- DSM-aware compatibility. Backend selection happens per operation from the APIs and versions advertised by the target NAS; unsupported or unverified operations fail closed.
- Secrets stay out of agent inputs. Passwords, OTPs, DSM sessions, and bearer tokens are stored or entered through dedicated human-gated surfaces, not request JSON, plans, logs, or MCP tool arguments.
The Gateway Admin UI is a central management console/control plane, not a replacement for DSM and not a content-management system. It manages the relationships around DSM administration:
- NAS profiles isolate connection, TLS, DSM session, and credential state for each managed NAS.
- MCP access gives every client an explicit NAS allowlist and a preset or
custom combination of
nas.read,nas.plan,nas.apply, andlan.discover. - High-risk approvals default to an exact, single-use confirmation inside the active MCP conversation; an optional administrator policy keeps the short-lived, out-of-band Admin-console approval.
- Audit records administrator, token, approval, and remote-execution events without retaining passwords, sessions, or bearer-token values.
See the Gateway Admin guide for the complete setup, OAuth/manual-token, approval, audit, and recovery workflows.
The CLI, stdio MCP server, Gateway, and x86_64 Synology SPK builder are in the
repository today. The public release publishes the dsmctl CLI and the local
stdio dsmctl-mcp server (both bundled in the CLI archives) plus the offline
DSM package.
The current checksum-verified preview,
dsmctl-v7.3.2-21,
publishes the Package Center launch-path fix. The SPK remains a preview until
the hardware/lifecycle matrix in
deploy/synology/SUPPORTED.md is complete.
The public release and distribution plan defines
the exact CLI archives, install scripts, .spk, checksums, release gates, and
GitHub Release layout needed to make this page a direct-download entry point
without overstating current certification.
These version-bound 7.3.2-21 links are live. CLI archives contain dsmctl
and the local stdio dsmctl-mcp server; the Synology package contains the
Gateway Admin UI, remote HTTP MCP service, and its offline runtime image.
| Platform | Direct asset | Status |
|---|---|---|
| Windows amd64 | dsmctl CLI .zip |
Published preview |
| Linux amd64 | dsmctl CLI .tar.gz |
Published preview |
| Synology x86_64 | Offline DSM .spk |
Published hardware-limited preview |
| All assets | GitHub Releases | Includes checksums, license, installers, and support matrix |
Inspect the installer before running it. An explicit version is required for
the preview because GitHub's latest endpoint excludes prereleases.
curl -fsSLO https://github.com/derekvery666/dsmctl/releases/download/dsmctl-v7.3.2-21/install.sh
less install.sh
sh install.sh --version 7.3.2-21Invoke-WebRequest https://github.com/derekvery666/dsmctl/releases/download/dsmctl-v7.3.2-21/install.ps1 -OutFile install.ps1
Get-Content .\install.ps1
.\install.ps1 -Version 7.3.2-21 -AddToPathOn an eligible Synology, download the .spk, review the support matrix, then
use Package Center → Manual Install. The SPK requires x86_64, DSM 7.2.1 or
newer, Container Manager, and Web Station; it does not require Go or a registry
download. The Gateway runtime is bundled inside the .spk; no standalone
container image is published by this release.
CLI ---------+
+--> application --> runtime/session manager --> Synology client façade
MCP server --+ | |
+--> OS credential store +--> compatibility router
|
+--> operation variant --> WebAPI executor --> DSM
CLI and MCP never construct raw DSM requests or select DSM versions. Each operation chooses a backend from the APIs and versions advertised by the NAS, with narrowly scoped DSM-release overrides when behavior actually differs. See the compatibility architecture.
Planned work and multi-agent coordination live in the specification index. Specs describe incomplete work; docs/ describes implemented behavior.
Focused Control Panel module conventions are documented in the Control Panel guide.
Go 1.25 or newer is required.
git clone https://github.com/derekvery666/dsmctl.git
cd dsmctl
go test ./...
go build -o bin/dsmctl ./cmd/dsmctl
go build -o bin/dsmctl-mcp ./cmd/dsmctl-mcp
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/dsmctl-gateway ./cmd/dsmctl-gatewayOn Windows, use bin/dsmctl.exe and bin/dsmctl-mcp.exe.
The current source version is 7.3.2-18. dsmctl versions use
DSM_MAJOR.DSM_MINOR.DSM_PATCH-DSMCTL_BUILD: 7.3.2 names the latest DSM
feature train certified by the release, while 18 is the monotonically
increasing dsmctl build within that train. CLI, stdio MCP, gateway container,
and Synology SPK artifacts built from one revision carry the same full version.
The compatibility train is a concise release-support label, not a global DSM API switch. A NAS on that train or an older supported release still receives operation-scoped backend selection from its advertised APIs; unavailable or unverified operations fail closed. Exact verified DSM builds remain listed in the relevant work items and distribution support matrix.
dsmctl --version
dsmctl-mcp --version
dsmctl-gateway --versionAI agents and first-time operators should begin with the AI agent quick start. It defines explicit target selection, authentication handoff, capability discovery, and the guarded plan/review/apply sequence shared by CLI and MCP.
The CLI has three recurring patterns:
- Connect — create a named profile with
dsmctl nas add, then complete human authentication withdsmctl auth login. - Read — select a profile with
--nas, check the relevantcapabilitiescommand, and add--jsonwhen another program or agent will consume the result. - Change — run the module's
plancommand, review the returned target, risk, summary, warnings, precondition, and hash, then pass that exact unmodified plan and hash to the matchingapplycommand.
Run dsmctl --help for the safe starting workflow and
dsmctl <module> --help for module-specific commands. A binary-only agent can
inspect the complete CLI surface with dsmctl commands list --json, filter to
one module or runnable operations, and retrieve one command's exact usage,
flags, defaults, required inputs, workflow role, and request-schema link with
dsmctl commands show <command path...> --json.
dsmctl commands list --runnable-only --json
dsmctl commands list --prefix account
dsmctl commands list --prefix "control-panel file-services"
dsmctl commands list --prefix drive
dsmctl commands show account inventory --json
dsmctl commands show control-panel file-services plan --json
dsmctl commands show drive config plan --jsonThe complete catalog currently contains 357 visible project commands, of which 298 are directly runnable. Separately, 44 plan commands accept an external typed request JSON file. Discover those request bodies and emit their exact JSON Schema offline with:
dsmctl schema list
dsmctl schema list --json
dsmctl schema show account plan
dsmctl schema show storage plan > storage-request.schema.json
dsmctl account plan --nas office --file request.json --output plan.jsonEach command's normal --help also links back to its exact catalog entry, and
each applicable plan help page prints its schema command and invocation
example. The schema describes JSON structure and rejects unknown properties. The plan
command remains the authority for semantic, DSM capability, current-state, and
safety validation; do not guess fields or treat schema validation as approval.
Add a NAS profile:
dsmctl nas add office --url https://nas.example.com:5001 --username automation --defaultAuthenticate interactively:
dsmctl auth login --nas officeauth login first performs normal system-CA, hostname, and validity
verification. If that verification fails, dsmctl shows every warning together
with the certificate identity, validity, and observed SHA-256 fingerprint, then
asks whether to trust and pin that exact certificate before opening a browser.
This allows an explicitly approved LAN IP even when it is absent from the
certificate SAN. A missing/unparseable certificate or TLS protocol,
cryptographic-handshake, or network failure cannot be pinned. The NAS's own sign-in page then opens in
your web browser; the password — and any two-factor, passkey, or
approve-sign-in step — is entered only there and never passes through dsmctl.
The resulting DSM session (SID, SynoToken, and its renewal keys) is stored per
profile in the operating system's credential store, not in config.json, and
is reused by later CLI and MCP processes.
Inspect or remove the stored session without revealing any secret value:
dsmctl auth status
dsmctl auth logout --nas officeauth status is fully offline. auth logout signs out: it asks DSM to revoke the session (best-effort; an unreachable NAS only skips the revocation) and then deletes the stored copy. nas remove also cleans the removed profile's stored session unless --keep-credentials is passed. Details and cross-process caveats are in the credential lifecycle guide.
Read system information:
dsmctl system info
dsmctl system info --nas office --json
dsmctl nas capabilities --nas office
dsmctl storage capabilities --nas office
dsmctl storage inventory --nas office
dsmctl storage inventory --nas office --json
dsmctl san capabilities --nas office
dsmctl san inventory --nas office --json
dsmctl san plan --nas office --file lun-change.json --output lun-change.plan.json
dsmctl san apply --file lun-change.plan.json --approve <plan-sha256>
dsmctl control-panel time state --nas office --json
dsmctl control-panel file-services capabilities --nas office
dsmctl control-panel file-services smb state --nas office --json
dsmctl control-panel file-services nfs state --nas office --json
dsmctl account capabilities --nas office
dsmctl account inventory --nas office --json
dsmctl account inventory --nas office --memberships --json
dsmctl account inventory --nas office --quotas --application-privileges --principal-type user --principal automation --json
dsmctl share capabilities --nas office
dsmctl share inventory --nas office
dsmctl share inventory --nas office --include-permissions --json
dsmctl access explain --nas office --principal-type user --principal automation --resource-type share --resource team-data --json
dsmctl log capabilities --nas office
dsmctl log list --nas office
dsmctl log list --nas office --type connection --limit 50
dsmctl log list --nas office --from "2026-07-01" --to "2026-07-08"
dsmctl log list --nas office --keyword cache --level error --json
dsmctl notification capabilities --nas office
dsmctl notification mail --nas office --json
dsmctl notification history --nas office --level error --limit 20
dsmctl notification history --nas office --from "2026-07-01" --json
dsmctl package capabilities --nas office
dsmctl package inventory --nas office --json
dsmctl package settings --nas office --json
dsmctl resource-monitor capabilities --nas office
dsmctl resource-monitor current --nas office --json
dsmctl resource-monitor history --nas office --period week --dimension cpu --dimension memory
dsmctl resource-monitor setting --nas office
dsmctl drive admin capabilities --nas office
dsmctl drive admin status --nas office
dsmctl drive admin connections --nas office --json
dsmctl drive admin team-folders --nas office
dsmctl drive admin log list --nas office --username alice --limit 50
dsmctl external-access capabilities --nas office
dsmctl external-access account --nas office --json
dsmctl external-access quickconnect --nas office
dsmctl external-access ddns --nas office --json
dsmctl external-access port-forward --nas office
dsmctl download capabilities --nas office
dsmctl download service --nas office --json
dsmctl download tasks --nas office
dsmctl download statistics --nas office
dsmctl download settings --nas office
dsmctl backup capabilities --nas office
dsmctl backup tasks --nas office
dsmctl backup task 1 --nas office
dsmctl backup versions 1 --nas office
dsmctl backup logs --nas office
dsmctl backup vault --nas office
dsmctl backup luns --nas office
dsmctl backup lun-backups --nas officeDownload tasks are created and controlled through the same guarded plan/apply contract (one action per request: create / pause / resume / delete):
echo '{"action":"create","uris":["https://example.com/file.iso"],"destination":"Share"}' | dsmctl download tasks plan --nas office -o task.plan.json
dsmctl download tasks apply --nas office -f task.plan.json --approve <hash-from-plan>BitTorrent settings are changed the same way (patch-only, full-object merge):
echo '{"bt":{"max_upload_rate":15}}' | dsmctl download settings plan --nas office -o bt.plan.json
dsmctl download settings apply --nas office -f bt.plan.json --approve <hash-from-plan>Hyper Backup tasks are run, canceled, and created through the same contract
(the plan is bound to the observed task state, so it goes stale if the task
inventory changes in the meantime). A create can target a shared folder on the
NAS itself, another NAS known to dsmctl (target_nas — the stored credential
is resolved at apply time and never enters the plan), or an explicit host with
a password_ref:
echo '{"action":"backup","task_id":1}' | dsmctl backup tasks plan --nas office -o run.plan.json
dsmctl backup tasks apply --nas office -f run.plan.json --approve <hash-from-plan>
echo '{"action":"create","create":{"task_name":"nightly-homes","source_folders":["/homes"],"target_nas":"vault-nas","destination_share":"hb_vault"}}' \
| dsmctl backup tasks plan --nas office -o create.plan.json
dsmctl backup tasks apply --nas office -f create.plan.json --approve <hash-from-plan>The one External Access write so far is the QuickConnect relay toggle, through the same plan/apply contract:
echo '{"relay_enabled": false}' | dsmctl external-access quickconnect plan --nas office -o relay.plan.json
dsmctl external-access quickconnect apply --nas office -f relay.plan.json --approve <hash-from-plan>Account and shared-folder writes use a two-step plan/apply contract. Put the desired change in JSON, create a plan bound to the current DSM resource ID/state, review it, then apply that exact plan with its hash:
dsmctl account plan --nas office --file create-user.json --output create-user.plan.json
dsmctl account apply --file create-user.plan.json --approve <hash-from-plan>
dsmctl share plan --nas office --file create-share.json --output create-share.plan.json
dsmctl share apply --file create-share.plan.json --approve <hash-from-plan>
dsmctl control-panel file-services plan --nas office --file smb-change.json --output smb-change.plan.json
dsmctl control-panel file-services apply --file smb-change.plan.json --approve <hash-from-plan>
dsmctl control-panel time plan --nas office --file time-change.json --output time-change.plan.json
dsmctl control-panel time apply --file time-change.plan.json --approve <hash-from-plan>
dsmctl package plan --nas office --file package-change.json --output package-change.plan.json
dsmctl package apply --file package-change.plan.json --approve <hash-from-plan>
dsmctl resource-monitor plan-recording --nas office --enable --output recording.plan.json
dsmctl resource-monitor apply-recording --file recording.plan.json --approve <hash-from-plan>Package Center changes use the same plan/apply contract: a lifecycle action
(start, stop, or uninstall) on one installed package, or a settings
change to the automatic-update policy. The publisher trust level is read-only
(no DSM write endpoint). See the Package Center guide.
Shared-folder btrfs snapshots (list with attributes, guarded take\edit\delete, per-share snapshot configuration, retention policy, and the Snapshot Replication log and replication-plan reads) are covered in the Snapshot Replication guide.
User passwords are never included in requests or plans. A user create/change refers to an apply-time environment variable such as "credential_ref":"env:DSMCTL_NEW_USER_PASSWORD". Request formats and examples are in account and share management.
Manage more than one NAS:
dsmctl nas add lab --url https://192.168.10.20:5001 --username automation
dsmctl nas list
dsmctl auth login --nas lab
dsmctl system info --nas lab
dsmctl nas use labThe default configuration path is the platform user-config directory, such as %AppData%\dsmctl\config.json on Windows. Override it with --config or DSMCTL_CONFIG.
Example configuration (no secret values):
{
"default_nas": "office",
"nas": {
"office": {
"url": "https://nas.example.com:5001",
"username": "automation",
"password_env": "DSMCTL_PASSWORD_OFFICE",
"timeout_seconds": 30
}
}
}password_env remains a non-interactive password fallback for automation. The runtime resolves the account password keyring-first (including one stored by dsmctl provision) and then from password_env, consulting either only when no resumable web-login session exists for the profile:
$env:DSMCTL_PASSWORD_OFFICE = "your-password"Two-factor authentication needs no special handling: the challenge is completed in the browser during dsmctl auth login, and the stored session is what later processes reuse.
TLS verification is automatic. Unknown-issuer certificates are offered for an
explicit observed-fingerprint pin during auth login; a changed pin fails
closed and must be confirmed again. The legacy
--insecure-skip-tls-verify profile option is only for an explicitly isolated
test NAS and bypasses this protection entirely.
For the recommended tool-call order and mutation approval contract, see the AI agent quick start. MCP clients also receive the same guidance in the server's initialize instructions.
Run the stdio server directly, or register the bundled dsmctl-mcp binary with
an MCP client that supports stdio, e.g. claude mcp add <name> <path-to-dsmctl-mcp>:
dsmctl-mcp --config C:\path\to\config.jsonThis local path needs no certificate or DNS — dsmctl pins the NAS certificate by fingerprint. The remote gateway below is for clients that connect by URL and requires HTTPS with a certificate the client trusts (free on a domain-less NAS via Synology DDNS + Let's Encrypt).
The portable HTTP gateway and its managed remote security boundary are documented in the gateway guide. Production amd64 Linux Compose/Podman deployment is in deploy/linux, and the offline x86_64 DSM package is described in the Synology package guide.
Available tools:
list_nas: list safe profile metadata; secrets are never returned.get_auth_status: report per-NAS credential presence, the password environment variable name and set state, and this process's session state; fully offline and never returns secret values.get_system_info: authenticate to a selected profile and return normalized DSM system information.get_capabilities: report discovered APIs, DSM release, compatibility quirks, and the backend selected for each operation.get_storage_capabilities: report the storage operations currently exposed for a selected NAS and the selected DSM backend.get_storage_state: return normalized disk, storage-pool, RAID, volume, SSD cache, capacity, and health state without changing the NAS.plan_storage_change: validate a storage-pool, volume, or SSD cache intent and return a topology-, capacity-, and safety-state-bound approval plan without mutating DSM.apply_storage_plan: apply an approved, unchanged storage-pool, volume, or SSD cache plan and verify the postcondition.get_san_capabilities: report SAN Manager inventory and guarded mutation support plus the selected backends.get_san_state: return normalized iSCSI targets, LUNs, and their stable-ID mapping graph using bulk reads.plan_san_change: validate a target, LUN, or mapping intent and return a state-bound approval plan without mutating DSM.apply_san_plan: apply an approved, unchanged SAN plan and verify stable-ID and mapping-graph postconditions.get_control_panel_time_capabilities: report read and guarded set support plus the selected backend for the focused time/NTP module.get_control_panel_time_state: return normalized time zone, display formats, synchronization mode, and NTP servers.plan_control_panel_time_change: validate a patch-only time zone, display format, or NTP request and return a full-state-bound approval plan; manual mode and wall-clock changes are rejected.apply_control_panel_time_plan: apply an approved, unchanged time plan and verify the configuration without claiming NTP reachability.get_file_service_capabilities: report independent SMB/NFS read and guarded setting backends.get_smb_state: return normalized global SMB service, workgroup, protocol, encryption, and signing settings.get_nfs_state: return normalized global NFS service, protocol, and NFSv4 domain settings.plan_file_service_change: validate a patch-only SMB/NFS request and return a full-state-bound approval plan.apply_file_service_plan: apply an approved unchanged SMB/NFS plan and verify the postcondition.get_account_capabilities: report local user, group, membership, quota, and application privilege operations plus their selected DSM backends.get_account_state: return normalized local users and groups; membership, quota, and explicit application privilege expansion is opt-in and may be filtered to one principal.plan_account_change: validate a user, group, membership, quota, or application privilege change and return a current-state-bound approval plan without mutating DSM.apply_account_plan: apply an approved, unchanged account plan and verify the postcondition.get_share_capabilities: report shared-folder and permission capabilities plus their selected DSM backends.get_share_state: return normalized shared folders; setinclude_permissionsonly when the user/group permission matrix is required.plan_share_change: validate a shared-folder or permission change and return an approval plan without mutating DSM.apply_share_plan: apply an approved, unchanged shared-folder plan and verify the postcondition.explain_effective_access: explain one principal's share or application access with direct/group evidence and conservative indeterminate results for custom rules.get_log_capabilities: report whether DSM system log reading is available and the selected backend.get_logs: read normalized DSM system log entries with optional keyword, log-type, severity, and paging filters; never mutates or clears logs.get_package_capabilities: report supported Package Center inventory, settings, and lifecycle operations plus the selected DSM backends; install and update report unsupported.get_package_state: return the normalized installed-package inventory with run status and start/stop/uninstall eligibility without changing packages.get_package_settings: return normalized global Package Center settings (publisher trust level and automatic-update policy); read-only.get_drive_admin_capabilities: report supported Drive Admin operations, the selected backends, and the installed SynologyDrive package version/running state the selection used.get_drive_admin_status: return the Drive service status with installed-package evidence; read-only.get_drive_admin_connections: list active Drive client connections; read-only.get_drive_admin_team_folders: list Drive team folders from the admin perspective; read-only.get_drive_admin_logs: read Drive server logs with keyword/username/target/time-range filters; read-only.get_external_access_capabilities: report which External Access read areas (Synology Account, QuickConnect, DDNS) are available and the DSM backend selected for each; read-only.get_external_access_account: read the Synology Account (MyDS) binding — signed-in/activated state plus the non-secret account identifier, customer id, and serial; the account token is never returned; read-only.get_external_access_quickconnect: read QuickConnect configuration, relay setting, live status, and per-service external exposure; read-only.get_external_access_ddns: read configured DDNS records and detected WAN addresses; read-only.get_external_access_port_forward: read the paired router configuration and configured port-forwarding rules; read-only.plan_external_access_quickconnect_change: validate a QuickConnect relay-toggle patch and return a state-bound approval plan without mutating DSM.apply_external_access_quickconnect_plan: apply an approved, unchanged QuickConnect relay plan and verify the relay setting.get_download_station_capabilities: report Download Station read support, installed-package evidence, and selected backends; package-gated, read-only.get_download_station_service: read Download Station service configuration (version, destination, rate limits, schedule); read-only.get_download_station_tasks: list Download Station download tasks with type, size, status, and transfer speed; read-only.get_download_station_statistics: read the current aggregate download/upload speed; read-only.get_download_station_settings: read the full detailed settings (BT, eMule, FTP/HTTP, NZB, auto-extraction, location, RSS, scheduler); passwords never returned; read-only.plan_download_station_task_change: validate a task create/pause/resume/delete request and return a target-bound approval plan without mutating DSM.apply_download_station_task_plan: apply an approved, unchanged task plan and verify the postcondition (created/paused/resumed/deleted).plan_download_station_settings_change: validate a settings patch for exactly one group (BT, FTP/HTTP, RSS, location, scheduler, global, auto-extraction, or NZB) and return a state-bound approval plan without mutating DSM.apply_download_station_settings_plan: apply an approved, unchanged settings plan (full-object merge) and verify each changed field.get_hyper_backup_capabilities: report Hyper Backup read/action support and the HyperBackup + HyperBackupVault package evidence; package-gated, read-only.get_hyper_backup_tasks: list backup tasks with state, live activity, last result, next scheduled run, and source folders; read-only.get_hyper_backup_task: read one task's repository, transfer options, live status/progress, and destination reachability; read-only.get_hyper_backup_versions: list the backup versions one task has produced; read-only.get_hyper_backup_logs: read the Hyper Backup log feed with per-level totals; read-only.get_hyper_backup_applications: list the packages Hyper Backup can include in a backup task, with per-application eligibility; read-only.get_hyper_backup_luns: list the file/regular LUNs the legacy LUN-backup engine can protect; read-only.get_hyper_backup_lun_backups: list the legacy LUN backup tasks with activity and last result; read-only.plan_hyper_backup_lun_backup_create: validate a local LUN backup create and return a plan bound to the source LUN and existing task names without mutating DSM.apply_hyper_backup_lun_backup_plan: apply an approved, unchanged LUN backup plan (apply_lun loclunbkp) and verify the task exists (and the first backup started when backup_now is set).get_hyper_backup_vault: read the Hyper Backup Vault view (inbound targets, parallel-session limit); requires HyperBackupVault; read-only.plan_hyper_backup_task_change: validate a run-backup-now or cancel request and return a plan bound to the observed task state without mutating DSM.apply_hyper_backup_task_plan: apply an approved, unchanged task plan and verify the postcondition (run started, or the running backup stopped).plan_package_change: validate a start/stop/uninstall lifecycle action or an automatic-update settings change and return a state-bound approval plan without mutating DSM; install, update, and trust-level changes are rejected.apply_package_plan: apply an approved, unchanged Package Center plan (lifecycle or settings) and verify the terminal package-state or settings postcondition.
Storage-pool create, add-disk expansion, and delete, plus volume create, expansion, and delete, require independently selected backends and guarded plan/apply; storage-pool RAID migration remains fail-closed. SSD cache create and remove (read-only or read-write) are also guarded plan/apply on a cache resource; SSD cache expand and read-only/read-write conversion are modeled but fail closed on DSMs whose flashcache API exposes only create and remove. Local user/group CRUD, memberships, per-user/group quotas, explicit application access, shared-folder CRUD, normalized none/read/write/deny share permissions, and guarded SAN target/LUN/mapping lifecycles are also available only through plan/apply. SAN deletes refuse active sessions or mappings, mappings never cascade-delete endpoints, and LUN capacity is checked against the selected backing volume. Guarded time-module changes never write wall-clock values or switch to manual synchronization, and NTP servers are validated for syntax without any reachability claim. Package Center exposes installed-package inventory, global settings (publisher trust level and automatic-update policy), guarded automatic-update settings changes, and guarded start/stop/uninstall on installed packages; uninstall is refused for packages DSM reports as non-removable, and start/stop/uninstall verify the terminal package state. The publisher trust level is read-only (no DSM write endpoint). Package install-from-repository and update are modeled but fail closed because they contact the online repository, run asynchronously, and download and run remote code. The trust-level, beta-channel, and default-volume writes, the online catalog browse, and per-package application-specific settings are also deferred. The Drive Admin module is read-only in this slice (service status, connections, team folders, logs); it selects operations from the installed SynologyDrive package version, re-checks that version before every command, and fails closed on Drive releases older than the verified 3.0 baseline or when the package is missing. Team-folder changes are modeled but fail closed. Encrypted shares, WORM, custom Windows ACLs, IP-specific application rules, and SAN snapshots/clones remain out of scope.
Account expansion is opt-in because DSM exposes quota and application rules per principal. For large systems, filter get_account_state or account inventory with principal_type plus principal instead of reading every local principal. Membership expansion scales with local groups rather than users.
Permission expansion is opt-in because DSM exposes permissions by user and group. get_share_state {"include_permissions":true} and the matching CLI flag perform additional read-only calls for every local user and group, then aggregate the results by shared folder.
MCP intentionally has no tool that accepts a password or OTP. If interactive authentication is required, it returns an actionable error asking the user to run dsmctl auth login --nas <name> first.
An opt-in live smoke test verifies the real stdio process boundary:
$env:DSMCTL_MCP_BINARY = (Resolve-Path .\bin\dsmctl-mcp.exe).Path
$env:DSMCTL_LIVE_NAS = "office"
go test ./integration -run TestMCPGetSystemInfoLive -v- Passwords, OTP values, DSM device IDs, SIDs, and SynoTokens are never stored in the config file or returned by CLI/MCP display models.
- Account inventory never returns passwords, hashes, recovery codes, or other authentication material.
- User create/password updates accept only an
env:NAMEreference; the secret is resolved at apply time and is absent from the request, plan, hash, result, and logs. - Every account/share mutation re-reads DSM state before apply. Deletes are bound to the planned UID/GID or shared-folder UUID plus a state fingerprint.
- Built-in
admin,guest,root,administrators,users,http,home, andhomesresources cannot be managed by mutation commands. - Login parameters use an HTTPS POST form, not URL query parameters.
- OTP values are short-lived and never persisted.
- Web-login sessions (SID, SynoToken, and renewal keys) use Windows Credential Manager, macOS Keychain, or Linux Secret Service; dsmctl adds no encryption layer of its own because the OS store already provides at-rest encryption, and on hosts without a store (headless Linux) it fails closed instead of writing secrets to disk.
- dsmctl never requires storing a password: web login keeps it in the browser.
dsmctl provisionoptionally stores a generated administrator password in the OS credential store, and the runtime then resolves the account password keyring-first (falling back to the password environment variable), so a provisioned NAS re-authenticates for every command without a browser. A stored password is retrievable only by a human at a terminal viadsmctl auth reveal-password(an interactive-terminal check plus a typed confirmation) and is never returned by any MCP tool. - Web login sends no password, OTP, session, or one-time login code until the NAS passes system-CA verification or the user confirms the freshly observed leaf-certificate fingerprint after reviewing its warnings. A pin authenticates that exact leaf for the profile in place of CA, hostname, and validity checks; certificate rotation or a different certificate fails closed and requires another explicit confirmation.
- Credential status reports booleans, metadata, and the environment variable name only; session IDs, tokens, keys, and password values are never displayed.
auth logoutandnas removerevoke the DSM session server-side (best-effort, with a bounded wait) before deleting the stored copy, so a signed-out session cannot be replayed; when the NAS is unreachable the local copy is still removed and the session lapses on its own expiry.- Closing a process never invalidates the stored web-login session; only an explicit sign-out does.
- Every NAS profile owns a separate stored session.
- DSM session errors 106 and 119 trigger one automatic re-login and retry when the client logged in with a password; a client using a stored web-login session instead recovers without a password — it re-reads the store (picking up a newer
auth loginfrom another process) or renews the session with the stored Noise resume keys — and otherwise reports that a newauth loginis required.
A management feature normally adds:
- A stable result model and one or more variants under
internal/synology/operations/<operation>. - Capability matchers for the shared backend and only the version-specific overrides that differ.
- A use case and policy under
internal/application. - Thin CLI and MCP adapters.
Raw generic DSM calls are not exposed as MCP tools. Mutating operations use guarded plan/apply semantics as the project expands into Control Panel and SAN management.
dsmctl is available under the Apache License 2.0.




