zima-mcp
Allows monitoring and managing Docker containers on a remote Docker host over SSH, including listing containers, retrieving CPU/memory stats, viewing logs, checking disk usage and system load, and restarting allowlisted containers.
zima-mcp
An MCP server that lets your AI assistant check on a ZimaBlade (or any Docker box) over plain SSH, and restart the containers you allow, with nothing installed on the box.

Real output from a ZimaBlade running ZimaOS, captured 11 Oct 2026. The stats table is trimmed to the Immich and Homepage containers.
Contents
Related MCP server: MCP SSH SRE
What it does
Answers "is the box busy?" with load average and uptime (
zima_load).Finds the culprit with top processes by CPU (
zima_top) and one snapshot of CPU and memory per container (zima_docker_stats).Lists containers with status and image (
zima_docker_ps) and shows disk usage (zima_disk).Reads logs for one named container, up to 500 lines (
zima_container_logs).Restarts a container, but only one you have put on the allowlist (
zima_restart_container). Everything else is refused.Can't reboot the box, use sudo or kill root processes. None of the tools runs those commands, and the test suite checks that.
Quick start
You need Python 3.10+, an SSH key that logs in to the box without a password, and a user on the box that can run docker without sudo. On ZimaOS the normal user can, because it's in the docker group.
# 1. check SSH and docker work for that user
ssh you@your-zima docker ps
# 2. install
pipx install git+https://github.com/casareanderson/zima-mcp
# 3. try one tool
ZIMA_HOST=your-zima ZIMA_USER=you zima-mcp --call zima_loadSuccess looks like one uptime line, for example 10:09:19 up 16 days, 23:54, 0 users, load average: 0.81, 0.99, 0.94.
Then add it to your MCP client (next section). The full walkthrough, including every client and the common errors, is in docs/SETUP.md.
Usage
Claude Code:
claude mcp add zima -e ZIMA_HOST=your-zima -e ZIMA_USER=you -e ZIMA_RESTART_ALLOWLIST=immich-server -- zima-mcpClaude Desktop, Cursor and most other clients take the same JSON shape (claude_desktop_config.json, ~/.cursor/mcp.json):
{
"mcpServers": {
"zima": {
"command": "zima-mcp",
"env": {
"ZIMA_HOST": "your-zima",
"ZIMA_USER": "you",
"ZIMA_RESTART_ALLOWLIST": "immich-server,immich-machine-learning"
}
}
}
}Then ask things like "is the Zima busy?", "which container is eating the memory?" or "show me the last 100 lines of immich-server's logs".
Testing without a client:
zima-mcp --list-tools
zima-mcp --call zima_docker_stats
zima-mcp --call zima_container_logs --arg container=immich-server --arg lines=50Configuration
All settings are environment variables. There's a copy-and-edit template in config.example.env.
Variable | Default | What it does |
| required | Hostname or IP of the box |
| required | SSH user. Must be able to run |
|
| SSH port |
| your SSH default | Path to a private key, passed as |
|
| Seconds before a command is given up on (60 for restarts) |
| empty | Comma-separated container names the agent may restart. Empty means every restart is refused |
How it works
flowchart LR
A[AI assistant] -- MCP over stdio --> B[zima-mcp]
B -- "ssh -o BatchMode=yes user@box 'docker stats ...'" --> C[ZimaBlade]
C -- text output --> B -- tool result --> AEach tool is one fixed command run with ssh. SSH runs in BatchMode, so it never sits waiting for a password. A command that takes too long is stopped and reported as an error, not left hanging. Container names are checked against Docker's own naming rules before they go anywhere near a shell, so a name like --help or a;reboot is refused, and names are shell-quoted as well. Restarts also have to be on the allowlist.
zima_mcp/
server.py the tools, SSH runner, config and MCP wiring
__main__.py python -m zima_mcp
tests/
test_server.py unit tests plus an in-memory MCP session
scripts/
setup-check.sh what CI runs to prove docs/SETUP.md worksStatus, limits and real results
Status: in use on one ZimaBlade (ZimaOS) as the "Zima ops" toolset of a self-hosted agent. This repo is the cleaned-up, configurable copy. The output above is from that box on 11 Oct 2026.
Tested: 19 unit tests, plus a CI job that follows docs/SETUP.md against a stand-in Docker host on the GitHub runner (SSH to localhost, a real
nginxcontainer, a real allowlisted restart).Not a ZimaOS API client. It doesn't talk to the ZimaOS/CasaOS app store or settings, only to
dockerand standard Linux tools over SSH. That's also why it works on any Linux Docker host.One box per server. To watch two boxes, add it twice under different names.
zima_topusestop -o %CPU. That works on ZimaOS. Some minimal BusyBox systems don't support-o, and the tool will return the error text.Can't fix a sick host. No reboot, no sudo. If the box itself is wedged, it tells you and that's all.
Licence and credits
MIT, see LICENSE. Built on the Model Context Protocol Python SDK (MIT).
If zima-mcp is useful to you, buy me a coffee. More field notes at dev.to/iam-tech.
Available Tools
7 toolszima_container_logsB
Tail recent logs for one named container.
| Name | Required | Description | Default |
|---|---|---|---|
| lines | No | Lines to tail (default 80, max 500). | |
| container | Yes | Container name, e.g. immich-server. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden, and it discloses very little: it does not say whether the call is read-only, whether it blocks or follows the stream, whether output is bounded, or what happens if the container is missing. 'Recent' is the only behavioral hint and it is undefined in the prose (the 80/500 bound lives in the schema).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence, front-loaded with the verb and resource, with zero filler. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter read tool with full schema coverage and no output schema, the description is minimally adequate. However, with no annotations and no output schema, it leaves open whether the result is a bounded string, whether the call streams/blocks, and what failure looks like.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with both 'container' (name, example) and 'lines' (default 80, max 500) documented in the schema itself, so the baseline of 3 applies. The description only echoes the singular-container constraint and adds no format or syntax detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource pair ('tail logs') scoped to one named container, which is enough to distinguish it from zima_docker_ps (listing) and zima_restart_container (mutation). It stops short of naming or contrasting any sibling explicitly, so it is clear but not fully differentiated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance, no prerequisites (e.g. container must be running), and no mention of alternatives for viewing logs versus other container inspection tools. The agent must infer usage entirely from the name and purpose.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zima_diskB
Disk usage (df -h).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. Referencing 'df -h' implicitly conveys a read-only, human-readable inspection operation, which is genuine context beyond the empty schema, but there is no explicit statement of side-effect-free behavior, permissions, or output shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two words plus a parenthetical command reference; maximally front-loaded with zero waste for a trivial tool. It is arguably too terse to be called exemplary, but nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, no-output-schema read tool, the description is minimally adequate. The 'df -h' reference hints at the return format, but the agent gets no explicit statement of what fields or host scope to expect.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so per the baseline there is nothing for the description to explain. It neither misleads nor needs to compensate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (disk usage) and pins it to a known command (df -h), which lets an agent tell it apart from siblings like zima_top, zima_docker_stats, and zima_load without opening a schema. It is not a bare tautology, though it does not explicitly contrast itself with any sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use, when-not-to-use, or alternative is stated. The agent must infer that this is the tool for checking host disk space rather than container or resource stats; nothing in the text guides that choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zima_docker_psA
List running Docker containers with status and image.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It usefully implies a read-only listing and scopes results to running containers only (stopped/exited ones are excluded), but says nothing about permissions, pagination, or output format beyond two field names.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with the action, scope, and return fields; every word earns its place and there is no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description should indicate what comes back, and 'status and image' does so at a basic level. For a zero-parameter read-only listing this is nearly sufficient, though the exact shape/ordering of the listing is unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is no parameter semantics to document; the baseline for a 0-param tool is 4. The description correctly implies no arguments are needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List running Docker containers') and clarifies the returned fields ('status and image'), which distinguishes it from log- or control-oriented siblings like zima_container_logs and zima_restart_container. It does not explicitly differentiate from zima_docker_stats, which likely overlaps in scope, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance, no mention of when to prefer zima_docker_stats or zima_top instead, and no stated prerequisites. The agent must infer the tool's place in the sibling set on its own.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zima_docker_statsA
One snapshot of CPU and memory per container. Best tool for finding the culprit.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses that this is a point-in-time snapshot rather than a live stream, but omits any statement about side effects, permissions, or return shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, no waste, with the core function front-loaded before the routing hint. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter tool with no output schema, the description is serviceable but thin: it never indicates what the snapshot contains (per-container CPU/memory figures, units, ordering), which an agent would need to interpret results. Adequate but with a clear gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing to document and the baseline of 4 applies. The description adds no parameter detail because none is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource (CPU and memory per container) and a clear scope ('one snapshot'), which distinguishes it from the streaming/monitoring siblings. It does not explicitly name how it differs from zima_top or zima_docker_ps, so it stops short of full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Best tool for finding the culprit' implies a use case (diagnosing a resource-hungry container), but no explicit when-to-use or when-not guidance and no named alternatives. Usage is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zima_loadA
Load average and uptime of the box. Quick check of whether it is busy.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full disclosure burden, but it does state the return content (load average and uptime), which is the main behavioral fact for a metric tool. It omits that the operation is read-only with no side effects and says nothing about output format, which is a modest gap for a zero-param probe.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the returned data before the usage hint, and no filler. It is appropriately sized for a trivial tool, though the second sentence is somewhat colloquial rather than informative.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-param, no-output-schema tool the description is nearly sufficient — it says what comes back. It stops short of situating the tool among its siblings (e.g. zima_top for per-process detail), so an agent lacks a complete basis for choosing this over the alternatives.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing to document and the baseline is 4. The description correctly implies no arguments are needed for a box-level metric read.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States exactly what the tool retrieves (load average and uptime) and its target (the box), so an agent knows the resource and scope. It does not explicitly distinguish itself from the closest sibling zima_top, which is also a system-level metric tool, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Quick check of whether it is busy" implies a lightweight triage use case, which is genuine guidance. However, it names no alternatives and gives no condition for preferring zima_load over zima_top or the docker-specific siblings, leaving the routing decision to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zima_restart_containerA
Restart one named container. Only containers in ZIMA_RESTART_ALLOWLIST are allowed.
| Name | Required | Description | Default |
|---|---|---|---|
| container | Yes | Container name to restart. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full behavioral burden. It usefully discloses the allowlist eligibility constraint, but omits that a restart causes downtime/state loss, whether the call blocks until the container is back up, and how failures are surfaced.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with the action front-loaded and the eligibility constraint second. No filler; every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Adequate for a simple one-parameter tool: it says what happens and the eligibility rule. But as an annotation-free mutation tool it leaves the operational consequences of a restart (downtime, blocking behavior, error mode) unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single 'container' parameter is already documented as 'Container name to restart.' The description reinforces the single-named-container constraint but adds no format, naming, or lookup details beyond the schema. Baseline 3 for full schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Restart one named container') with unambiguous scope. Against the read-only siblings (zima_docker_ps, zima_top, zima_container_logs), the mutating 'restart' action is immediately distinguishable without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a clear precondition/exclusion: only containers in ZIMA_RESTART_ALLOWLIST are eligible, which tells the agent when the call will fail. It does not, however, point to any sibling (e.g., zima_container_logs) for diagnosing a container before or after restart.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zima_topB
Top processes by CPU. Use it to find what is pegging the CPU.
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | How many processes to show (default 12, max 40). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden. It implies a read-only inspection but never states that it makes no changes, whether it requires host access, whether sampling is instantaneous vs. averaged, or how results behave under load.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with zero filler, and the resource definition is front-loaded before the use case. Nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple, one-optional-parameter read tool with no output schema, the description is nearly sufficient — the agent knows what it returns conceptually (ranked processes). Only the behavioral/safety framing is thin.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single optional parameter's default (12) and max (40) are documented in the schema. The description adds no further meaning about the count parameter, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource and ordering (top processes by CPU), which is enough to distinguish it from siblings like zima_disk or zima_docker_stats. It does not explicitly differentiate itself from the Docker-oriented siblings, but the host-CPU focus is clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Use it to find what is pegging the CPU" gives a concrete trigger scenario, so usage is implied rather than absent. However, it names no alternatives or exclusions (e.g. when to prefer zima_docker_stats for container-level CPU), leaving the agent to infer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
7 tool updates
v0.1.0- First observed
zima_container_logs - First observed
zima_disk - First observed
zima_docker_ps - First observed
zima_docker_stats - First observed
zima_load - First observed
zima_restart_container - First observed
zima_top
TDQS
Scored across 7 tools
Each tool targets a distinct host or container concern (load, CPU, disk, container listing, stats, logs, restart), and descriptions explicitly differentiate the overlapping-looking ones (e.g. docker_ps vs docker_stats, top vs docker_stats). Minor residual overlap between host CPU tools and container CPU tools, but selection is generally clear.
All tools share a zima_ prefix and consistent lowercase snake_case, so the set reads as a coherent family. The style is noun-oriented rather than strict verb_noun (load, top, disk, docker_ps), with only restart_container using a verb, but this is a minor deviation rather than confusion.
Seven tools is well-scoped for a host-plus-Docker monitoring server: one per core observation (load, CPU, disk, container list, container stats, logs) plus a single guarded mutation. Nothing feels redundant or missing at the count level.
Covers the main diagnostic surface: host load/CPU/disk, container listing/stats/logs, and a safe restart. Gaps include host memory/network metrics and start/stop operations (only restart exists), but an agent can work around these for typical troubleshooting.
Maintenance
Related MCP Connectors
- emisarOAuthdev.emisar
Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Remote Linux boxes for coding agents: Docker, a browser, screenshots, logs, human takeover.
Work on your own computers from Claude or ChatGPT: run commands, edit and search files.
Related MCP Servers
- AlicenseBqualityAmaintenanceEnables AI assistants to manage homelab infrastructure through automated service installation (Jellyfin, Pi-hole, Ollama, Home Assistant, Frigate NVR), VM operations, AI accelerator support (MemryX, Coral TPU, Hailo-8), and Terraform state management with SSH-based discovery and deployment.585MIT
- AlicenseNot gradedqualityFmaintenanceProvides read-only server monitoring and diagnostic tools for AI assistants to manage Linux and Unraid systems via SSH. It enables natural language interactions for container management, storage health checks, and system log analysis while keeping credentials secure.17ISC
- AlicenseAqualityBmaintenanceEnables AI assistants to manage remote servers via SSH with agentless command execution, file operations, and service management.919 PyPIMIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to autonomously check, diagnose, and recover Dockerized services through safe, tool-based ops without direct host shell access.MIT