Skip to main content
Glama
mcp-interactive-terminal

mcp-interactive-terminal

by hugo94z

mcp-interactive-terminal

CI License: MIT Python 3.10+

A Model Context Protocol server that gives AI agents a real interactive terminal on Windows: launch PowerShell, PowerShell 7 or CMD, type into it, read what happens, answer prompts, interrupt processes and resize the window — across multiple sessions that stay alive between tool calls.

Most "terminal" tools for LLMs run a command and return its output. That is not a terminal. Anything that asks a question, shows a menu, draws a progress bar or waits for a keypress is out of reach. This server runs the shell inside a ConPTY (Windows pseudo-console), so the agent talks to a genuine terminal session, exactly like a human.

agent ── MCP (stdio) ──> session manager ── ConPTY ──> powershell.exe / pwsh.exe / cmd.exe
                             │
                             ├─ raw output ring buffer (cursor based reads)
                             └─ VT emulator (rendered screen, like a human sees it)

Features

  • Real PTY sessions — ConPTY under the hood, not pipes. Prompts, TUIs, colors and interactive programs work.

  • Live interaction — send text and named keys (enter, tab, ctrl-c, up, f1…), read incrementally.

  • Rendered screen — an internal VT100 emulator turns cursor movements and repaints into clean, readable text.

  • Blocking waits — wait for a regex, for output to go quiet, for the process to exit, or for a timeout. No polling.

  • Multiple sessions — independent shells running in parallel, each with its own buffer, screen and size.

  • One-shot shortcut — terminal_exec for commands that only need output and an exit code.

  • UTF-8 everywhere — accents and non-ASCII output are handled for PowerShell and CMD.

  • Token friendly — incremental reads, grep/tail filters, head+tail truncation with an explicit omission marker.

Related MCP server: Interactive Terminal MCP Server

Requirements

  • Windows 10 (1809+) or Windows 11 — ConPTY is required.

  • Python 3.10+.

  • An MCP client (Claude Desktop, Cursor, opencode, Cline, any SDK-based agent).

Install

pip install git+https://github.com/hugo94z/mcp-interactive-terminal

Or from a clone:

git clone https://github.com/hugo94z/mcp-interactive-terminal
cd mcp-interactive-terminal
uv venv .venv
uv pip install --python .venv\Scripts\python.exe -e .

The mcp-interactive-terminal command starts the server on stdio.

Configure your MCP client

opencode (~/.config/opencode/opencode.jsonc)

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      "interactive-terminal": {
        "type": "local",
        "command": ["mcp-interactive-terminal"]
      }
    }
  }
}

Claude Desktop (claude_desktop_config.json)

{
  "mcpServers": {
    "interactive-terminal": {
      "command": "mcp-interactive-terminal"
    }
  }
}

Cursor (.cursor/mcp.json)

{
  "mcpServers": {
    "interactive-terminal": {
      "command": "mcp-interactive-terminal"
    }
  }
}

If the command is not on your PATH, use the absolute path to the entry point, for example:

{
  "command": "C:\\Users\\you\\project\\.venv\\Scripts\\mcp-interactive-terminal.exe"
}

Tools

Tool

Description

terminal_start

Start a session (powershell, pwsh, cmd, or any executable), with cwd, env, cols, rows, name, replace, args. Returns the id, pid and initial screen.

terminal_send

Send text, named keys, enter=true, repeat.

terminal_read

Incremental raw output since the last read (or an explicit since cursor). Optional grep, tail, strip_ansi.

terminal_wait

Block until until regex matches, output is quiet for quiet_ms, the session exits, or timeout_ms. Provide until and/or quiet_ms.

terminal_screen

Rendered VT screen with cursor position — the authoritative view.

terminal_interrupt

Ctrl+C, then terminate the child process tree if the command is still running. The shell survives.

terminal_resize

Resize the pseudo-terminal (columns × rows).

terminal_list

Active sessions, state, pid, cwd, size, idle time.

terminal_stop

Close a session (force to kill the tree).

terminal_exec

One-shot command: output, exit_code, timed_out, duration.

Keys accepted by terminal_send

enter tab backtab esc space backspace up down left right home end pageup pagedown insert delete f1…f12 ctrl-a…ctrl-z ctrl-space ctrl-break, plus text:<literal> for arbitrary text.

Example

terminal_start(shell="powershell", cwd="C:/work/api")
-> session_id: "t1", screen: "PS C:\\work\\api> "

terminal_send(session_id="t1", text="python -m http.server 8080", enter=True)
terminal_wait(session_id="t1", until="Serving HTTP on", timeout_ms=15000)
-> reason: "matched"

terminal_exec(command="curl.exe -s -o NUL -w '%{http_code}' http://localhost:8080")
-> output: "200", exit_code: 0

terminal_interrupt(session_id="t1")
-> sent: true, running: true      # back to the prompt

terminal_send(session_id="t1", text="exit", enter=True)
terminal_stop(session_id="t1")

Why terminal_screen and terminal_read both exist

PowerShell uses PSReadLine, which redraws the current line with absolute cursor movements every time a character is typed. Raw output therefore contains fragments such as \x1b[1;58He, \x1b[1;58Hec, \x1b[1;58Hech… Stripping ANSI codes gives unreadable text.

terminal_screen feeds that stream into a VT100 emulator (via pyte) and returns what a human would actually see. terminal_read is still useful for exact incremental output (logs, byte streams, detecting events) and never returns the same bytes twice.

terminal_wait matches against the rendered screen and the raw output, and ignores the echo of the command you just typed by default (ignore_echo).

Design notes

  • One reader thread per session pushes output into a bounded ring buffer and the VT screen under a single lock.

  • Reads are cursor-based (buffer end offset), so nothing is duplicated and nothing is lost silently.

  • terminal_wait sleeps on a condition variable — no busy loop, negligible CPU.

  • Sessions are closed on exit (atexit, EOF on stdio, or explicit terminal_stop); forced stops use taskkill /T /F on the process tree.

  • PowerShell sessions are started with -NoExit -Command to force UTF-8 console encoding before the first prompt.

  • CMD sessions run chcp 65001 at startup.

Notes on Windows behaviour

  • Ctrl+C in a pseudo-console is not delivered as a console control event to native child processes: the control character reaches the console input buffer, but the child process group does not receive CTRL_C_EVENT. terminal_interrupt therefore sends Ctrl+C and then terminates the remaining child process tree while keeping the shell alive. Processes that trap Ctrl+C gracefully get the chance to run their handler first.

  • Resizing the pseudo-console can make some shells drop the next write. See Known limitations.

Known limitations

  • Windows only. ConPTY does not exist on Linux or macOS, so there is no POSIX backend yet.

  • terminal_resize works, but some shells need a moment to redraw after a size change; give the next command a short delay if you resize in the middle of a session.

  • The rendered screen shows the visible window only. Use terminal_read for full scrollback (bounded by the 500k-character ring buffer).

  • Interactive programs that require raw mouse events or bracketed paste are not emulated.

Security

This server executes arbitrary commands with the privileges of the user running it. There is no sandbox, no allowlist and no confirmation prompt. Only connect it to MCP clients you trust, and treat its tools with the same care as a shell running on your machine.

Development

uv venv .venv
uv pip install --python .venv\Scripts\python.exe -e ".[dev]"
.venv\Scripts\python.exe -m pytest -q

The test suite covers the ring buffer, VT rendering, key mapping, truncation, real PowerShell/CMD sessions (interactive prompt, Ctrl+C, resize, exit codes) and a full MCP client handshake over stdio.

License

MIT — see LICENSE.

Available Tools

10 tools
terminal_execA

Run a one-shot command to completion and return its output and exit code.

Use this for non-interactive commands. Use terminal_start + terminal_send for programs that need input, a TUI, or a persistent shell.

Args: command: Command line to execute. shell: "powershell", "pwsh" or "cmd". cwd: Working directory. Defaults to the server's current directory. env: Extra environment variables. timeout_ms: Kill the command after this long. max_chars: Maximum output characters returned.

Returns: output, exit_code, timed_out, duration_ms, truncated.

Inputs: command (required), cwd, env, shell, +2 more.

terminal_interruptA

Stop the command running in a session, keeping the shell alive.

Sends Ctrl+C first. Native Windows programs often ignore the control character inside a pseudo-console, so any child process still running after a short grace period is terminated together with its own children. The shell itself is preserved.

Args: session_id: Session returned by terminal_start. force: Skip the grace period and terminate child processes immediately.

Returns: session_id, sent, running and the list of terminated pids.

Inputs: session_id (required), force.

terminal_listB

List active sessions with their state, pid, cwd, size, idle time and buffer size.

Inputs: no named parameters.

terminal_readA

Read incremental raw output from a session, without duplicates.

Each call returns only what arrived after the previous read. Use the returned cursor with since to resume from an explicit position.

Args: session_id: Session returned by terminal_start. since: Absolute character offset to read from. Defaults to the last read position. max_chars: Maximum characters returned (head+tail with an explicit omission marker). grep: Keep only lines matching this regular expression. tail: Keep only the last N lines (applied after grep). strip_ansi: Remove ANSI escape sequences.

Returns: text, cursor (pass as since), dropped, truncated, running, exit_code.

Note: PowerShell (PSReadLine) repaints the current line with cursor movements, so raw output contains fragments. Use terminal_screen for an authoritative view.

Inputs: session_id (required), grep, tail, since, +2 more.

terminal_resizeA

Resize the pseudo-terminal (affects wrapping and full-screen programs).

Args: session_id: Session returned by terminal_start. cols: New width, 2..1000. rows: New height, 2..500.

Inputs: cols (required), rows (required), session_id (required).

terminal_screenA

Return the rendered terminal screen (VT emulation) with cursor position.

This is the clean view: cursor moves, erases and color codes are applied, so it shows exactly what a human would see, including the current prompt or TUI.

Args: session_id: Session returned by terminal_start. max_chars: Maximum characters returned (head+tail with an omission marker).

Returns: text, cursor {x,y}, cols, rows, running, exit_code.

Inputs: session_id (required), max_chars.

terminal_sendA

Send text and/or named keys to a session.

Args: session_id: Session returned by terminal_start. text: Literal text to type (not followed by Enter unless enter=true). keys: Named keys, e.g. ["ctrl-c"], ["up"], ["tab"], ["f5"], ["text:abc"]. Supported: enter, tab, backtab, esc, space, backspace, up, down, left, right, home, end, pageup, pagedown, insert, delete, f1..f12, ctrl-a..ctrl-z, ctrl-space, ctrl-break. enter: Append a carriage return after text/keys. repeat: Repeat the whole sequence 1..100 times.

Returns: session_id, sent_chars and running state.

Inputs: session_id (required), keys, text, enter, +1 more.

terminal_startA

Start an interactive terminal session and return its id plus the initial screen.

Args: shell: "powershell" (Windows PowerShell 5.1), "pwsh" (PowerShell 7), "cmd", or an absolute path to any executable. cwd: Working directory. Defaults to the server's current directory. env: Extra environment variables merged into the inherited environment. cols: Terminal width in columns (default 120). rows: Terminal height in rows (default 30). name: Session id. Auto-generated (t1, t2, ...) when omitted. replace: Kill an existing session with the same name and start a fresh one. args: Extra arguments passed to the shell or executable.

Returns: session_id, shell, cwd, pid, size, ready reason and the rendered screen.

Inputs: cwd, env, args, cols, +4 more.

terminal_stopB

Close a session and free its process.

Args: session_id: Session returned by terminal_start. force: Kill the whole process tree instead of requesting a graceful stop.

Inputs: session_id (required), force.

terminal_waitA

Block until output matches a regex, becomes quiet, the session exits, or timeout.

Args: session_id: Session returned by terminal_start. until: Case-insensitive regular expression to wait for, e.g. "PS C:\|>>>|Done". quiet_ms: Return when no output arrived for this long (0 disables quiet detection). Provide at least one of until or quiet_ms. timeout_ms: Give up after this long. ignore_echo: Ignore the echo of the last command line when matching until (prevents matching the command text itself).

Returns: reason: "matched" | "quiet" | "exited" | "timeout", matched, running, exit_code, and the rendered screen.

Inputs: session_id (required), until, quiet_ms, timeout_ms, +1 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.1/5.0

    Scored across 10 tools

    Disambiguation5/5

    Each tool has a clearly distinct role: lifecycle (start/stop/list/resize), input (send/interrupt), and output (read/screen/wait/exec). The potentially overlapping read vs. screen and wait vs. read pairs are explicitly differentiated in their descriptions (raw incremental vs. rendered VT view; blocking vs. immediate).

    Naming Consistency5/5

    Every tool follows the same terminal_<verb> snake_case pattern with no exceptions. The verb choices are predictable and consistent across the set.

    Tool Count5/5

    Ten tools is well-scoped for interactive terminal control, with each one covering a necessary operation (lifecycle, input, output, waiting, rendering). No redundant or filler tools.

    Completeness4/5

    The surface covers the full interactive lifecycle: start/stop, send/interrupt, read/screen/wait, resize, plus a one-shot exec for non-interactive commands. Minor gaps exist, such as no session rename or explicit scrollback/buffer clearing, but core workflows are fully covered.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI assistants to fully interact with console applications, monitor output, detect errors, and automate terminal workflows across multiple sessions. Similar to how Playwright works for web browsers but for command-line interfaces.
      138 npm
      54
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Provides AI agents with fully interactive terminal sessions, including TUI support, keyboard control, and screen capture across Windows, Linux, and Mac.
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      A PTY-based MCP server providing persistent, interactive shell sessions with strong Windows support, enabling AI agents to run commands, handle interactive tools, and manage large output across MCP-compatible clients.
      228 npm
      12
      MIT