Skip to main content
Glama
Raspberry Pi SSH MCP Controller

Raspberry Pi SSH MCP Controller

by dimoxe

Raspberry Pi SSH MCP Controller

This is a local Model Context Protocol (MCP) server that accesses Raspberry Pis over SSH from VS Code. It follows Arm's uv-managed Python MCP workflow, updated to the current MCP Python SDK and its recommended stdio transport. It deliberately does not expose an Internet-facing SSE/ngrok endpoint and can be installed as an independent uv tool.

Name

Device

Configuration

Architecture

rpi5

Raspberry Pi 5

RPI_MCP_RPI5_*

arm64

rpi3bplus

Raspberry Pi 3B+

RPI_MCP_RPI3_*

arm32

Package layout

Keep the protocol boundary thin and place lower-level concerns behind it:

  • server.py: MCP tool schemas, validation, and tool registration only.

  • ssh.py: shell-free OpenSSH command construction and process execution.

  • config.py: configuration discovery, parsing, validation, and device inventory.

  • cli.py: the installable rpi-mcp entry point and config-template bootstrap.

  • templates/default.env: non-secret configuration template packaged with the wheel.

This keeps the SSH adapter testable without an MCP host and prevents LAN addresses, usernames, private-key paths, and opt-in controls from being embedded in the distributable artifact.

Related MCP server: RunbookBridge

Install as a uv tool

Build a wheel and source distribution from the source checkout:

uv build

Install it locally from that source project:

uv tool install --from . rpi-mcp-controller

For a released or copied artifact, install the generated wheel instead:

uv tool install path/to/rpi_mcp_controller-<version>-py3-none-any.whl

Create the operator-owned configuration file and print its location:

rpi-mcp init-config
rpi-mcp config-path

The installed tool uses a platform-specific per-user configuration directory. Set RPI_MCP_ENV_FILE to use a different file, such as a managed secrets location. Source-checkout development continues to load .env when it exists.

What it provides

  • list_raspberry_pis: show the configured device inventory.

  • get_raspberry_pi_status: hostname, kernel, uptime, memory, disk, and CPU temperature.

  • read_text_file: bounded, read-only remote file access.

  • get_service_status and get_service_logs: inspect a systemd service.

  • control_service: start, stop, or restart a service after an explicit opt-in.

  • run_command: arbitrary remote command execution after an explicit opt-in.

  • power_action: reboot or shut down a device after a separate opt-in and a CONFIRM argument.

Security model

The server runs as a child process of VS Code over stdio: it listens on no TCP port. Each tool invocation calls the local OpenSSH client with BatchMode=yes and StrictHostKeyChecking=yes; password prompts are disabled and an unknown host key is rejected. Use an SSH key or agent, not a password.

Read-only tools are available by default. control_service and run_command remain disabled until RPI_MCP_ENABLE_COMMANDS=1 is set. power_action needs its own RPI_MCP_ENABLE_POWER_ACTIONS=1 setting. Enabling run_command gives the connected MCP client arbitrary access available to the SSH user, so only enable it for a trusted local VS Code session.

The service and power tools use sudo -n, which refuses a password prompt. Grant only the exact systemctl actions needed in a Pi-specific sudoers file; do not grant NOPASSWD: ALL.

If a Pi's sudo requires a password (for example, a Raspberry Pi 5 whose image does not grant NOPASSWD), set RPI_MCP_RPI5_SUDO_PASSWORD or RPI_MCP_RPI3_SUDO_PASSWORD. Those tools then run sudo -S -p '' and write the password to the SSH process's stdin, so it never appears in a local or remote command line, process listing, or tool result. The password is read verbatim from the environment and cannot contain line breaks. run_command does not receive it. Keep the configuration file private; a scoped NOPASSWD sudoers entry remains the preferred setup.

One-time Pi setup

On each Pi, enable the SSH service:

sudo systemctl enable --now ssh

Create a dedicated local SSH key on the Windows host:

ssh-keygen -t ed25519 -f "$env:USERPROFILE\.ssh\id_ed25519_rpi_mcp"

Install its public key on each Pi, replacing your-pi-user with the account created through Raspberry Pi Imager:

The addresses below are RFC 5737 documentation examples; replace them with your Pi hostnames or addresses.

Get-Content "$env:USERPROFILE\.ssh\id_ed25519_rpi_mcp.pub" | ssh your-pi-user@192.0.2.5 "umask 077; mkdir -p ~/.ssh; cat >> ~/.ssh/authorized_keys"
Get-Content "$env:USERPROFILE\.ssh\id_ed25519_rpi_mcp.pub" | ssh your-pi-user@192.0.2.3 "umask 077; mkdir -p ~/.ssh; cat >> ~/.ssh/authorized_keys"

Before accepting either SSH host key, compare the fingerprint shown on the Pi console with:

ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub

