{
  "markdown": "# mcp-interactive-terminal\n\n[![npm version](https://img.shields.io/npm/v/mcp-interactive-terminal.svg)](https://www.npmjs.com/package/mcp-interactive-terminal)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![Node.js >= 18](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org/)\n\nMCP server that gives AI agents (Claude Code, Cursor, Windsurf, etc.) real interactive terminal sessions. Run REPLs, SSH, database clients, and any interactive CLI — with clean text output, smart completion detection, and 7-layer security.\n\n## Why This Exists\n\nAI coding agents can't handle interactive commands. There's no PTY, no stdin streaming. You can't run `rails console`, `python`, `psql`, `ssh`, or any REPL through them. This MCP server fixes that.\n\n```\nAI Agent (Claude Code, Cursor, etc.)\n    ↕  MCP (JSON-RPC over stdio)\nmcp-interactive-terminal\n    ↕  node-pty + xterm-headless\nInteractive Process (rails console, python, psql, ssh, bash...)\n    ↕\nClean text output (exactly what a human would see)\n```\n\n## Install\n\n### Claude Code\n\n```bash\nclaude mcp add terminal -- npx -y mcp-interactive-terminal\n```\n\nThat's it. The server is now available. Ask Claude to \"open a python REPL and calculate 2**100\".\n\n### Cursor\n\nGo to **Settings > MCP Servers**, click **Add Server**, and enter:\n\n```json\n{\n  \"mcpServers\": {\n    \"terminal\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-interactive-terminal\"]\n    }\n  }\n}\n```\n\n### Windsurf\n\nAdd to your MCP configuration:\n\n```json\n{\n  \"mcpServers\": {\n    \"terminal\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-interactive-terminal\"]\n    }\n  }\n}\n```\n\n### VS Code (GitHub Copilot)\n\nAdd to your `.vscode/mcp.json`:\n\n```json\n{\n  \"servers\": {\n    \"terminal\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-interactive-terminal\"]\n    }\n  }\n}\n```\n\n### Any MCP Client\n\nThe server communicates over stdio using the [Model Context Protocol](https://modelcontextprotocol.io/). Any MCP-compatible client can use it with the same `npx -y mcp-interactive-terminal` command.\n\n## Real-World Examples\n\n### Rails Console\n\n```\nYou: \"Open rails console for staging and check the user count\"\n\nAgent creates session → bash\nAgent sends: cd /path/to/app && rails console -e staging\nAgent sends: User.count\nAgent returns: 1,847,293\n```\n\n### Python REPL\n\n```\nYou: \"Open python and test my sorting algorithm\"\n\nAgent creates session → python3\nAgent sends: def quicksort(arr): ...\nAgent sends: quicksort([3, 1, 4, 1, 5, 9])\nAgent returns: [1, 1, 3, 4, 5, 9]\n```\n\n### Database Client\n\n```\nYou: \"Connect to postgres and show me the largest tables\"\n\nAgent creates session → psql -U myuser mydb\nAgent sends: SELECT tablename, pg_size_pretty(pg_total_relation_size(tablename::text)) ...\nAgent returns: formatted table of results\n```\n\n### SSH\n\n```\nYou: \"SSH into the staging server and check disk usage\"\n\nAgent creates session → ssh user@staging.example.com\nAgent sends: df -h\nAgent returns: disk usage table\n```\n\n### Docker\n\n```\nYou: \"Open a shell in my running container and check the logs\"\n\nAgent creates session → docker exec -it my-container bash\nAgent sends: tail -100 /var/log/app.log\nAgent returns: last 100 log lines\n```\n\n### Node.js REPL\n\n```\nYou: \"Open node and test the date parsing logic\"\n\nAgent creates session → node\nAgent sends: new Date('2024-02-29').toISOString()\nAgent returns: 2024-02-29T00:00:00.000Z\n```\n\n## Tools\n\nThe server exposes 7 MCP tools:\n\n### `create_session` — Spawn an interactive process\n\n```json\n{ \"command\": \"python3\", \"name\": \"my-python\", \"cwd\": \"/project\" }\n→ { \"session_id\": \"a1b2c3d4\", \"name\": \"my-python\", \"pid\": 12345 }\n```\n\n| Parameter | Required | Default | Description |\n|-----------|----------|---------|-------------|\n| `command` | Yes | — | Command to run (bash, python3, psql, ssh, etc.) |\n| `args` | No | `[]` | Command arguments |\n| `name` | No | auto | Human-readable session name |\n| `cwd` | No | server cwd | Working directory |\n| `env` | No | `{}` | Additional environment variables |\n| `cols` | No | `120` | Terminal columns |\n| `rows` | No | `40` | Terminal rows |\n\n### `send_command` — Send input and get output\n\n```json\n{ \"session_id\": \"a1b2c3d4\", \"input\": \"1 + 1\" }\n→ { \"output\": \"2\", \"is_complete\": true, \"is_alive\": true }\n```\n\n| Parameter | Required | Default | Description |\n|-----------|----------|---------|-------------|\n| `session_id` | Yes | — | Target session |\n| `input` | Yes | — | Command/input to send (newline appended automatically) |\n| `timeout_ms` | No | `5000` | Max wait time for output |\n| `max_output_chars` | No | `20000` | Truncate output beyond this |\n\nDangerous commands (`rm -rf`, `DROP TABLE`, `curl|bash`, etc.) are blocked — the agent must use `confirm_dangerous_command` first.\n\n### `read_output` — Read terminal screen (read-only)\n\n```json\n{ \"session_id\": \"a1b2c3d4\" }\n→ { \"output\": \">>> \", \"is_alive\": true }\n```\n\nSafe to auto-approve — this only reads, never sends input.\n\n### `list_sessions` — List active sessions (read-only)\n\n```json\n→ [{ \"session_id\": \"a1b2c3d4\", \"name\": \"my-python\", \"command\": \"python3\", \"pid\": 12345, \"is_alive\": true }]\n```\n\nSafe to auto-approve.\n\n### `close_session` — Kill a session\n\n```json\n{ \"session_id\": \"a1b2c3d4\" }\n→ { \"success\": true }\n```\n\n### `send_control` — Send control characters\n\n```json\n{ \"session_id\": \"a1b2c3d4\", \"control\": \"ctrl+c\" }\n→ { \"output\": \"^C\\n>>>\" }\n```\n\nSupported: `ctrl+c`, `ctrl+d`, `ctrl+z`, `ctrl+l`, `ctrl+r`, `tab`, `escape`, `up`, `down`, `left`, `right`, `enter`, `backspace`, `delete`, `home`, `end`, and more.\n\n### `confirm_dangerous_command` — Two-step safety confirmation\n\n```json\n{ \"session_id\": \"a1b2c3d4\", \"input\": \"rm -rf /tmp/old\", \"justification\": \"Cleaning up stale temp files from failed build\" }\n→ { \"output\": \"...\", \"is_complete\": true, \"is_alive\": true }\n```\n\nRequired when `send_command` detects a dangerous pattern. The agent must explain why the command is necessary. This is a **separate tool** — even if `send_command` is auto-approved, this requires its own permission.\n\n## How It Works\n\n### Two Terminal Modes\n\n**PTY mode** (default) — uses `node-pty` + `@xterm/headless` (the same terminal emulator as VS Code):\n\n- Clean output — the AI sees exactly what a human would see on screen\n- Cursor positioning, progress bars, `\\r` overwrites all render correctly\n- Full keyboard: arrow keys, tab completion, ctrl+c/d/z, home/end\n- Terminal resize, TUI apps (vim, htop, top), 256-color, 1000-line scrollback\n\n**Pipe mode** (automatic fallback) — activates when node-pty can't load (e.g., in sandboxed environments):\n\n- Interactive sessions still work via `child_process.spawn` with auto-injected flags (`python -u -i`, `bash -i`, etc.)\n- ANSI codes stripped, control keys still work\n- No terminal emulation, but covers the basics\n\nThe mode is selected automatically — PTY is tried first, pipe mode kicks in if it fails.\n\n### What the AI sees: PTY vs Pipe\n\n| Scenario | PTY mode | Pipe mode |\n|----------|----------|-----------|\n| `printf \"\\rProgress: 3/3\"` | `Progress: 3/3` | `Progress: 1/3Progress: 2/3Progress: 3/3` |\n| ANSI colors | Stripped cleanly | Stripped via regex |\n| vim, htop, top | Readable screen | Garbled |\n| Arrow keys, tab completion | Works | Works |\n| Terminal resize | Works | No-op |\n\n### Smart \"Command Done\" Detection\n\nInstead of blindly waiting a fixed time, the server uses a layered strategy:\n\n1. **Process exit** — if the process died, command is done\n2. **Prompt detection** — auto-detects the session's prompt at startup (bash `$`, python `>>>`, psql `#`, etc.), watches for it to reappear\n3. **Output settling** — no new output for 300ms = probably done\n4. **Timeout** — always returns after `timeout_ms` with `is_complete: false`\n\n## Security\n\nSeven-layer defense-in-depth:\n\n| Layer | What It Does | Default |\n|-------|-------------|---------|\n| MCP Tool Annotations | `readOnlyHint`/`destructiveHint` on each tool | Always on |\n| Confirmation Flow | Dangerous patterns require `confirm_dangerous_command` | Always on |\n| Input Pattern Detection | Detect rm -rf, DROP TABLE, curl\\|bash, etc. | Always on |\n| Command Blocklist/Allowlist | Block/allow specific commands | Configurable |\n| OS-Level Sandbox | Kernel-level process sandboxing via `@anthropic-ai/sandbox-runtime` | Off (opt-in) |\n| Secret Redaction | Redact AWS keys, tokens, private keys in output | Off (opt-in) |\n| Resource Limits | Max sessions, output cap, idle timeout, audit logging | Always on |\n\n### Recommended Permissions\n\nOnly auto-approve the read-only tools:\n\n```json\n{\n  \"permissions\": {\n    \"allow\": [\n      \"mcp__terminal__list_sessions\",\n      \"mcp__terminal__read_output\"\n    ]\n  }\n}\n```\n\nThis way `send_command`, `create_session`, and especially `confirm_dangerous_command` always require human approval.\n\n## Configuration\n\nAll settings via environment variables. Pass them in your MCP config:\n\n```json\n{\n  \"mcpServers\": {\n    \"terminal\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-interactive-terminal\"],\n      \"env\": {\n        \"MCP_TERMINAL_ALLOWED_COMMANDS\": \"bash,python3,node,psql\",\n        \"MCP_TERMINAL_REDACT_SECRETS\": \"true\",\n        \"MCP_TERMINAL_IDLE_TIMEOUT\": \"300000\"\n      }\n    }\n  }\n}\n```\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `MCP_TERMINAL_MAX_SESSIONS` | `10` | Max concurrent sessions |\n| `MCP_TERMINAL_MAX_OUTPUT` | `20000` | Max output chars per read |\n| `MCP_TERMINAL_DEFAULT_TIMEOUT` | `5000` | Default wait timeout (ms) |\n| `MCP_TERMINAL_BLOCKED_COMMANDS` | — | Comma-separated blocklist |\n| `MCP_TERMINAL_ALLOWED_COMMANDS` | — | Comma-separated allowlist (if set, only these are allowed) |\n| `MCP_TERMINAL_ALLOWED_PATHS` | — | Comma-separated paths sessions can access |\n| `MCP_TERMINAL_REDACT_SECRETS` | `false` | Redact AWS keys, tokens, private keys in output |\n| `MCP_TERMINAL_LOG_INPUTS` | `false` | Log all inputs to stderr (for debugging) |\n| `MCP_TERMINAL_IDLE_TIMEOUT` | `1800000` | Auto-close idle sessions (ms, default 30min, 0 = disabled) |\n| `MCP_TERMINAL_DANGER_DETECTION` | `true` | Enable dangerous command confirmation flow |\n| `MCP_TERMINAL_AUDIT_LOG` | — | Path to JSON audit log file |\n| `MCP_TERMINAL_SANDBOX` | `false` | Enable OS-level kernel sandboxing |\n| `MCP_TERMINAL_SANDBOX_ALLOW_WRITE` | `/tmp` | Writable paths in sandbox mode |\n| `MCP_TERMINAL_SANDBOX_ALLOW_NETWORK` | `*` | Allowed network domains in sandbox |\n\n## Troubleshooting\n\n### \"Tools not showing up\" / Server fails silently\n\nMCP servers that fail to start often show no error in the client. Check:\n\n```bash\n# Test the server directly:\nnpx -y mcp-interactive-terminal\n\n# You should see \"[mcp-terminal] Starting MCP Interactive Terminal Server\" on stderr.\n# If you see an error, that's what's failing.\n```\n\n### Node.js version too old\n\nThe server requires Node.js >= 18. If you see errors about unsupported syntax or missing APIs:\n\n```bash\nnode --version  # Must be >= 18\n\n# If using nvm:\nnvm install 18 && nvm use 18\n\n# If using volta:\nvolta install node@18\n```\n\n**For nvm/volta/fnm users**: `npx` may use a different Node version than your shell. Use an absolute path:\n\n```json\n{\n  \"mcpServers\": {\n    \"terminal\": {\n      \"command\": \"/Users/you/.nvm/versions/node/v22.0.0/bin/npx\",\n      \"args\": [\"-y\", \"mcp-interactive-terminal\"]\n    }\n  }\n}\n```\n\nFind your path with: `which npx`\n\n### node-pty compilation errors\n\n`node-pty` is a native module that requires build tools. If it fails to compile, the server automatically falls back to **pipe mode** — interactive sessions still work, just without terminal emulation.\n\nIf you want full PTY support:\n\n```bash\n# macOS:\nxcode-select --install\n\n# Ubuntu/Debian:\nsudo apt-get install -y make python3 build-essential\n\n# RHEL/Fedora:\nsudo yum install -y make python3 gcc gcc-c++\n```\n\n### Session dies immediately\n\nSome commands need to be run inside a shell rather than directly:\n\n```\n# Instead of:  create_session({ command: \"rails console -e staging\" })\n# Do this:     create_session({ command: \"bash\" })\n#              send_command({ input: \"rails console -e staging\" })\n```\n\nThis is because `create_session` runs the command directly (like `exec`), not through a shell. Spawning `bash` first gives you a full shell environment.\n\n### Output looks garbled\n\nIf output contains escape codes or looks wrong, you're likely in **pipe mode** (node-pty failed to load). Check the server logs for `\"falling back to pipe mode\"`. Install build tools (see above) to enable PTY mode.\n\n### Timeout too short for long-running commands\n\nIncrease the timeout per-command:\n\n```json\n{ \"session_id\": \"...\", \"input\": \"bundle install\", \"timeout_ms\": 60000 }\n```\n\nOr globally via environment variable:\n\n```json\n{ \"env\": { \"MCP_TERMINAL_DEFAULT_TIMEOUT\": \"30000\" } }\n```\n\n## Comparison with Alternatives\n\n| Feature | mcp-interactive-terminal | App-specific terminal servers | Generic shell MCP servers |\n|---------|------------------------|-------------------------------|--------------------------|\n| Cross-platform | Yes | Often single-app only | Varies |\n| Clean output (xterm-headless) | Yes | No (screen scrape) | No (raw PTY dump) |\n| Smart completion detection | 4-layer algorithm | No | Basic timeout |\n| Security layers | 7 (confirmation flow, sandbox, redaction, etc.) | None | Basic |\n| Dangerous command confirmation | Yes (separate tool) | No | No |\n| MCP tool annotations | Yes | No | No |\n| Background sessions | Yes | No (uses active tab) | Yes |\n| Focused API | 7 tools | 2-3 tools | 15-20+ tools (scope creep) |\n| Install | `npx -y` (zero-config) | Requires specific app | Varies |\n\n## Development\n\n```bash\ngit clone https://github.com/amol21p/mcp-interactive-terminal.git\ncd mcp-interactive-terminal\nnpm install\nnpm run build\nnpm test\n```\n\nTest with MCP Inspector:\n\n```bash\nnpx @modelcontextprotocol/inspector dist/index.js\n```\n\n## License\n\nMIT\n",
  "bytes": 13840,
  "sha": "e67cc286124282bb7d4abb975d1d83682df587f8fa91c32cfff29f1d54cf8d12",
  "repo_slug": "amol21p/mcp-interactive-terminal",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_amol21p_interactive_terminal_f1a356fc/readme"
}