Skip to content

radical-beard/interactive-shell-mcp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

interactive-shell-mcp

MCP server that lets AI agents drive interactive terminal programs via persistent PTY sessions. Start a shell, send keystrokes, capture screen snapshots, and stop the session -- all through four simple tools.

Works with any interactive program: vim, ssh, python REPL, htop, psql, and more.

Quick Start

Run the server:

uv run --script server.py

Requires Python 3.10+. Dependencies (mcp[cli]>=1.0, pydantic>=2) are declared inline and installed automatically by uv.

MCP Server Setup

Add to your ~/.claude.json to make it available in Claude Code:

{
  "mcpServers": {
    "interactive-shell": {
      "command": "uv",
      "args": ["run", "--script", "/path/to/interactive-shell-mcp/server.py"]
    }
  }
}

Replace /path/to/ with the actual path to the project directory.

Tools

interactive_shell_start

Launch a command in a persistent terminal session.

Parameter Type Default Description
command string required Shell command to run
cwd string /tmp Working directory for the process
rows int 30 Terminal height (minimum 10)
cols int 120 Terminal width (minimum 40)
session string "" Optional stable session ID. Auto-generated UUID if omitted

Returns: {session, pid, rows, cols, alive}

interactive_shell_snapshot

Capture the current screen content.

Parameter Type Default Description
session string required Session ID from start

Returns: {ok, alive, lines} where lines is an array of {line: int, text: str} (1-based line numbers, only non-empty lines included).

interactive_shell_input

Send text and special keys to the terminal.

Parameter Type Default Description
session string required Session ID from start
input string required Input payload (plain text + key tokens)

Returns: {ok: true}

interactive_shell_stop

Terminate the session and its child process.

Parameter Type Default Description
session string required Session ID from start

Returns: {ok: true, stopped: true}

Key Syntax Reference

The input parameter supports plain text mixed with special key tokens and escape sequences.

Special Keys

Token Key
<CR> Enter / Return
<ENTER> Enter / Return
<ESC> Escape
<TAB> Tab
<BS> Backspace
<BACKSPACE> Backspace
<SPACE> Space
<UP> Arrow Up
<DOWN> Arrow Down
<LEFT> Arrow Left
<RIGHT> Arrow Right
<HOME> Home
<END> End
<PAGEUP> Page Up
<PAGEDOWN> Page Down
<DELETE> Delete
<INSERT> Insert
<F1> F1
<F2> F2
<F3> F3
<F4> F4

Control Keys

Token Key
<C-c> Ctrl+C
<C-d> Ctrl+D
<C-z> Ctrl+Z
<C-a> Ctrl+A
<C-l> Ctrl+L
<C-S-t> Ctrl+Shift+T

Any single letter works with <C-x>. The <C-S-x> form includes Shift (though for letters, the control byte is the same).

Escape Sequences

Sequence Meaning
\n Newline (LF)
\r Carriage return
\t Tab
\< Literal <
\\ Literal \

Examples

Input string Effect
ls -la<CR> Type "ls -la" then press Enter
<C-c> Send Ctrl+C (interrupt)
hello<TAB> Type "hello" then press Tab
<ESC>:wq<CR> Escape, type ":wq", press Enter
<UP><UP><CR> Press Up twice, then Enter

Example Workflow

A typical session follows this pattern:

1. START   -- launch the program
2. SNAPSHOT -- see what's on screen
3. INPUT   -- send keystrokes
4. SNAPSHOT -- verify the result
5. ...repeat 3-4 as needed...
6. STOP    -- terminate when done

Concrete example: running a Python REPL

# 1. Start a Python session
interactive_shell_start(command="python3", session="py-repl")

# 2. See the initial prompt
interactive_shell_snapshot(session="py-repl")
# -> lines: [{line: 1, text: "Python 3.x.x ..."}, {line: 3, text: ">>>"}]

# 3. Send a command
interactive_shell_input(session="py-repl", input="print('hello world')<CR>")

# 4. See the output
interactive_shell_snapshot(session="py-repl")
# -> lines include "hello world" and a new ">>>" prompt

# 5. Exit cleanly
interactive_shell_input(session="py-repl", input="exit()<CR>")

# 6. Stop the session
interactive_shell_stop(session="py-repl")

Tips for Reliable Terminal Interaction

  • Wait before snapshot: After sending input, give the program a moment to process. Complex commands may need a brief pause before snapshotting.
  • Use named sessions: Pass a stable session ID (e.g., "vim-editor") instead of relying on auto-generated UUIDs. This makes multi-step workflows easier to follow.
  • Check alive: The snapshot response includes alive: bool. If the process has exited, stop the session to clean up.
  • Use <CR> not \n: To press Enter, use <CR> or <ENTER>. Using \n sends a literal newline character, which may behave differently in some programs.
  • Interrupt stuck programs: Send <C-c> to interrupt, or <C-d> to send EOF.
  • Set appropriate dimensions: Use rows and cols to match what the program expects. Vim and htop render differently at different sizes.
  • One thing at a time: Send a command, snapshot to verify, then send the next command. Do not blindly chain many inputs without checking results.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages