Homelab SSH MCP
Overview
Section titled “Overview”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.
| Port | Protocol | Purpose |
|---|---|---|
| 19000 | TCP | Streamable HTTP endpoint for MCP clients |
Access
Section titled “Access”| Access Method | URL |
|---|---|
| Local loopback | http://127.0.0.1:19000/ |
| Localhost | http://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.
Semantic Tools
Section titled “Semantic Tools”The server provides specialized tools instead of raw command execution for better safety and UX:
list_services
Section titled “list_services”Discovery tool to see all services and their current state (Active, Loaded, Description).
service_status
Section titled “service_status”Fetches a detailed health check and current status of a specific systemd unit.
service_logs
Section titled “service_logs”Retrieves logs for a specific service. Supports a flexible lines parameter to fetch as much context as needed (e.g., 50 or 1000 lines).
manage_service
Section titled “manage_service”Performs administrative actions on an allowed service: start, stop, restart, or reload.
Security
Section titled “Security”- 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
sudorules to the validated wrapper scriptshomelab-mcp-systemctlandhomelab-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, andPrivateTmp=true. - Privilege Elevation:
NoNewPrivilegesis set tofalsein the systemd unit to allow thesudowrapper (setuid binary) to function. - Host Validation: The server validates the
Hostheader against an allowlist injected viaALLOWED_HOSTS.
Connection in Antigravity
Section titled “Connection in Antigravity”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.
Backup
Section titled “Backup”This service is stateless. No backup is required for its runtime data. The source code and configuration are persisted in the homelab-nixos repository.
Troubleshooting
Section titled “Troubleshooting”Forbidden: Host header is not allowed
Section titled “Forbidden: Host header is not allowed”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.
Service is not allowed
Section titled “Service is not allowed”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.