After verifying it, add the host key from Windows with one interactive SSH connection. The server will then require that key to remain unchanged:

ssh -o StrictHostKeyChecking=accept-new your-pi-user@192.0.2.5 true
ssh -o StrictHostKeyChecking=accept-new your-pi-user@192.0.2.3 true

For service control, edit a file through sudo visudo -f /etc/sudoers.d/rpi-mcp on each Pi. Substitute only the service units you want the MCP server to operate:

your-pi-user ALL=(root) NOPASSWD: /usr/bin/systemctl start mixto-api.service, /usr/bin/systemctl stop mixto-api.service, /usr/bin/systemctl restart mixto-api.service

Power operations require similarly scoped entries for /usr/bin/systemctl reboot and /usr/bin/systemctl shutdown (or the appropriate local systemctl path). Confirm the executable path first with command -v systemctl.

Configure and test

For source-checkout development, copy the local template from the repository root:

Copy-Item .env.example .env

Set RPI_MCP_RPI5_HOST, RPI_MCP_RPI5_SSH_USER, and RPI_MCP_RPI5_SSH_PORT plus the corresponding RPI_MCP_RPI3_* values. When not using the default SSH agent/key lookup, also set the dedicated identity-file path. The .env file is ignored by Git and is loaded automatically; process environment variables take priority over it.

Install the standalone project's dependencies and run its network-free tests:

uv sync
uv run pytest

Check real read-only connectivity before enabling any write capability:

uv run python -c "from rpi_mcp.server import get_raspberry_pi_status; print(get_raspberry_pi_status('rpi5'))"
uv run python -c "from rpi_mcp.server import get_raspberry_pi_status; print(get_raspberry_pi_status('rpi3bplus'))"

The MCP Inspector is also available once Node.js is installed:

uv run mcp dev src/rpi_mcp/server.py

VS Code

The checked-in MCP configuration registers a local stdio server named raspberry-pi-ssh from the source checkout. To use an installed artifact instead, replace that server's command with:

{
	"type": "stdio",
	"command": "rpi-mcp"
}

Reload VS Code after creating or changing its configuration, then start or debug it from the MCP Servers view. The server's output uses stderr, leaving stdout exclusively for the MCP protocol.

References

Available Tools

8 tools
control_serviceB

Start, stop, or restart a systemd service after command control is explicitly enabled.

Inputs: action (required), device (required), service (required). Returns: object

get_raspberry_pi_statusA

Read hostname, kernel, uptime, memory, disk, and CPU temperature from a Pi.

Inputs: device (required). Returns: object

get_service_logsA

Read the newest journal entries for one systemd service on a Pi.

Inputs: device (required), service (required), lines. Returns: object

get_service_statusA

Get detailed systemd status for one service on a Pi.

Inputs: device (required), service (required). Returns: object

list_raspberry_pisA

List the named Raspberry Pis available to this MCP server.

Inputs: no named parameters. Returns: object

power_actionA

Reboot or shut down a Pi only after a separate power-control opt-in and confirmation.

Inputs: action (required), device (required), confirm (required). Returns: object

read_text_fileA

Read up to one MiB of a text file from a named Pi without modifying it.

Inputs: path (required), device (required), max_bytes. Returns: object

run_commandA

Run an arbitrary remote command only after the operator enables command control.

Inputs: device (required), command (required), timeout_seconds. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.8/5.0

    Scored across 8 tools

    Disambiguation5/5

    Each tool has a distinct purpose: listing Pis, reading status, reading files, service status/logs, controlling services, running commands, and power actions. No overlap or ambiguity.

    Naming Consistency4/5

    Most tools follow a verb_noun pattern (list_, get_, read_, control_, run_), but 'power_action' is a noun phrase rather than a verb-based name, creating a minor inconsistency.

    Tool Count5/5

    With 8 tools, the set is well-scoped for a Raspberry Pi SSH controller—covering discovery, status, file access, service management, command execution, and power control without being bloated.

    Completeness4/5

    The toolset covers the core operations expected of a remote Pi controller (read, inspect, control, run). Minor gaps exist, such as no file write/upload or multi-service listing, but they are not essential for the stated purpose.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Converts VSCode into an MCP server that enables external clients to remotely execute VSCode internal commands, query workspace information, and interact with the editor through HTTP streaming. Built on the FastMCP framework with security controls and real-time monitoring.
      63
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI assistants to perform operations on remote servers by reusing SSH sessions from a local desktop app, including command execution, file upload/download, and project document management with security controls.
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Enables managing services on OpenWrt, ImmortalWrt, and systemd-based routers via SSH, with read-only service listing, status, and log queries, plus write operations (start/stop/restart) requiring confirmationional confirmation and an optional shell execution capability.
      8
      1
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables MCP clients to list SSH hosts, test reachability, retrieve Linux resource metrics, index and search project files, and run remote SSH commands when allowed, with local-first and safety-focused operations.
      MIT