Skip to main content
Glama
brkhrdt
by brkhrdt
README.md
# PTY-MCP

MCP server exposing PTY (pseudo-terminal) sessions for AI agents. Enables programmatic control of shell sessions and REPLs through the Model Context Protocol.

## Features

- Start and manage multiple PTY sessions
- Run commands with sentinel-based completion detection
- Works with any shell (bash, zsh, tcsh, fish, etc.)
- Works with nested REPLs (Python, Node, Tcl, etc.)
- Configurable session timeout and buffer size
- Raw input support for interactive applications

## Installation

```bash
uv add pty-mcp
```

## Usage

### As an MCP Server

Add to your MCP client configuration:

```json
{
  "mcpServers": {
    "pty": {
      "command": "uv",
      "args": ["run", "pty-mcp"]
    }
  }
}
```

Or run directly:

```bash
uv run pty-mcp --max-sessions 10 --log-dir /path/to/logs
```

The `--log-dir` option enables real-time session logging. When specified, each session's output is written immediately to a log file named `pty_<command_name>_<session_id>.log` (e.g., `pty_bash_3a4b5c6d7e8f.log`). The directory must exist; the server will error if it doesn't. You can watch logs in real-time with `tail -f /path/to/logs/*.log`.

### MCP Tools

#### `start_session`

Start a new PTY session with any command or shell.

**Parameters:**
- `command` (optional): Command/binary to execute (default: `$SHELL` or `/bin/bash`). Can be any executable like `bash`, `python3`, `tcl`, `somebinary -a -b`, etc. If `args` is not provided, the command string will be automatically parsed to extract arguments.
- `args` (optional): List of arguments to pass to the command. If omitted, arguments will be parsed from the `command` string. Explicitly provide this when arguments contain spaces or special characters.
- `cwd` (optional): Working directory
- `timeout_session` (optional): Idle timeout (default: 86400)
- `buffer_size` (optional): Scrollback buffer lines (default: 1000)
- `sentinel_command` (optional): Command to echo sentinel (default: `echo {sentinel}`)

**Returns:** Session ID

**Examples:**
```python
# Start default shell (bash)
start_session()

# Start Python REPL
start_session(command="python3")

# Start custom binary with arguments (auto-parsed)
start_session(command="somebinary -a -b --args")

# Start with explicit args (for complex arguments)
start_session(command="somebinary", args=["-a", "-b", "--args"])

# Start Tcl shell in specific directory
start_session(command="tclsh", cwd="/path/to/project")
```

#### `run_command`

Run a command and wait for completion.

**Parameters:**
- `session_id` (required): Session ID from `start_session`
- `command` (required): Command to run
- `timeout` (optional): Timeout in seconds (default: 1800)

**Returns:** Command output

#### `send_keys`

Send raw input without waiting for completion.

**Parameters:**
- `session_id` (required): Session ID
- `keys` (required): Raw input (use `\n` for Enter, `\x03` for Ctrl+C)

#### `get_buffer`

Get scrollback buffer contents.

**Parameters:**
- `session_id` (required): Session ID
- `lines` (optional): Number of lines from end

**Returns:** Buffer contents

#### `stop_session`

Stop and clean up a session.

**Parameters:**
- `session_id` (required): Session ID to stop

#### `set_sentinel`

Change the sentinel command for a session. Use when switching between shells/REPLs.

**Parameters:**
- `session_id` (required): Session ID
- `sentinel_command` (required): New sentinel command template with `{sentinel}` placeholder

#### `list_sessions`

List all active sessions with metadata.

## Working with REPLs

When switching from a shell to a REPL (or between REPLs), use `set_sentinel` to update the sentinel command:

```python
# Start with bash (default sentinel: echo {sentinel})
session_id = start_session()

# Run some bash commands
run_command(session_id, "ls -la")

# Switch to Python REPL
send_keys(session_id, "python3\n")
set_sentinel(session_id, "print('{sentinel}')")

# Now run Python commands
run_command(session_id, "print('hello from python')")
run_command(session_id, "2 + 2")

# Exit Python and switch back to bash
send_keys(session_id, "exit()\n")
set_sentinel(session_id, "echo {sentinel}")
```

**Common sentinel commands:**
- Bash/sh/zsh: `echo {sentinel}`
- Python: `print('{sentinel}')`
- Node.js: `console.log('{sentinel}')`
- Tcl: `puts {sentinel}`
- Ruby (irb): `puts '{sentinel}'`

## Development

```bash
# Install dependencies
uv sync

# Run tests
uv run pytest tests/ -v
```

## License

MIT

TDQS

A3.8/5.0

Scored across 7 tools

Disambiguation5/5

Each tool has a clear, distinct purpose: session lifecycle (start, stop, list), command execution, interactive input, output retrieval, and sentinel configuration. No overlaps.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case (e.g., start_session, get_buffer), making predictions easy.

Tool Count5/5

7 tools is well-scoped for managing PTY sessions, covering creation, interaction, output, and cleanup without excess.

Completeness4/5

Core lifecycle and interaction are covered, but lacks tools for session details (e.g., size) or resizing, which are minor gaps.