Skip to content

Homelab SSH MCP

The Homelab SSH MCP server is a specialized bridge that allows AI agents (like Antigravity) to interact with the host operating system’s service manager (systemd) using semantic tools.

Unlike a full SSH session, this server exposes specific high-level functions for service management. This follows the Principle of Least Privilege, ensuring that an AI agent can monitor and maintain the homelab without having full administrative access or raw shell capabilities.

PortProtocolPurpose
19000TCPStreamable HTTP endpoint for MCP clients
Access MethodURL
Local loopbackhttp://127.0.0.1:19000/
Localhosthttp://localhost:19000/

This service is intentionally not registered in homelab.proxies. It must stay private on loopback or another explicitly private transport because it can inspect logs and restart approved systemd units.

The server provides specialized tools instead of raw command execution for better safety and UX:

Discovery tool to see all services and their current state (Active, Loaded, Description).

Fetches a detailed health check and current status of a specific systemd unit.

Retrieves logs for a specific service. Supports a flexible lines parameter to fetch as much context as needed (e.g., 50 or 1000 lines).

Performs administrative actions on an allowed service: start, stop, restart, or reload.

  • Isolation: The service runs as a non-privileged system user (homelab-ssh-mcp) with its shell set to /run/current-system/sw/bin/nologin.
  • Sudo Rules: Privileged operations are restricted via surgical sudo rules to the validated wrapper scripts homelab-mcp-systemctl and homelab-mcp-journalctl.
  • Service Allowlist: The Rust server and Nix wrappers both validate service names against a fixed allowlist.
  • Sandboxing: The systemd unit uses ProtectSystem=strict, ProtectHome=true, and PrivateTmp=true.
  • Privilege Elevation: NoNewPrivileges is set to false in the systemd unit to allow the sudo wrapper (setuid binary) to function.
  • Host Validation: The server validates the Host header against an allowlist injected via ALLOWED_HOSTS.

Add the following entry to your mcp_config.json:

{
"mcpServers": {
"homelab-ssh": {
"url": "http://127.0.0.1:19000/"
}
}
}

For the current hardened setup, prefer a loopback-accessible IDE or private transport and use http://127.0.0.1:19000/ when the client runs on the host. Do not use the public Cloudflare hostname pattern for this MCP server.

This service is stateless. No backup is required for its runtime data. The source code and configuration are persisted in the homelab-nixos repository.

The server is receiving a request with a Host header that is not in its allowlist. Check the ALLOWED_HOSTS environment variable in the Nix configuration.

The requested unit is not in the MCP allowlist. Add the unit to both the Rust allowlist and the Nix wrapper allowlist in modules/nixos/mcp/homelab-ssh/, then rebuild.

sudo: /run/current-system/sw/bin/sudo must be owned by uid 0

Section titled “sudo: /run/current-system/sw/bin/sudo must be owned by uid 0”

The server is trying to use the wrong sudo path or NoNewPrivileges is set to true. Ensure the code uses /run/wrappers/bin/sudo and the Nix module has the correct sandboxing settings.