sdl-lab-hostops
Enables monitoring of Docker containers via host checks, folding container status into the host's STATUS_SPEC components and metrics to indicate degraded or error states.
Enables monitoring of NVIDIA GPU memory via nvidia-smi as part of host checks, folding GPU metrics into the host's STATUS_SPEC components and metrics.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@sdl-lab-hostopscheck if plateloc.service is running"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
sdl-lab-hostops
Whitelisted host-operations MCP server for SDL2 lab machines. It answers "is the service up, what did it log, did the USB adapter come back, is the local device API answering" — the class of incident (boot USB-enumeration races, corrupt-venv locks, silent partial syncs) that a network client can see but not diagnose.
Deliberate non-goals: no shell tool, no arbitrary commands, and no path
to any device /control/* endpoint. Hardware control belongs to the
lab-skills SDK and its MCP server (ac-organic-lab — AGENT_RULES §1.1).
The tool surface below is the complete surface; every target must be
whitelisted in config.toml, so a service or port not listed cannot be
touched at all.
Tools
Tool | Mutates? | Notes |
| no | hostname, OS, uptime, disk free, loadavg, backend |
| no | systemd unit / Windows service state |
| no | journald (Linux) or NSSM |
| yes | only services in the smaller |
| no | pyserial ( |
| no |
|
Related MCP server: CommandBridge MCP
Host checks (optional)
GET /status is a liveness ping by default: ready whenever the process is
up. [checks] in config.toml makes it mean something — per-mount disk use,
ZFS pool health and capacity, nightly-backup result and age, systemd user
units, docker containers, GPU memory. Results become STATUS_SPEC components
and metrics, folded into equipment_status (ready / degraded / error)
and a one-line message.
Three properties worth knowing, because they are what make the tile trustworthy:
A check that cannot run is
unknown, andunknowndegrades the host. Missingzpool, an unreadable docker socket or a timeout never reads as healthy — STATUS_SPEC §2.1: "cannot tell" is not "fine".backup OKis not automatically green.backup_warn_patternscatches a run that succeeded with gaps (gaia: adot6:line sayingpostgres: not published), and a log older thanbackup_max_age_hoursis an error even if its last line says OK.Cost is bounded. Every check has its own timeout and the whole set is cached for
ttl_seconds, so a 30 s dashboard poll does not re-runzpool/nvidia-smi. Measured on a 6-check config: ~10 ms cold, <1 ms cached.
Only enable checks that work on that host: a permanently-unknown check means
a permanently-amber tile, which teaches people to ignore it.
Backends
Selected automatically by platform:
systemd (Linux, Raspberry Pi):
systemctl/journalctl. Restarts can be prefixed withsudo -n(use_sudo = true) — grant only the exact units, e.g./etc/sudoers.d/sdl-lab-hostops:sdl2 ALL=(root) NOPASSWD: /usr/bin/systemctl restart plateloc.servicenssm (Windows device PCs):
sc query,nssm restart+sc continue(DEVICE_PC_SETUP §7 quirk), log tails fromC:\SDL_Logs\<svc>.{out,err}.log.
Transports & auth
stdio(default): the MCP client spawns the process per connection. No daemon, no token. This is also the daemonless "lite" mode — see the Pi section.http(streamable-http): long-lived service. A non-loopback bind refuses to start unlessHOSTOPS_TOKENis set; clients sendAuthorization: Bearer <token>. Network reachability is additionally gated by Tailscale ACLs, per the lab's v1 auth posture (STATUS_SPEC §11). Exception:GET /statusis unauthenticated — it serves a read-only STATUS_SPEC v1.2 envelope (read-only conformance clause, §9) so the dashboard can register the instance inequipment.yamland monitor the watchers. Primary operation: none (ops service) —activityis permanentlyidle; claims/allowed_actionsare N/A because there is no control surface.
Environment
Var | Meaning |
| path to |
| bearer token, required for non-loopback http binds |
| e.g. |
Audit: every restart_service posts a hostops_action event to the
dashboard's POST /api/ingest/events (best-effort, never blocks the
restart). Reads are not audited. Register the hostops_action event type in
ac-organic-lab/docs/LAB_MONITORING.md §4 when the first instance ships.
Install — Windows device PC (NSSM)
Follow ac-organic-lab/docs/DEVICE_PC_SETUP.md §3 with:
cd C:\Users\sdl2\Projects
git clone <this-repo> sdl-lab-hostops
cd sdl-lab-hostops
Copy-Item config.example.toml config.toml # edit whitelists for this PC
C:\SDL_Tools\uv.exe sync --extra serial
nssm install sdl-lab-hostops C:\SDL_Tools\uv.exe run --project C:\Users\sdl2\Projects\sdl-lab-hostops lab-hostops-serve --transport http
nssm set sdl-lab-hostops AppDirectory C:\Users\sdl2\Projects\sdl-lab-hostops
nssm set sdl-lab-hostops AppEnvironmentExtra HOSTOPS_TOKEN=<token> HOSTOPS_INGEST_URL=http://sdl2-server-gaia.tail6a1dd7.ts.net:8001
# ... stdout/stderr logs, auto-start, run-as user: exactly as DEVICE_PC_SETUP §3
nssm start sdl-lab-hostops
sc continue sdl-lab-hostopsNote the service account needs rights to restart the other services
(sc sdset per service, or run sdl-lab-hostops under an account that has them).
A permission failure is reported truthfully in the tool result.
Install — Linux / Raspberry Pi (systemd)
git clone <this-repo> /opt/sdl-lab-hostops && cd /opt/sdl-lab-hostops
cp config.example.toml config.toml # edit
uv sync # base deps only — no extras needed
sudo cp deploy/sdl-lab-hostops.service /etc/systemd/system/
sudo systemctl enable --now sdl-lab-hostopsPi Zero 2W "lite" mode
The base install is small (mcp + httpx/starlette/uvicorn, all pure-Python or
armv8 wheels) and idles at a few tens of MB — the same footprint class as the
sense-every-zone gateway already running on sdl2-pi0-environ-01. Two ways
to run it lighter:
http, minimal: skip the
[serial]extra, keep the whitelist tiny.daemonless stdio-over-SSH — zero resident footprint; the central Hermes spawns it on demand and SSH is the auth (no token, no open port):
# Hermes mcp_servers entry on the central server hostops-pi0-environ: command: ssh args: [sdl2@sdl2-pi0-environ-01, /opt/sdl-lab-hostops/.venv/bin/lab-hostops-serve, --transport, stdio, --config, /opt/sdl-lab-hostops/config.toml]Requires key-based SSH from the central server. Prefer this on the Pis; prefer the http service on the Windows PCs (no SSH daemon there).
Client registration
Register each instance in the lab's reviewed MCP registry
(ac-organic-lab/mcp/servers.yaml) with the full 6-tool include list, and
mirror that allowlist in the client config (e.g. the Hermes lab-ops
profile's mcp_servers.<name>.tools.include). A new tool added here should
only reach an agent after both lists are updated — that's the point.
Tests
uv run pytest -qThis server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
An MCP server that provides Javelin Standalone Guardrails
Hosted MCP server for task-first delegation to remote workstations and workers.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn MCP server that gives an agent full cross-VM management of a Qubes OS system via dom0 qrexec, bounded by an explicit VM allowlist for security.-
- FlicenseAqualityBmaintenanceCross-platform MCP server for policy-controlled command execution on Linux and Windows, with no SSH dependency.3-
- AlicenseNot gradedqualityCmaintenanceA production-ready MCP server for secure, session-based command execution, file manipulation, and system inspection via local terminal sessions.8 npmISC
- AlicenseNot gradedqualityCmaintenanceRead-only MCP server to inspect allowlisted Docker containers, systemd services, JSONL logs, and HTTP health endpoints without arbitrary shell access.MIT