Skip to main content
Glama

omv-mcp — MCP server for the OpenMediaVault NAS

Manage and inspect an OpenMediaVault NAS from any MCP-capable AI harness (Claude Code, Claude Desktop, Copilot, Cursor, Codex, …): 48 tools across system, storage/SMART health, Docker, and Portainer stacks, plus resources, prompts, and completions.

Install (one command)

Install uv if you don't have it, then run setup:

# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
uvx omv-mcp setup
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
uvx omv-mcp setup

Setup asks for your NAS address and SSH login, then does everything else:

  1. Passwordless SSH — if key login isn't set up yet, it installs your public key using your OMV password once (never stored; an ed25519 key is generated if you don't have one).

  2. Live verification — runs real omv-rpc and docker ps on the NAS and shows the results.

  3. Portainer (optional) — paste an API key to enable the compose-stack tools (Portainer → user icon → Access tokens); blank to skip.

  4. Registration — registers with Claude Code automatically and prints paste-ready config blocks for Claude Desktop, VS Code, and Cursor.

Requirements: root SSH login on the NAS (OMV's default) and any address that reaches it — a LAN IP like 192.168.x.x is what v1 is tested on. Tailscale IPs usually work as-is; official Tailscale support lands in v2.

Related MCP server: linux-ssh-mcp-server

Two modes, one package

Mode B — run anywhere (default). The server runs on your machine and executes every command on the NAS over one persistent SSH connection (~25 ms per call after the handshake). Nothing is installed on the NAS.

your machine                                 NAS (OMV, Debian)
┌────────────────────────────┐               ┌──────────────────────┐
│ MCP client ──▶ omv-mcp     │ ═ ssh (1) ══▶ │ omv-rpc / docker / … │
│              (uvx omv-mcp) │ ─ tunnel ───▶ │ Portainer :9000      │
└────────────────────────────┘               └──────────────────────┘

Mode A — run on the NAS (advanced). Choose A during setup: it installs uv on the NAS and registers the client to launch the server there over stdio-on-SSH. Commands are then local subprocess calls on the NAS.

your machine                        NAS (OMV, Debian)
┌─────────────┐                     ┌────────────────────────────────┐
│ MCP client ─┼── ssh … uvx omv-mcp ▶ omv-mcp ─▶ omv-rpc / docker / …│
└─────────────┘                     └────────────────────────────────┘

The selector is one config key: OMV_HOST set → Mode B; unset → Mode A.

Configuration

omv-mcp setup writes this for you. File location: %APPDATA%\omv-mcp\config.env (Windows) or ~/.config/omv-mcp/config.env (macOS/Linux/NAS). Real environment variables override the file.

Key

Default

Meaning

OMV_HOST

(empty)

NAS address. Set = Mode B (remote); empty = Mode A (on-NAS).

OMV_SSH_USER

root

SSH user (v1 requires root).

OMV_SSH_PORT

22

SSH port.

OMV_SSH_KEY

(empty)

Explicit private key path; default is ssh-agent, then ~/.ssh keys.

PORTAINER_URL

(auto)

Explicit Portainer API URL. Auto = localhost:9000 in Mode A, SSH tunnel in Mode B.

PORTAINER_API_KEY

(empty)

Enables the stack tools.

PORTAINER_ENDPOINT_ID

1

Portainer endpoint id.

Host keys are trust-on-first-use, pinned in <config dir>/known_hosts; a changed host key fails loudly. Dropped SSH connections reconnect once, transparently. In Mode B, Portainer traffic rides an SSH tunnel — the API key never crosses your network in cleartext, and no port besides SSH needs to be reachable.

Register a client manually

Setup prints these for you; for reference (Mode B):

{ "mcpServers": { "omv": { "command": "uvx", "args": ["omv-mcp"] } } }
claude mcp add omv -- uvx omv-mcp

VS Code (.vscode/mcp.json) uses "servers" with "type": "stdio", same command. For Mode A, setup prints the equivalent ssh …@nas -T -- uvx omv-mcp form.

Updating: uvx caches the package; refresh with uvx omv-mcp@latest --version (or uv cache clean omv-mcp).

⚠️ Safety

This server executes as root on the NAS and is meant for a single trusted user. There is no deny-list — run_command and omv_rpc are unrestricted root. The destructive named tools (reboot, shutdown, apply_updates, docker_prune, stop_container, stop_stack, restart_stack, update_stack, run_smart_test) require confirm=True. Your Portainer API key is stored in the per-user config file on whichever machine runs the server. Do not expose this server to untrusted clients.

Tools

Group

Tools

System

get_system_info, disk_usage, list_block_devices, top_processes, memory_info, network_info, service_status, service_logs, available_updates, apply_updates ⚠️, run_command ⚠️, reboot ⚠️, shutdown ⚠️

Storage / health

list_filesystems, list_disks, storage_summary, smart_status, smart_health, smart_attributes, smart_selftest_log, run_smart_test ⚠️, disk_temperatures, cpu_temp, sensors_readout, list_shared_folders, list_smb_shares, omv_rpc ⚠️

Users/groups

list_users, list_groups

Docker

list_containers, container_stats, container_inspect, container_logs, list_images, list_volumes, list_networks, docker_system_df, start_container, restart_container, stop_container ⚠️, docker_exec ⚠️, docker_prune ⚠️

Portainer stacks

list_stacks, get_stack_compose, start_stack, stop_stack ⚠️, restart_stack ⚠️, update_stack ⚠️

⚠️ = unrestricted root or requires confirm=True.

Resources

Read-only NAS context any client can pull without a tool call:

URI

Content

omv://system

live host/OMV info (JSON)

omv://storage/overview

per-mount usage for OS + data disks (JSON)

omv://health

composite: SMART overall + disk/CPU temps + df (JSON)

omv://stacks

Portainer stacks (JSON)

omv://container/{name}/logs

last 100 log lines (template)

omv://stack/{stack_id}/compose

compose YAML (template)

Prompts & completions

Canned diagnostic workflows — diagnose_storage_health, triage_containers, whats_using_space, audit_shares_and_permissions — plus argument autocompletion for container names, stack ids, and share names.

apply_updates, docker_prune, stop_stack, restart_stack, and update_stack are async and emit MCP log/progress notifications while they run.

Development

git clone https://github.com/vnaveenb/openmediavault-mcp-ssh.git
cd openmediavault-mcp-ssh
uv sync                                  # venv with Python 3.12 + deps
uv run pytest                            # unit tests (no NAS needed)
uv run python tests/smoke_client.py      # live smoke test (uses your config.env)
uv run omv-mcp setup --dev               # register THIS checkout instead of PyPI

PRs welcome! See CONTRIBUTING.md for the workflow (GitHub Flow, conventional commits, squash-merge).

⚠️ This server runs as root on the NAS. Review every change with that in mind — never merge a PR you haven't read and understood.

License

MIT © 2026 Naveen Busiraju.

Available Tools

48 tools
apply_updatesA
Destructive

Install pending APT upgrades (apt-get -y upgrade, noninteractive). Requires confirm=True. Run available_updates first to see what changes. Returns {exit_code, output}.

Inputs: confirm.

available_updatesA

APT packages with pending upgrades (name/versions only). {count, packages}.

Inputs: no named parameters.

container_inspectA

Full docker inspect for one container (config, mounts, network, state).

Inputs: name (required).

container_logsA

Last tail lines of a container's logs.

Inputs: name (required), tail. Returns: result

container_statsA

Live per-container CPU%, memory, net/block I/O (docker stats --no-stream).

Inputs: no named parameters.

cpu_tempB

CPU temperature in °C (OMV CpuTemp plugin).

Inputs: no named parameters.

disk_temperaturesA

Current temperature (°C) of every physical disk (smartctl -A per disk).

Inputs: no named parameters.

disk_usageA

Human-readable filesystem usage (df -h).

Inputs: no named parameters. Returns: result

docker_execA
Destructive

Run a shell command inside a container as its user. UNRESTRICTED -- no allow/deny-list. Returns {stdout, stderr, exit_code}.

Inputs: cmd (required), name (required), timeout.

docker_pruneA
Destructive

Reclaim space by removing stopped containers, dangling images, unused networks and build cache (docker system prune -f). Set volumes=True to also drop anonymous volumes (DELETES their data). Requires confirm=True.

Inputs: confirm, volumes.

docker_system_dfA

Disk usage + reclaimable space by images/containers/volumes/build cache (docker system df).

Inputs: no named parameters.

get_stack_composeC

The full compose file for a Portainer stack.

Inputs: stack_id (required). Returns: result

get_system_infoA

OMV/host info: hostname, OMV version, kernel, CPU, memory, uptime, load.

Inputs: no named parameters.

list_block_devicesA

Block devices with size/model/serial/fs/mountpoint/uuid (lsblk -J).

Inputs: no named parameters.

list_containersA

Docker containers with names/status/image (docker ps; include_all adds stopped).

Inputs: include_all.

list_disksB

Physical disk devices known to OMV.

Inputs: no named parameters.

list_filesystemsA

All filesystems OMV knows about (mounted or not).

Inputs: no named parameters.

list_groupsC

Non-system OMV groups.

Inputs: no named parameters.

list_imagesB

Docker images (repo, tag, id, size).

Inputs: no named parameters.

list_networksC

Docker networks (id, name, driver, scope).

Inputs: no named parameters.

list_shared_foldersB

OMV shared folders (name, path, device).

Inputs: no named parameters.

list_smb_sharesB

Configured SMB/CIFS shares.

Inputs: no named parameters.

list_stacksA

Portainer stacks (id, name, status).

Inputs: no named parameters.

list_usersC

Non-system OMV users.

Inputs: no named parameters.

list_volumesB

Docker volumes (name, driver, mountpoint).

Inputs: no named parameters.

memory_infoB

RAM and swap usage in bytes (free -b).

Inputs: no named parameters.

network_infoA

Network interfaces with addresses (ip -j addr); virtual docker/veth interfaces are filtered out for signal.

Inputs: no named parameters.

omv_rpcA
Destructive

Generic OMV RPC passthrough: omv-rpc -u admin <service> <method> <params>. UNRESTRICTED -- can call mutating methods too. Discover methods by grepping /usr/share/openmediavault/engined/rpc/*.inc on the host.

Inputs: method (required), service (required), params.

rebootA
Destructive

Reboot the NAS. Requires confirm=True.

Inputs: confirm.

restart_containerA
Destructive

Restart a single container (seconds of downtime).

Inputs: name (required).

restart_stackA
Destructive

Stop then start a stack (downtime during the cycle). Requires confirm=True.

Inputs: stack_id (required), confirm.

run_commandA
Destructive

Run an arbitrary shell command on the NAS as root. UNRESTRICTED and UNGUARDED -- there is no allow/deny-list. Prefer the specific tools (omv_rpc, docker, stacks) over hand-editing config. Returns {stdout, stderr, exit_code}.

Inputs: cmd (required), timeout.

run_smart_testA

Start a SMART self-test on a device. kind is 'short', 'long', or 'conveyance'. The test runs in the background (adds drive load); poll results later with smart_selftest_log. Requires confirm=True.

Inputs: device (required), kind, confirm.

sensors_readoutA

All lm-sensors readings as structured JSON (sensors -j).

Inputs: no named parameters.

service_logsA

Last lines journal entries for a systemd unit (journalctl -u).

Inputs: unit (required), lines. Returns: result

service_statusB

systemd active/enabled state per unit (systemctl, fast). Defaults to a common NAS set if none given.

Inputs: units.

shutdownA
Destructive

Power off the NAS. Requires confirm=True.

Inputs: confirm.

smart_attributesA

Full SMART attribute table for one device (smartctl -A), plus current temperature and power-on hours. device is 'sda' or '/dev/sda'.

Inputs: device (required).

smart_healthA

SMART overall-health self-assessment for one device (PASSED/FAILED). device is 'sda' or '/dev/sda'.

Inputs: device (required).

smart_selftest_logB

SMART self-test history for one device (smartctl -l selftest).

Inputs: device (required).

smart_statusB

S.M.A.R.T. overview per device (overall health status, from OMV).

Inputs: no named parameters.

start_containerB

Start a stopped container.

Inputs: name (required).

start_stackA

Start a stopped stack (brings its containers up).

Inputs: stack_id (required).

stop_containerA
Destructive

Stop a running container (downtime until restarted). Requires confirm=True.

Inputs: name (required), confirm.

stop_stackA
Destructive

Stop a running stack (takes all its containers down). Requires confirm=True.

Inputs: stack_id (required), confirm.

storage_summaryA

Per-mount usage for the OS + data disks (df): device, mount, fstype, total/used/avail bytes, and percent. Skips tmpfs/overlay/virtual mounts.

Inputs: no named parameters.

top_processesA

Top processes by cpu or mem (ps, fast). sort_by is 'cpu' or 'mem'.

Inputs: limit, sort_by.

update_stackA
Destructive

Redeploy a stack with the given compose YAML. DESTRUCTIVE: recreates containers (brief downtime). Requires confirm=True. Existing Env is preserved automatically.

Inputs: compose (required), stack_id (required), confirm.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3/5.0

    Scored across 48 tools

    Disambiguation4/5

    Most tools have clearly distinct purposes, but smart_status vs smart_health and disk_usage vs storage_summary overlap enough to cause confusion. Overall, an agent can usually tell tools apart with careful reading.

    Naming Consistency3/5

    Naming follows a loose pattern: list_* for enumeration and verb_object for actions, but there are outliers like docker_system_df, omv_rpc, cpu_temp, and container_stats. Mixed conventions are still readable but not consistently applied.

    Tool Count2/5

    48 tools is far beyond the typical 3-15 range and the 25+ threshold. The high granularity (e.g., six SMART-specific tools) feels excessive, especially since generic run_command and omv_rpc already exist for arbitrary operations.

    Completeness3/5

    The tool set covers monitoring and lifecycle operations for Docker/stacks and system info, but lacks CRUD for OMV shared folders, users, groups, and SMB shares. The unrestricted omv_rpc and run_command fill gaps but bypass the safer specific tools.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      B
      quality
      C
      maintenance
      Enables AI assistants to monitor and manage OpenMediaVault NAS systems by providing access to storage, network shares, user accounts, and system services. It supports OMV 5 and 6 via the JSON-RPC API for comprehensive hardware and configuration oversight through natural language.
      39
      3
      -
    • A
      license
      Not graded
      quality
      C
      maintenance
      Remote Linux operations via SSH, exposed as an MCP server, with tools for filesystem, systemd, Docker, network, and more, using per-user AD authentication and optional sudo elevation.
      1
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      An MCP server that lets AI assistants manage an OpenMediaVault NAS over SSH using OMV's own RPC interface, covering disks, filesystems, shares, users, S.M.A.R.T. health, services, and configuration changes. It exposes a small set of generic tools to discover and call RPC methods, plus optional shell access.
      6
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Exposes a Raspberry Pi homelab's systemd service health, disk usage, CPU temperature, and LAN game-server status as read-only MCP tools, letting MCP clients answer questions like "how's the homelab doing?" without SSHing in manually.
      4
      MIT