An Opus is a piece that deserves to be held by an Orchestra, conducted by a proper Maestro.
Maestro is an MCP server that turns a heterogeneous machine fleet into a unified workspace for AI agents. SSH into any host, run commands across platforms, transfer files, and dispatch coding agents — all through a single orchestration layer.
Built for developers/power users in general who work across multiple machines and want their AI assistant to do the same.
Most MCP SSH servers connect to one host. You configure a hostname, a key, and you're in.
But that's not how real setups work. You have a GPU box running Linux, a MacBook for travel, a Windows workstation with WSL — each with different shells, different paths, different capabilities. You don't just need SSH. You need a conductor that understands the whole orchestra.
Maestro gives your AI agent the same mental model you have: named hosts, persistent connections, cross-platform awareness, and the ability to dispatch long-running tasks to coding agents while continuing the conversation.
- Named hosts with per-host shell awareness (Bash, PowerShell, WSL)
- SSH ControlMaster lifecycle — persistent multiplexed connections with auto-reconnect and exponential backoff
- Local routing — the hub machine bypasses SSH entirely for zero-overhead local execution
- Cross-platform commands —
execadapts to each host's shell automatically - Multi-line scripts —
scriptpipes scripts viabash -sor PowerShell stdin - File operations —
read,write, andtransfer(SCP) across any host - Fleet status — one-command health check across all hosts with auto-reconnection
- Agent orchestra (optional) — dispatch Claude Code, Codex CLI, Gemini CLI, or OpenCode CLI as async background tasks with budget caps, output pagination, and polling
- Remote access (optional) — OAuth 2.1 with PIN-gated consent for exposing Maestro over HTTP (e.g., from Claude.ai via Cloudflare Tunnel). Not needed for stdio usage with Codex CLI, Claude Code, or Claude Desktop
Maestro runs on one hub machine — the one with SSH access to all others. Star topology: every host is one hop from the hub. The hub itself executes locally, no SSH overhead.
AI Agent (MCP client)
│
MCP protocol
│
┌──────┴──────┐
│ Maestro │ ← hub machine (is_local: true)
└──┬───┬───┬──┘
│ │ │
SSH ControlMaster pool
│ │ │
┌────┘ │ └────┐
▼ ▼ ▼
linux-box win-pc macbook
(bash) (pwsh) (bash)
│
└─► WSL (ProxyJump)
- Python 3.12+
- SSH configured with
~/.ssh/configentries for your remote hosts (ControlMaster recommended) - MCP SDK (
pip install "mcp[cli]")
git clone https://github.com/rmstxrx/maestro-mcp.git
cd maestro-mcp
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtCopy the example config and edit it. CRITICAL: hosts.yaml and .env contain sensitive data (IPs, hostnames, PIN hashes, and tokens). They are git-ignored by default. Never commit these files or hardcode sensitive topology details if you plan to push your fork to a public repository.
cp hosts.example.yaml hosts.yaml# hosts.yaml — define your machine fleet
hosts:
workstation:
alias: ssh-workstation # must match a Host entry in ~/.ssh/config
description: "Main dev box, Arch Linux"
is_local: true # hub machine — no SSH, direct execution
gpu-box:
alias: ssh-gpu
description: "Training rig, Ubuntu 24.04"
# shell: bash (default)
macbook:
alias: ssh-macbook
description: "MacBook Pro, on the go"
windows-pc:
alias: ssh-winpc
description: "Windows 11, PowerShell"
shell: powershell
windows-wsl:
alias: ssh-winpc-wsl
description: "WSL2 on windows-pc (ProxyJump)"
# shell: bash (default)# Generate a PIN hash for the OAuth consent gate
python -c "import hashlib; pin = input('Choose a PIN: '); print(hashlib.sha256(pin.encode()).hexdigest())"Create your .env file:
cp .env.example .env
# Edit .env and paste your PIN hash# .env
MAESTRO_AUTHORIZE_PIN_HASH="your_sha256_hash_here"
SSH_TIMEOUT=300
MAESTRO_ISSUER_URL=https://your-domain.example.com # Required for HTTP transport
# MAESTRO_DEFAULT_REPO=~/workspace # Default working dir for agent tools# Local MCP client (stdio transport, for Codex CLI / Claude Code / Claude Desktop)
.venv/bin/python server.py --transport stdio
# Remote/cloud access (HTTP transport, for Claude.ai via tunnel)
.venv/bin/python server.py --transport streamable-http --port 8222 --host 127.0.0.1Claude Code:
claude mcp add maestro -- /path/to/maestro-mcp/.venv/bin/python /path/to/maestro-mcp/server.py --transport stdioCodex CLI:
codex mcp add maestro -- /path/to/maestro-mcp/.venv/bin/python /path/to/maestro-mcp/server.py --transport stdioClaude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"maestro": {
"command": "/path/to/maestro-mcp/.venv/bin/python",
"args": ["/path/to/maestro-mcp/server.py", "--transport", "stdio"]
}
}
}Claude.ai (via Cloudflare Tunnel or similar): Point the MCP connector to your tunnel URL. OAuth consent is handled automatically for Claude.ai clients.
| Tool | Description |
|---|---|
exec |
Execute a shell command on any host |
script |
Run a multi-line script (piped via bash -s or PowerShell) |
read |
Read a text file (with optional head/tail line limits) |
write |
Write or append to a file (creates parent dirs automatically) |
transfer |
SCP a file to or from a remote host |
status |
Health check all hosts, auto-reconnect stale connections |
| Tool | Description |
|---|---|
claude |
Run Claude Code with inline-or-background auto-promote |
codex |
Run OpenAI Codex CLI with inline-or-background auto-promote |
gemini |
Run Gemini CLI with approval_mode and resume support |
opencode |
Run OpenCode CLI with session_id, model selection, and JSON format |
opencode_sessions |
List previous OpenCode CLI sessions on a host |
gemini_sessions |
List previous Gemini CLI sessions on a host |
install_agent |
Install a CLI agent (opencode/codex/gemini/claude) on a remote host |
poll |
Check status of an auto-promoted task |
read_output |
Read full or partial output from a completed task |
agent_status |
Check which CLI agents are available on a host |
Why did Gemini change? The
modeparameter was replaced withapproval_modeto align directly with Gemini CLI flags (plan,yolo,auto_edit). Addedresumesupport for continuing sessions andgemini_sessionsfor easier session management.
Maestro relies on your existing ~/.ssh/config. Here's a recommended setup for fleet usage:
# Global: enable ControlMaster for all hosts
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
ServerAliveInterval 30
ServerAliveCountMax 3
# Direct hosts
Host ssh-gpu
HostName 192.168.1.100
User dev
Host ssh-macbook
HostName macbook.local
User user
# Windows host (PowerShell over OpenSSH)
Host ssh-winpc
HostName 192.168.1.200
User admin
# WSL via ProxyJump through Windows host
Host ssh-winpc-wsl
HostName localhost
Port 2222
User user
ProxyJump ssh-winpc# Don't forget to create the sockets directory
mkdir -p ~/.ssh/sockets# /etc/systemd/system/maestro.service
[Unit]
Description=Maestro MCP Server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=youruser
WorkingDirectory=/path/to/maestro-mcp
EnvironmentFile=/path/to/maestro-mcp/.env
ExecStart=/path/to/maestro-mcp/.venv/bin/python server.py --transport streamable-http --port 8222 --host 127.0.0.1
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetIf you want Claude.ai to reach your Maestro instance:
cloudflared tunnel --url http://localhost:8222Or as a persistent named tunnel — see Cloudflare's documentation.
maestro-mcp/
├── server.py # Main MCP server — fleet tools + agent orchestra
├── maestro_oauth.py # OAuth 2.1 provider with PIN-gated consent
├── hosts.yaml # Your fleet definition (git-ignored)
├── hosts.example.yaml # Example fleet config
├── .env # Secrets — PIN hash, tokens (git-ignored)
├── .env.example # Template for .env
├── pyproject.toml # Project metadata
├── requirements.txt # Python dependencies
├── maestro.service # systemd unit file (example)
├── cloudflared-maestro.service # Cloudflare Tunnel unit (example)
└── LICENSE # Apache 2.0
A key design insight from daily usage with Claude: tool responses consume LLM context. Every byte returned by read enters the conversation permanently. For large files, this causes context exhaustion.
Best practice:
- Use
execwithgrep,head,tail,sed,awk,jqfor surgical reads - Use
transferto move files to the hub disk (response is just[OK], ≈0 context cost) - Use
readwithhead/tailparameters for bounded reads - Reserve
read(no limits) for files under ~100 lines
The agent orchestra tools follow the same principle: full output is saved to disk, and only a truncated summary enters the conversation. Use read_output with line ranges for targeted inspection.
Maestro was born from necessity. I work across three machines — a Linux box for inference, a Windows PC for training, and a MacBook for when I'm away from the desk. I got tired of my AI assistant only seeing one machine at a time while I had to manually bridge the gaps.
What started as a simple SSH relay grew into a full orchestration layer: persistent connections, cross-platform shell awareness, agent dispatch, and eventually OAuth for remote access from Claude.ai. The name came naturally — if the models are the instruments, someone needs to conduct.
Apache 2.0 — use it freely, contribute fearlessly, and don't weaponize patents.
Contributions are welcome. If you're building something with Maestro, I'd love to hear about it.
For bug reports and feature requests, open an issue. For code contributions, please open a PR with a clear description of what changed and why.