Let AI Agents control your remote servers through tmux β perfect for jump-host environments where direct SSH isn't possible.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your Machine (Local) β
β β
β ββββββββββββββββ ββββββββββββββββββββββ β
β β tmux session β βββββββΊ β AI Agent (MCP) β β
β β (any name) β β mcp_server.py β β
β β β β β β
β β Manual login:β β send-keys ββββΊ β β
β β jump β targetβ β ββββ capture-pane β β
β ββββββββ¬ββββββββ ββββββββββββββββββββββ β
β β β
βββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββ
β SSH
βββββββΌββββββ
β Jump Host β β No deployment needed
βββββββ¬ββββββ
β SSH
βββββββΌββββββ
β Target β β Server the AI agent controls
βββββββββββββ
Core idea: You manually establish SSH connections through jump hosts. The AI Agent uses tmux API (send-keys / capture-pane) to send commands and read output from your established sessions. Everything runs locally β no changes needed on jump hosts or target servers.
git clone https://github.com/your-username/tmux-mcp-agent.git
cd tmux-mcp-agent
bash setup.shThis will automatically:
- Check and install tmux
- Create a Python virtual environment
- Install dependencies (
mcpSDK)
Create a tmux session and login manually. Session names are completely flexible:
tmux new-session -s work
ssh your_jump_host # login to jump host
ssh your_target_server # login to target server
# Press Ctrl+B D to detach (session stays in background)Open another terminal to test:
python3 tmux_agent.py list # list all tmux sessions
python3 tmux_agent.py -t work:0.0 capture # read screen content
python3 tmux_agent.py -t work:0.0 run "hostname" # run a commandAdd to your IDE's MCP config:
{
"mcpServers": {
"tmux-remote": {
"command": "/path/to/tmux-mcp-agent/.venv/bin/python",
"args": ["/path/to/tmux-mcp-agent/mcp_server.py"],
"env": {}
}
}
}| Tool | Description |
|---|---|
tmux_list_sessions |
List all tmux sessions |
tmux_list_all_panes |
β‘ Fast overview of all panes across sessions |
tmux_discover_servers |
π Deep scan: run hostname/whoami in panes |
tmux_run_command |
Execute command and return output (smart wait) |
tmux_capture_pane |
Read current screen content |
tmux_send_keys |
Send raw keys (for interactive programs) |
tmux_send_ctrl_c |
Send Ctrl+C to interrupt |
tmux_safe_execute |
π‘οΈ Run command with connection safety checks |
tmux_connection_guard |
π Check SSH connection status |
tmux_remote_parallel |
π Run parallel tasks in remote tmux |
tmux_check_remote_tasks |
π Monitor parallel task status with exit codes & duration |
tmux_kill_remote_tasks |
ποΈ Stop individual tasks or kill entire remote session |
tmux_register_server |
Tag servers for natural language matching |
tmux_find_server |
Find server by natural language query |
tmux_health_check |
Quick shell responsiveness check |
tmux_set_pane_title |
Label panes for easy identification |
tmux_create_session |
Create a new tmux session |
tmux_create_window |
Create a new window in a session |
tmux_split_pane |
Split a pane horizontally or vertically |
tmux_kill_session/window/pane |
Destroy sessions, windows, or panes |
After configuration, you can ask the AI Agent:
- "Check disk usage on the remote server"
- "Check nginx status on the target server"
- "Find recently modified log files"
- "Deploy the latest code to production"
The tmux_safe_execute and tmux_connection_guard tools prevent dangerous misoperations when SSH connections drop:
- Health check: Is the shell responsive?
- Hostname verification: Are we on the expected remote host?
- Local detection: Block commands if accidentally targeting local machine
- Reconnection guidance: Clear instructions when disconnection is detected
Run multiple long-running commands in parallel on remote hosts. Tasks are disconnect-resilient β they continue running even if your SSH connection drops.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your Machine (Local) β
β β
β ββββββββββββββββ ββββββββββββββββββββββββ β
β β tmux pane β βββββββΊ β AI Agent (MCP) β β
β β SSH session β β mcp_server.py β β
β ββββββββ¬ββββββββ ββββββββββββββββββββββββ β
βββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SSH (can disconnect!)
βββββββΌββββββββββββββββββββββββββββββββββββββββββββββββ
β Remote Host β
β β
β tmux session "ai_work" β survives disconnect β
β ββββββββββββ ββββββββββββ ββββββββββββ β
β β window 0 β β window 1 β β window 2 β β
β β "build" β β "test" β β "deploy" β β
β β make buildβ β make test β β ./deploy β β
β ββββββββββββ ββββββββββββ ββββββββββββ β
β β
β /tmp/_tmux_tasks_ai_work/ β status tracking β
β βββ build.status (start time, exit code, etc.) β
β βββ test.status β
β βββ deploy.status β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Step 1: Launch parallel tasks
Ask the AI Agent:
"Run
make build,make test, andtail -f /var/log/app.login parallel on the remote server"
This calls tmux_remote_parallel which:
- Creates a tmux session on the remote host (not local)
- Each command runs in its own window with status tracking
- Records start time, and will record exit code + duration on completion
Step 2: Monitor progress
Ask the AI Agent:
"Check how the remote tasks are going"
This calls tmux_check_remote_tasks which returns:
π Remote Tasks Status (session: ai_work):
β
[build] completed (exit code: 0) in 2m34s
Build successful: 142 targets built
π [test] running (1m12s elapsed)
Running test suite: 87/120 passed...
π [logs] running (3m45s elapsed)
[2024-01-15 10:23:45] INFO: Request processed in 12ms
Step 3: Stop or clean up
"Stop the log tailing task" β
tmux_kill_remote_tasks(window_name='logs')"Clean up all remote tasks" βtmux_kill_remote_tasks()(kills entire session)
| Scenario | Commands |
|---|---|
| Build & Test | ['make build', 'make test', 'make lint'] |
| Log Monitoring | ['tail -f /var/log/app.log', 'tail -f /var/log/error.log'] |
| Data Processing | ['python process_batch_1.py', 'python process_batch_2.py'] |
| Deployment | ['docker build -t app .', 'npm run build', 'python manage.py migrate'] |
| System Diagnostics | ['vmstat 1', 'iostat -x 1', 'tail -f /var/log/syslog'] |
tmux_remote_parallel(
commands=['make build', 'pytest -v', 'flake8 .'],
window_names=['build', 'test', 'lint'],
session_name='ci_pipeline'
)
Add tasks to an already-running session without killing previous tasks:
tmux_remote_parallel(
commands=['tail -f /var/log/nginx/access.log'],
window_names=['nginx_logs'],
session_name='ai_work',
reuse_session=True
)
If your SSH connection drops mid-task:
- Tasks continue running in the remote tmux session
- Reconnect SSH manually (or have AI send SSH command via
tmux_send_keys) - Check task status with
tmux_check_remote_tasksβ it reads status files - Or attach interactively:
tmux attach -t ai_work
Find the right pane automatically through multiple strategies:
- Explicit
targetparameter server_hintnatural language matching- Pane title matching (instant, no commands sent)
- Auto-select when only one server exists
tmux new-session -s dev # development environment
tmux new-session -s ops # operations environment
# Login to different servers in each sessionTag servers for natural language targeting:
tmux_register_server(target="dev:0.0", name="Web Frontend", tags=["prod", "web"])
tmux_run_command(server_hint="web frontend", command="uptime")
from tmux_agent import TmuxAgent
agent = TmuxAgent(session_name="work", pane_target="work:0.0")
output = agent.run_command("ls -la /var/log")
print(output)tmux-mcp-agent/
βββ README.md # English documentation
βββ README_zh.md # Chinese documentation
βββ tmux_agent.py # Core controller (TmuxAgent class + CLI)
βββ mcp_server.py # MCP Server (AI Agent integration)
βββ setup.sh # Quick setup script
βββ requirements.txt # Python dependencies
βββ LICENSE # MIT License
- Security: Jump host passwords/keys are entered manually β the AI Agent never touches credentials
- Timeout: Default command timeout is 5 minutes (
max_wait=300), adjustable per command - Output limit:
capture-panecaptures 200 lines by default; use| tailor| headfor long output - Interactive programs: Use
send_keysinstead ofrun_commandforvim,top, etc. - Connection loss: If SSH disconnects, you need to reconnect manually; use
connection_guardfor detection