Skip to main content

PyPI PyPI - Downloads Python License CI

bladerunner-mcp

MCP server that lets an AI session operate your remote machines over SSH.

⚠️ These tools run real commands on real servers with your credentials. Running your MCP client in auto-approve ("YOLO") mode means the model can execute anything on your machines without you seeing it first. Keep manual approval on for this server, use least-privilege SSH accounts, and have backups/snapshots for anything you point it at. See Security.

You pip install bladerunner-mcp, describe your hosts (e.g. a Hetzner box) in a YAML config with credentials, and the server exposes MCP tools to run commands, track long-running processes and transfer files on those hosts. The model only ever sees host aliases — secrets never enter the conversation.

Scope: POSIX remote hosts only (sh, nohup, tail, head, wc must be present on the target). Windows hosts are not supported.

Tools

Tool Description
list_hosts List configured host aliases (no secrets)
run_command Run a shell command on a host, return stdout/stderr/exit code (capped at 64 KiB per stream)
read_output Page through the full output of a truncated run_command or a background process
start_process Start a long-running command in the background (nohup), return pid + work_dir
check_process Report process status (running/succeeded/failed/unknown), exit code and log tails
kill_process Kill a background process
put_file Upload a local path to a host via rsync
get_file Download a remote path from a host via rsync

Large outputs: run_command keeps the full output on the host (in a work_dir under /tmp/bladerunner_mcp/) whenever it exceeds the 64 KiB cap and returns truncated: true — page through it with read_output(host, work_dir, offset=...).

Installation

pip install bladerunner-mcp

Configuration

Copy bladerunner_mcp.example.yaml to ~/.bladerunner_mcp.yaml (or set BLADERUNNER_MCP_CONFIG to its path):

hosts:
  hetzner-prod:
    host: 203.0.113.10
    user: root
    port: 22
    key_path: ~/.ssh/id_ed25519
    # key_passphrase: "..."  # for passphrase-protected keys (commands only)
    strict_host_key: true    # verify against system known_hosts (default: false)
    allow_dangerous: false   # keep the safety filters on (default)
    # protected_paths: [/etc, /var/lib]               # override the default protected list
    # allowed_remote_paths: [/srv/app, /var/log/app]  # opt-in transfer allowlist
    # allowed_local_paths: [~/deploys]

Register with a client

Claude Code:

claude mcp add bladerunner -- bladerunner-mcp

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "bladerunner": {
      "command": "bladerunner-mcp",
      "env": { "BLADERUNNER_MCP_CONFIG": "/Users/me/.bladerunner_mcp.yaml" }
    }
  }
}

Security

  • Do not run your MCP client in auto-approve ("YOLO") mode with this server. Every run_command/start_process call is a real shell on a real machine; keep per-call approval on so you see each command before it runs.
  • Protected-path filter (commands) — mutating operations (rm, mv, chmod, chown, shred, truncate, chattr, sed -i, tee, output redirects, and cp/rsync/install/ln writing into them) on system paths (/, /etc, /boot, /bin, /sbin, /usr, /lib*, /dev, /sys, /proc, /root, /var/lib) are rejected; reads of the same paths and mutations elsewhere pass. Catastrophic non-path patterns (mkfs, dd of=/dev/..., shutdown/reboot, fork bombs, DROP TABLE/DATABASE) are also rejected. Override with per-host protected_paths. This is a seatbelt against accidents, not a security boundary: shell is not statically analyzable. Disable per host with allow_dangerous: true.
  • Path validation (transfers)put_file/get_file paths are expanded and normalized (.. resolved) and then enforced for real: protected system prefixes are denied on the remote side, and ~/.ssh, ~/.gnupg, ~/Library/Keychains plus system dirs on the local side (both directions — exfiltrating local keys is as bad as overwriting them). Optional per-host allowed_remote_paths / allowed_local_paths restrict transfers to listed prefixes. Remote symlinks are not resolved (known limit).
  • Least privilege — point the server at dedicated SSH accounts with the minimum rights the task needs, not at root, and keep backups/snapshots of anything it can touch.
  • Host keys — by default unknown host keys are auto-accepted (convenient, MITM-unsafe). Set strict_host_key: true per host to verify against your system known_hosts (applies to both paramiko and rsync).
  • Auth — prefer SSH keys; passphrase-protected keys work for command tools via key_passphrase (transfers need an agent-loaded or plain key). Password auth works (rsync falls back to sshpass, which exposes the password in the local process list) and the password sits in plaintext YAML; treat it as legacy-host escape hatch only.
  • Secrets stay local — the model sees host aliases only; keys and passwords never enter the conversation. Executed commands are logged to stderr for audit.

Design

  • One short file (bladerunner_mcp/server.py) built on MCPServer from the official mcp Python SDK.
  • Command execution via paramiko; background processes follow the nohup + PID + exit-code-file pattern proven in blade_runner's SSHBackend (the AI session itself plays the role of the polling monitor, so the full FSM is not embedded).
  • File transfer via rsync_ssh_client (put / get over rsync+SSH, sshpass fallback for password auth).

Development

pip install -e ".[dev]"
pytest                      # unit tests (mocked paramiko/rsync)
RUN_E2E=1 pytest tests/e2e  # e2e against a docker compose sshd container
ruff check . && mypy bladerunner_mcp

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bladerunner_mcp-0.5.0.tar.gz (22.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bladerunner_mcp-0.5.0-py3-none-any.whl (11.5 kB view details)

Uploaded Python 3

File details

Details for the file bladerunner_mcp-0.5.0.tar.gz.

File metadata

  • Download URL: bladerunner_mcp-0.5.0.tar.gz
  • Upload date:
  • Size: 22.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for bladerunner_mcp-0.5.0.tar.gz
Algorithm Hash digest
SHA256 349613d5645f86c1e22674f67105c7ac46e0016819267963bb4543ea5c7df2f5
MD5 9b4563117a2542df1aa99af8136c5152
BLAKE2b-256 e51c019cd9c068ffd8af535a4c68e26038fb9eed387eef5289b99a9c079d79c8

See more details on using hashes here.

File details

Details for the file bladerunner_mcp-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: bladerunner_mcp-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 11.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for bladerunner_mcp-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ce18e3213a8fb30b4f37ca73dc263963887d72e75af50159cf3ae06fddce7d64
MD5 6167582658d7f7bb3a5b4205d01fd501
BLAKE2b-256 a822deca0f0e66c956d6fd0e42ff85ca3d7d326bf12bad217eed7d61d7351db3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page