interactive-process-mcp
by UserB1ank
README.md
# interactive-process-mcp
<p align="center">
<strong>Give AI Agents Interactive Terminal Capabilitiesnow has been moved to [termcp](https://github.com/open-mcp-ai/termcp)</strong>
</p>
<p align="center">
<img src="https://img.shields.io/badge/Go-1.21+-00ADD8.svg" alt="Go 1.21+">
<img src="https://img.shields.io/badge/Platform-macOS%20%7C%20Linux-lightgrey" alt="macOS / Linux">
<img src="https://img.shields.io/badge/MCP-SSE_Transport-green.svg" alt="MCP SSE">
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="MIT License">
</p>
<p align="center">
<a href="https://linux.do/"><img src="https://img.shields.io/badge/π§-linux.do-ff69b4.svg" alt="linux.do"></a>
<a href="./README.zh.md"><img src="https://img.shields.io/badge/π-δΈζ-blue.svg" alt="δΈζ"></a>
</p>
<p align="center">
<a href="./README.zh.md">δΈζ</a> | <strong>English</strong>
</p>
---
## Introduction
`interactive-process-mcp` is an MCP (Model Context Protocol) server that enables AI Agents (like Claude Code) to start, control, and manage **long-running interactive processes**.
### Why Do You Need It?
AI Agents can natively only execute one-shot commands β they run and immediately return results. But many real-world scenarios require **multi-turn interaction**:
- SSH into a remote server, enter a password first, then run commands
- Debug code line by line in a Python REPL
- Answer `[Y/n]` prompts in interactive installers
- Use terminal-dependent commands like `top`, `htop`
- Run security tools (e.g., impacket) for multi-step operations
In these scenarios, the process keeps running, and the AI Agent needs to **repeatedly read and write** the process's I/O across **multiple conversation turns**. `interactive-process-mcp` is the bridge designed precisely for this purpose.
### Key Features
| Feature | Description |
|---------|-------------|
| **Multi-agent session sharing** | Multiple AI agents read from the same session simultaneously, each with an independent cursor β no output stealing |
| **PTY and Pipe dual mode** | PTY mode emulates a real terminal; Pipe mode for simple stdin/stdout interaction |
| **Remote deployment** | SSE over HTTP transport β Agent and Server can run on different machines |
| **Multi-session management** | Manage multiple independent processes simultaneously without interference |
| **Message persistence** | Session records and I/O messages persisted to local JSON files |
| **ANSI escape code stripping** | Optional automatic removal of terminal control sequences for clean text output |
| **Blocking reads with timeout** | Agents wait for new output up to a configurable timeout; returns promptly via sync.Cond |
| **Atomic send-and-read** | `send_and_read` combines sending + reading in one step |
| **Graceful termination** | SIGTERM first, then SIGKILL after a configurable grace period |
| **PTY resize** | Dynamically adjust terminal rows and columns at runtime |
| **Session cleanup** | Delete exited sessions to prevent resource accumulation |
---
## Architecture
```
ββββββββ SSE/HTTP ββββββββββββββββ Internal SSH ββββββββββββ
βAgent β ββββββββββ> β Go Server β ββββββββββββββ> β PTY/ β
β(MCP) β β - MCP API β (localhost) β Process β
ββββββββ β - SSH Server β ββββββββββββ
ββββββββββββββββ
β
βΌ
ββββββββββββββββ
β JSON Storage β
β - sessions β
β - messages β
ββββββββββββββββ
```
### Project Structure
```
.
βββ cmd/server/main.go # Entry point
βββ internal/
β βββ config/config.go # Configuration with validation
β βββ mcp/
β β βββ server.go # MCP SSE server & tool registration
β β βββ handlers.go # 13 tool handlers
β βββ sshserver/server.go # Internal SSH server (gliderlabs/ssh)
β βββ sshclient/client.go # Internal SSH client (crypto/ssh)
β βββ session/
β β βββ session.go # Session lifecycle (goroutine-safe)
β β βββ manager.go # Thread-safe session registry
β βββ buffer/buffer.go # Multi-reader ring buffer (1MB per reader)
β βββ storage/store.go # Atomic JSON file persistence
β βββ message/message.go # Message management (per-session mutex)
β βββ ansi/strip.go # ANSI escape code removal
βββ pkg/api/types.go # Public types (Session, Message, SessionMode)
βββ go.mod
βββ go.sum
```
### Key Design Decisions
1. **Multi-Reader Ring Buffer**: Each agent registers as an independent reader with its own `ringbuffer.RingBuffer` instance. Writes broadcast to all readers. Slow readers lose oldest data (overwrite mode) rather than blocking the writer.
2. **Internal SSH Architecture**: The server starts a gliderlabs/SSH server on localhost. Each `start_process` creates an SSH session via crypto/ssh client, leveraging SSH's mature PTY allocation, window resize, signal forwarding, and environment variable passing.
3. **SSE over HTTP Transport**: Unlike traditional stdio-based MCP servers, this server exposes an HTTP endpoint supporting MCP SSE transport. Agents connect remotely, enabling cross-machine deployment.
4. **Atomic JSON Persistence**: Session metadata and I/O messages are stored via temp-file + fsync + rename, preventing half-written files on crash:
- `data/sessions.json` β Session list
- `data/messages/{session_id}/index.json` β Message index
- `data/messages/{session_id}/messages/{msg_id}.json` β Message content
5. **Session Lifecycle Safety**: Exit goroutine is the single authority for `Status`/`ExitCode` (via `sync.Once`). Terminate is idempotent. Stdin writes are serialized via a dedicated mutex.
---
## Examples
### Example 1: SSH Remote Operations
```
AI Agent Flow Process Output
βββββββββββββββββ ββββββββββββββββ
start_process(
command="ssh",
args=["deploy@192.168.1.100"],
mode="pty"
)
β "deploy@192.168.1.100's password: "
send_and_read(
text="my_secret_pass",
press_enter=true
)
β "Welcome to Ubuntu 22.04 LTS
deploy@web-server:~$ "
send_and_read(
text="df -h",
press_enter=true
)
β "Filesystem Size Used Avail Use% Mounted on
/dev/sda1 100G 45G 55G 45% /
deploy@web-server:~$ "
terminate_process(session_id="abc123")
```
### Example 2: Python REPL Debugging
```
start_process(command="python3", mode="pty")
β "Python 3.10.12\n>>> "
send_and_read(text="data = [1, 2, 3, 4, 5]", press_enter=true)
β ">>> "
send_and_read(text="sum(data)", press_enter=true)
β "15\n>>> "
```
### Example 3: Multi-Agent Collaboration
```
# Agent A starts a monitoring process
start_process(command="top", mode="pty")
β session_id: "sess-001"
# Agent B joins the same session without stealing output
register_reader(session_id="sess-001")
β reader_id: 2
# Agent A reads its own cursor
read_output(session_id="sess-001", reader_id=1)
β "PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND..."
# Agent B reads from the beginning independently
read_output(session_id="sess-001", reader_id=2)
β "top - 14:32:10 up 3 days, 2:15, 1 user, load average: 0.52, 0.58, 0.59..."
# Agent B is done
unregister_reader(session_id="sess-001", reader_id=2)
# Agent A terminates the session
terminate_process(session_id="sess-001")
delete_session(session_id="sess-001")
```
### Example 4: Multi-session Parallel Management
```
start_process(command="ping", args=["-c", "5", "google.com"], name="ping-test")
β session_id: "a1b2c3"
start_process(command="python3", args=["-m", "http.server", "8080"], name="web-server")
β session_id: "d4e5f6"
list_sessions()
β [{id: "a1b2c3", status: "running"}, {id: "d4e5f6", status: "running"}]
read_output(session_id="a1b2c3") β ping statistics
terminate_process(session_id="a1b2c3")
terminate_process(session_id="d4e5f6")
```
---
## Tool Reference
### `start_process`
Start an interactive process.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `command` | string | Yes | β | Command to execute |
| `args` | string[] | No | `[]` | Command arguments |
| `mode` | "pty" \| "pipe" | No | `"pty"` | I/O mode |
| `name` | string | No | Auto-generated | Session name |
| `rows` | integer | No | `24` | PTY row count (1β1000) |
| `cols` | integer | No | `80` | PTY column count (1β1000) |
Returns: `{ session_id, pid, initial_output }`
### `send_input`
Send text to a process.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `session_id` | string | Yes | β | Session ID |
| `text` | string | Yes | β | Text to send |
| `press_enter` | boolean | No | `false` | Whether to append a newline |
### `read_output`
Read new output since the last read for the given reader.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `session_id` | string | Yes | β | Session ID |
| `reader_id` | integer | No | `0` | Reader ID (0 = default) |
| `strip_ansi` | boolean | No | `true` | Strip ANSI escape codes |
| `timeout` | number | No | `5` | Wait time in seconds (0.1β60) |
| `max_lines` | integer | No | `0` | Max lines (0 = unlimited) |
Returns: `{ output, has_more, lines_returned, bytes_returned }`
### `send_and_read`
Atomic operation: send input + wait + read output. Parameters are the union of `send_input` and `read_output`.
### `list_sessions`
List all sessions. Returns: `{ sessions: [...] }`
### `get_session_info`
Get session details. Returns: `{ id, name, command, args, mode, status, exit_code, pid, created_at }`
### `terminate_process`
Terminate a process.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `session_id` | string | Yes | β | Session ID |
| `force` | boolean | No | `false` | Use SIGKILL directly |
| `grace_period` | number | No | `5` | Seconds to wait after SIGTERM (0β60) |
### `delete_session`
Remove an exited session from the registry.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `session_id` | string | Yes | β | Session ID |
### `resize_pty`
Resize PTY dimensions (PTY mode only).
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `session_id` | string | Yes | β | Session ID |
| `rows` | integer | No | `24` | Row count |
| `cols` | integer | No | `80` | Column count |
### `register_reader`
Register a new independent reader for a session.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `session_id` | string | Yes | β | Session ID |
Returns: `{ reader_id }`
### `unregister_reader`
Unregister a reader to free resources.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `session_id` | string | Yes | β | Session ID |
| `reader_id` | integer | Yes | β | Reader ID |
### `list_messages`
List the message index for a session.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `session_id` | string | Yes | β | Session ID |
Returns: `{ messages: [{id, type, created_at, byte_size}, ...] }`
### `get_message`
Get the content of one or more messages.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `session_id` | string | Yes | β | Session ID |
| `message_ids` | string[] | No | β | Message IDs to retrieve |
Returns: `{ messages: [{id, session_id, type, content, created_at, byte_size}, ...] }`
---
## Installation
### Build from source
```bash
go build -o server ./cmd/server
```
**Requirements:** Go >= 1.21 / macOS or Linux
### Run
```bash
./server --host 127.0.0.1 --port 8080 --data-dir ./data
```
Options:
| Flag | Default | Description |
|------|---------|-------------|
| `--host` | `127.0.0.1` | HTTP server host |
| `--port` | `8080` | HTTP server port |
| `--data-dir` | `./data` | JSON storage directory |
| `--ssh-host` | `127.0.0.1` | Internal SSH server host |
| `--ssh-port` | `0` (random) | Internal SSH server port |
## Configuration
### Claude Code
In `.claude/settings.json` or `.mcp.json`:
```json
{
"mcpServers": {
"interactive-process": {
"type": "sse",
"url": "http://your-server:8080/sse"
}
}
}
```
Or via CLI:
```bash
claude mcp add --transport sse interactive-process http://localhost:8080/sse
```
### Other MCP Clients
Any MCP client that supports SSE transport can connect to `http://<host>:<port>/sse`.
---
## Community
- [linux.do](https://linux.do/) β Chinese tech community
---
## License
MIT
TDQS
A3.7/5.0
Scored across 8 tools
Disambiguation5/5
Each tool has a distinct and clear purpose: starting, listing, inspecting, sending input, reading output, resizing, and terminating sessions. No overlap or ambiguity.
Naming Consistency5/5
All tool names follow a consistent verb_noun pattern in snake_case, such as start_process, read_output, and terminate_process. The naming is predictable and uniform.
Tool Count5/5
With 8 tools, the set is well-scoped for managing interactive processes. It covers essential operations without being overwhelming or sparse.
Completeness4/5
The tool surface covers core lifecycle operations (start, interact, read, resize, terminate). Minor gaps exist, such as explicit process status checking, but overall it is comprehensive.
Maintenance
ActivityInactive
ResponsivenessResponsive