mcp server
pty-pilot
MCP server letting an agent drive interactive PTY/pipe terminal sessions
Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
{
"mcpServers": {
"pty-pilot": {
"command": "uvx",
"args": [
"pty-pilot"
]
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 23, 2026pty-pilot
An MCP server that lets an agent pilot a terminal — REPLs, password prompts, full-screen TUIs, anything that needs a real PTY. Architecturally modeled after OpenAI Codex CLI's
UnifiedExec.
The built-in Bash tool in most agent harnesses is one-shot: it runs a command and returns the output. It can't drive a REPL, can't answer a prompt, and chokes on TTY-only commands like claude doctor, ssh user@host …interactive…, password prompts, or curses-style TUIs. pty-pilot adds four MCP tools that solve that.
Built and tested with Claude Code; works with any MCP client.
Tools
| Tool | Purpose |
|---|---|
term_open(cmd, …) | Spawn a process. Returns final output if it exits within yield_ms, otherwise a session_id. |
term_send_keys(session_id, chars, …) | Write to stdin, return any output that arrives before yield_ms. Empty chars polls without writing. |
term_close(session_id) | SIGTERM, then SIGKILL after 500ms. Kills the whole process group. |
term_list() | List live sessions with PID, cmd, age, idle. |
Full parameters documented in the tool descriptions registered with the server (see src/pty_pilot/server.py).
Design notes
- No expect/prompt detection. Every call deadline-drains the output buffer; the model picks
yield_msand re-polls. The minimum-yield clamps (250 ms active, 5000 ms empty-poll) keep models from busy-looping. Borrowed from Codex. - PTY backend:
ptyprocess(Unix).tty=falseuses a plainsubprocess.Popenwith pipes — cheaper, but no terminal semantics. Default istty=false. - Env scrubbing on spawn:
TERM=dumb,NO_COLOR=1,PAGER=cat,GIT_PAGER=cat,LANG=C.UTF-8, etc. Suppresses most color/pager noise at the source. - ANSI strip default-on.
raw=truekeeps escapes (rarely needed). - Bounded memory: per-session head/tail buffer capped at 256 KiB. Per-call response further truncated to
max_output_bytes(default 32 KiB). - Session limit: 32 concurrent. LRU eviction; the 4 most-recently-used are protected from eviction.
- Process-group kill:
SIGTERM(thenSIGKILL) to the entire pgid, so REPL → shell → child trees get reaped.
Install
Requires Python ≥ 3.10 and an MCP client.
git clone https://github.com/Shine12222/pty-pilot
cd pty-pilot
python3 -m venv .venv
.venv/bin/pip install -e .
Register with Claude Code (user scope, available everywhere):
claude mcp add --scope user pty-pilot "$PWD/.venv/bin/python" -- -m pty_pilot
Verify:
claude mcp list
# pty-pilot: …/.venv/bin/python -m pty_pilot - ✓ Connected
Open a new Claude Code session and the term_* tools will be visible under /mcp.
When to use vs. plain Bash
Use Bash for one-shot commands. It's cheaper and gives the model less rope. Use pty-pilot only when:
- The program needs a real TTY (password prompts, sudo, full-screen TUIs).
- You're driving a REPL (
python -i,node,psql,sqlite3, …). - You need to inspect a long-running process mid-flight.
Avoid for git interactive flows — use git -c core.editor=true, --no-edit, GIT_EDITOR=true, or commit -m. The Codex team explicitly warns against this and the same caveat applies here.
Tests
.venv/bin/python tests/test_smoke.py
Eight scenarios: one-shot exec, mid-flight pipe polling, Python REPL via PTY, multi-line REPL input, ANSI strip, ANSI raw mode, head/tail truncation under heavy output, terminate of long-running session.
Limitations
- Unix only for now. Windows ConPTY would be a second backend in
process.py. - No 2D screen model. Output is a flat byte stream; cursor-positioning TUIs (vim, htop, fullscreen ncurses) survive but look messy. A
tmux capture-pane-style alternative is plausible for v2. - No sandboxing. Trusts the host environment. Codex has Seatbelt/bwrap/landlock; pty-pilot does not.
- No expect-pattern primitive. If you need "send X, wait for prompt Y to come back," you loop in the model. A
term_send_and_wait(pattern, timeout)could be added if it turns out to be the bottleneck.
Credits
Architecture and parameter shapes (esp. yield_ms clamps, head/tail elision, env scrub list, session protection policy, "don't drive git interactive" warning) are lifted from the OpenAI Codex CLI's UnifiedExec. Thanks to that team for doing the hard design work first.
License
MIT — see LICENSE.