termcp
Give AI Agents interactive terminal capabilities.
English | 中文
Introduction
termcp is an MCP server written in Go that exposes interactive programs to AI Agents as persistent SSH sessions, letting Agents continuously manage and drive them. On top of that, termcp ships a dedicated session management UI that gives you full visibility into the Agent's behavior. You can also interact directly with the controlled machine — or adjust the Agent's behavior — just as you would over a normal SSH connection.
https://github.com/user-attachments/assets/d06a3c36-250a-4eeb-aefa-e80d13d1551c
Why termcp
Breaking the Boundary
Agents can natively only execute one-shot commands — they run and return. But a huge amount of real-world work is multi-turn interaction, for example:
- SSH into a host: enter a password first, then run commands.
- Debug code line by line in a Python REPL.
- Answer a
[Y/n] prompt buried deep inside an installer.
- Drive terminal-dependent tools like
top, htop, or impacket.
In these scenarios the process keeps running, and the Agent must read and write the process's I/O across multiple conversation turns. Plenty of specialized MCPs have sprung up to handle these — but why not just give the Agent hands so it can interact directly? termcp breaks that boundary for AI Agents: no more writing or installing a separate MCP for every interactive tool. The Agent can directly and continuously manage and drive interactive programs like TUIs, REPLs, GDB, msfconsole, vim, and more.
Visual Management
termcp provides a session management UI that gives you and the Agent a clear view of everything happening inside the processes:
- Multi-session dashboard: every running session lives here, distinguished by name — switch between them or take over at any time.
- Real-time Agent behavior observation: just like a local terminal, watch
htop's live display, vim's editing process, or an installer's colorful prompts right in the browser — no more guessing at a "black box".
- Tab-based management: under a single SSH session you can open multiple operating shells, each rendered as an independent tab in the UI. The Agent can debug in tab A and tail logs in tab B without interference.
- Port forwarding at a glance: every port-forwarding rule tied to a session is listed in the panel — local/remote ports and protocols, all visible at a glance.
- File management: browse directories, upload/download, rename, and create folders directly from the management UI.
- Centralized connection templates: a unified SSH config store. If you'd rather not expose the actual SSH credentials to the Agent, just tell it the name of the SSH config to use.
Quick Navigation
Features
- 🟦 Multi-turn interaction — The process keeps running; the Agent can drive it across multiple conversation turns instead of a one-shot call-and-return.
- 🟪 Real terminal environment — A fully emulated real terminal, so programs that depend on terminal features like
vim, top, gdb all run correctly, with cross-platform compatibility.
- 🟧 Built-in visual UI — Access live terminals, session lists, and output-history replay straight from a browser. Served from a single port, no extra deployment needed.
- 🟨 Multiple Agents, no conflicts — Multiple Agents can read the same session simultaneously, each maintaining its own independent cursor, with no output stealing.
- 🟩 Remote operations, all integrated — Command execution, file transfer, and port forwarding all over a single SSH connection, with no need to re-establish connections.
Quick Start
Download
Head to the Releases page and download the pre-built binary for your platform:
| Platform |
File |
| Linux (x86_64) |
termcp-linux-amd64 |
| Linux (ARM64) |
termcp-linux-arm64 |
| macOS (Intel) |
termcp-darwin-amd64 |
| macOS (Apple Silicon) |
termcp-darwin-arm64 |
| Windows (x86_64) |
termcp-windows-amd64.exe |
| Windows (ARM64) |
termcp-windows-arm64.exe |
Build
# Clone
git clone https://github.com/open-mcp-ai/termcp.git
cd termcp
# Build
go build -o termcp .
# Run (defaults: loopback, port 18765)
./termcp --data-dir ./data
Open http://127.0.0.1:18765 in your browser to enter the Web UI.
Usage
Command Line
termcp [flags]
| Flag |
Default |
Description |
--host |
127.0.0.1 |
HTTP bind address. 0.0.0.0 listens on all interfaces. |
--port |
18765 |
HTTP port. Shared by the Web UI, MCP SSE, and MCP streamable HTTP. |
--data-dir |
./data |
Persistence directory (sessions, messages, SSH configs). Auto-created. |
--log-level |
info |
Log level: debug / info / warn / error. debug shows MCP tool calls. |
--no-internal |
false |
Disable the built-in loopback SSH profile. |
--mcp-manage-ssh-configs |
false |
Enable MCP tools to create/edit/delete SSH configs (secrets are never exposed). |
Examples
# Listen on all interfaces
./termcp --data-dir ./data --host 0.0.0.0
# Allow AI agents to manage SSH configs
./termcp --data-dir ./data --mcp-manage-ssh-configs
Docker Deployment
Multi-stage build: add termcp to any container
Place the following Dockerfile in your application project. The build stage installs termcp with go install, then COPY --from copies the binary into the target image. The target container does not need the Go runtime:
# syntax=docker/dockerfile:1
# Replace this at build time with an accessible Go base image if needed
ARG GO_IMAGE=golang:1.25-alpine
FROM ${GO_IMAGE} AS termcp-build
# Go module proxy; use https://proxy.golang.org,direct outside China if preferred
ARG GOPROXY=https://goproxy.cn,direct
ENV GOPROXY=${GOPROXY}
ENV GOBIN=/out
# Pin latest to a concrete version in production, for example @vX.Y.Z
RUN go install github.com/open-mcp-ai/termcp@latest
# Replace with any target base image
FROM alpine
COPY --from=termcp-build /out/termcp /usr/local/bin/termcp
go install downloads termcp and its dependencies through the Go module proxy. GOPROXY defaults to goproxy.cn and can be replaced with --build-arg GOPROXY=.... If Docker Hub is slow or unavailable, use --build-arg GO_IMAGE=... to select an accessible Go base-image mirror.
Startup command examples
# Build the application image with termcp included
# You can also pass an internal GOPROXY or Go base-image mirror
docker build \
--build-arg GOPROXY=https://goproxy.cn,direct \
-t my-app-with-termcp .
# Run termcp as the container's main process
# Containers must bind to 0.0.0.0; persist the data directory as a volume
docker run -d --name my-app-termcp \
-p 18765:18765 \
-v termcp-data:/data \
--entrypoint /usr/local/bin/termcp \
my-app-with-termcp \
--host 0.0.0.0 --port 18765 --data-dir /data
# Enable MCP tools that write SSH configurations when needed
docker run -d --name my-app-termcp \
-p 18765:18765 -v termcp-data:/data \
--entrypoint /usr/local/bin/termcp \
my-app-with-termcp \
--host 0.0.0.0 --data-dir /data --mcp-manage-ssh-configs
# Follow logs
docker logs -f my-app-termcp
If the original application must run in the same container, start termcp from the existing entrypoint or process manager:
/usr/local/bin/termcp --host 0.0.0.0 --port 18765 --data-dir /data
A container typically runs one foreground process. If the application must remain the main process, run termcp as a separate service on the same Docker network and connect to it at http://termcp:18765/stream.
Docker Compose startup
services:
termcp:
build:
context: .
args:
GOPROXY: https://goproxy.cn,direct
entrypoint: ["/usr/local/bin/termcp"]
command: ["--host", "0.0.0.0", "--port", "18765", "--data-dir", "/data"]
ports:
- "18765:18765"
volumes:
- termcp-data:/data
volumes:
termcp-data:
docker compose up -d --build
Connecting MCP Clients
Claude Code (SSE)
{
"mcpServers": {
"termcp": {
"type": "sse",
"url": "http://your-server:18765/sse"
}
}
}
Or via CLI:
claude mcp add --transport sse termcp http://localhost:18765/sse
Open WebUI (Streamable HTTP)
Point Open WebUI at http://<host>:18765/stream.
- Same machine:
http://127.0.0.1:18765/stream.
- Open WebUI inside Docker, termcp on the host:
http://host.docker.internal:18765/stream (macOS/Windows), or the host's LAN IP.
- Both in Docker on the same network (see Docker Deployment):
http://termcp:18765/stream.
Other MCP Clients
- SSE transport →
http://<host>:<port>/sse
- Streamable HTTP →
http://<host>:<port>/stream