- Python 90.7%
- Shell 9.3%
PI_CONTROL_SSH_HOST=auto finds the Pi on the LAN with no IP and survives DHCP changes; system.py now runs over SSH (reads /proc + systemctl on the target), not only locally; the wizard offers the auto-detected Pi. |
||
|---|---|---|
| .github/workflows | ||
| docs/clients | ||
| hooks | ||
| src/pi_control_mcp | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| .sanity-patterns.json | ||
| LICENSE | ||
| manifest.json | ||
| pyproject.toml | ||
| README.md | ||
| WHITEPAPER.md | ||
Pi Control MCP
Observe and lightly control a Linux or Raspberry Pi host (CPU health, systemd service status, journal logs, allowlisted restarts) from any MCP client. Credentials stay on your machine.
An MCP server that exposes your Linux or Raspberry Pi to any MCP-capable client (Claude Desktop, Claude Code, Cursor, ChatGPT, and more). Run it directly on the Pi, or proxy it over SSH from your laptop. No credentials are sent to the author of this repo.
60-second quickstart
1. Run the setup wizard
uvx --from git+https://github.com/nidamen/pi-control-mcp pi-control-mcp-init
The wizard asks whether you are running locally on the Pi or over SSH, prompts for the target host, verifies the connection, and prints the exact claude mcp add line.
2. Add to Claude Code (one-liner)
claude mcp add pi-control -- uvx --from git+https://github.com/nidamen/pi-control-mcp pi-control-mcp
If connecting over SSH, the wizard prints a version of the line with the necessary env vars already filled in.
Restart Claude Code and the pi_control tools appear.
pip / uv alternative
pip install git+https://github.com/nidamen/pi-control-mcp
# then:
pi-control-mcp
Tools
| Tool | What it does |
|---|---|
pi_health |
CPU temperature (Raspberry Pi only via vcgencmd), throttle flags, load average, memory, uptime, root disk usage. |
service_status |
LoadState/ActiveState/SubState for any systemd unit (read-only). |
list_services |
Status of every unit in the configured allowlist. |
journal_tail |
Last N journald lines for a unit (capped at 200). |
failed_units |
List all systemd units currently in a failed state. |
restart_service |
Restart a unit, but ONLY if it is in the allowlist; all other units are rejected. |
Configuration
| Variable | Required | Description |
|---|---|---|
PI_CONTROL_ALLOWLIST |
no | Comma-separated units that restart_service is allowed to touch. Format: unit1,unit2 (all system scope) or unit1:system,unit2:user (explicit scope). Default: nginx,tailscaled,ssh. |
PI_CONTROL_SSH_HOST |
no | Hostname or IP of the remote machine when running over SSH. Set to auto to auto-discover a Raspberry Pi on your LAN every run (mDNS + ARP/MAC-OUI, no IP to memorize, survives DHCP changes). Leave unset for local mode. |
PI_CONTROL_MDNS_NAME |
no | Override the mDNS name used for discovery (default raspberrypi.local). |
PI_CONTROL_SSH_USER |
no | SSH username (default: current user). |
PI_CONTROL_SSH_PORT |
no | SSH port (default: 22). |
PI_CONTROL_CONFIG_DIR |
no | Directory for the wizard-written config (default: ~/.config/pi-control-mcp). |
Per-client setup
Security
Your SSH key and host details live only in ~/.config/pi-control-mcp (or $PI_CONTROL_CONFIG_DIR) on your machine. The server talks directly from your machine to your Pi over your LAN or Tailscale network. The author of this repo never receives your host address, SSH credentials, or any traffic. See WHITEPAPER.md for the full security and threat model.
The restart_service tool implements a deny-by-default allowlist: every restart request is checked against the list before any shell command is run. Units not in the list are rejected with an error.