termcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@termcpssh into my staging server and run htop"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Introduction
termcp is not only an MCP that lets AI act like a human at the terminal — typing into running processes, answering prompts, driving TUIs and REPLs across conversation turns. More than that, it is a cross-platform terminal management platform written in Go. It treats the terminal session as its unifying primitive and connects two classes of machines: the termcp host itself (built-in loopback profile, zero config) and any remote host (SSH profiles with password / key / jump-host support). Every session is a real PTY channel — hosting multiple shell tabs, port forwards, and SFTP file transfer — opened simultaneously to every kind of user:
You (human) — a browser-based Web UI for live observation and instant takeover of any session;
AI Agents — drive the same real terminals through MCP or through SKILLS: the instance ships an installable skill (
/skills.md) that drives it with plaincurl,termcp://locators included;Scripts / programs — a full REST API plus WebSocket channel for programmatic session, forward, and file operations.
As an MCP, termcp gives AI a human's hands on a real terminal; as a platform, MCP is just one of its interface layers — the instance also ships an installable Agent Skill (/skills.md) that drives the identical session layer over plain curl. The platform itself is a complete terminal service — suspendable/archivable sessions, parallel multi-session orchestration, a closed-loop SSH connection lifecycle — with a browser terminal, history replay, and a human-in-the-loop control model, forming an observable, programmable, human-and-AI handoff terminal platform.
Written in Go, it ships as a single lightweight binary that runs persistently with low overhead; compiled Go and goroutine concurrency keep it high-throughput and low-latency.
Demo Video
https://github.com/user-attachments/assets/d06a3c36-250a-4eeb-aefa-e80d13d1551c
Related MCP server: mcp-interactive-terminal
Why termcp
One platform, four entrances, one session layer
Entrance | For | Form |
Web UI | Humans | Browser live terminals, session dashboard, tabs, history replay, file/forward panels |
MCP server | AI Agents | Sessions as persistent connections; Agents manage/drive interactive programs across turns |
SKILLS ( | AI Agents | One-file install; drives termcp with |
REST API + WebSocket | Scripts | Programmatic session creation, terminal I/O, port forwarding, SFTP file operations |
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 — through MCP or through the instance's own Agent Skill over plain curl.
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
⚡ One-command install —
go install github.com/open-mcp-ai/termcp@latest; just a Go toolchain.🔌 One port, four entrances — Web UI (humans), MCP / SKILLS (Agents), and REST + WebSocket (scripts) share one port.
🤝 Human–AI relay — You and the Agent share one live session and you can take over or interrupt at any time; the Agent pauses at
sudo/ password / MFA prompts for you to type in the Web UI; input is serialized so keystrokes never collide.🟦 Multi-turn interaction on a real terminal — The process keeps running, so an Agent drives TUIs, REPLs, GDB, msfconsole, or vim across conversation turns; a full PTY (ConPTY on Windows) behaves the same on every platform.
🟫 Local or remote, one workflow — Zero-config access to the termcp host (
ssh_config="internal") or any remote machine over SSH profiles; commands, file transfer (SFTP plus resumable HTTP URLs), and port forwarding (-L/-R/-D) all run over that single connection.🟧 Built-in visual management — Browser live terminals, session dashboard, tabbed shells, tiling workspace, history replay, file and forward panels;
/api.htmlholds the API / MCP / SKILLS cheat sheet.🟨 Multiple Agents, no lost history — Parallel readers of one session keep independent cursors; exited or crashed sessions are archived with their full output, survive restarts, and stay searchable, renamable, taggable, and screenshot-able until explicitly deleted. After a drop, open a fresh session from the same entry (
termcp://<entry>) and carry on.🟥 Proactive notifications, no polling —
shell_notifywakes the Agent on process exit, silence, or new output — signal only, no payload (pull the text when needed);channel="sampling"sendssampling/createMessagedirectly.🔒 Credential-safe by design — Passwords, private keys, and passphrases written through
ssh_configare never readable back, so plaintext never enters the Agent's context; config-writing tools stay off unless--mcp-manage-ssh-configsis set.
Quick Start
Quick Install (Go toolchain required)
The fastest way to install — one command, no clone, no build:
go install github.com/open-mcp-ai/termcp@latestgo install resolves the module through the Go proxy (use GOPROXY=https://goproxy.cn,direct in mainland China) and drops the termcp binary into $(go env GOPATH)/bin — make sure that directory is on your PATH. termcp is written in Go, so install is go install or a prebuilt Release binary: there is no npx/uvx variant, and it needs no Node or Python runtime. Being a Go module, it also supports source-level integration: go get github.com/open-mcp-ai/termcp to bring it in as a dependency, or fork and build a customized binary from source. Then run:
termcpDownload
Head to the Releases page and download the pre-built binary for your platform:
Platform | File |
Linux (x86_64) | |
Linux (ARM64) | |
macOS (Intel) | |
macOS (Apple Silicon) | |
Windows (x86_64) | |
Windows (ARM64) |
Build
# Clone
git clone https://github.com/open-mcp-ai/termcp.git
cd termcp
# Build
go build -o termcp .
# Run (defaults: loopback, port 18765; data goes to ~/.termcp)
./termcpOpen http://127.0.0.1:18765 in your browser to enter the Web UI.
Usage
Command Line
termcp [flags]Flag | Default | Description |
|
| HTTP bind address. |
|
| HTTP port. Shared by the Web UI, MCP SSE, MCP streamable HTTP, and the docs/skill endpoints ( |
|
| Persistence directory (sessions, messages, SSH configs). Auto-created. Default overridable via |
|
| Log level: |
|
| Disable the built-in loopback SSH profile. |
|
| Enable MCP tools to create/edit/delete SSH configs (secrets are never exposed). |
| (unset) | Static token for HTTP authentication (or |
| (unset) | Salted SHA-256 hash of the token ( |
| (action) | Generate the salted SHA-256 hash of a token for |
These flags are your capability gates: --no-internal narrows Agents to remote hosts only, and --mcp-manage-ssh-configs is what opens SSH-config write access. Tighten or loosen what Agents can touch per scenario. See Authentication below.
Examples
# Listen on all interfaces
./termcp --host 0.0.0.0 --auth-token "your-long-random-token"
# Listen on all interfaces with only a salted hash stored server-side
./termcp --host 0.0.0.0 --auth-hash "$(./termcp --gen-auth-hash)"
# Allow AI agents to manage SSH configs
./termcp --mcp-manage-ssh-configs
# Disable the built-in loopback profile (agents may only reach remote hosts)
./termcp --no-internalAuthentication
A single static token protects the whole HTTP surface — the Web UI, REST API, MCP SSE, MCP streamable HTTP, and the browser WebSocket. (The read-only docs /api.md and /skills.md stay public, so an agent can fetch them before it has a token.) Configuring it is optional for loopback-only binds (127.0.0.1 keeps its no-setup default); exposing a non-loopback bind without a token is a startup error.
# Plaintext: flag or env var
./termcp --auth-token "your-long-random-token"
TERMCP_AUTH_TOKEN="your-long-random-token" ./termcp
# Hashed (recommended): the server keeps only sha256-<salt>-<digest>.
# `termcp --gen-auth-hash` reads the token from stdin without echo on a terminal,
# so it never lands in shell history:
./termcp --gen-auth-hash
TERMCP_AUTH_HASH='sha256-...' ./termcpHow each client presents the token:
Client | Credential |
API / MCP / curl |
|
Browser (Web UI) | Native login prompt on |
Behavior notes:
--auth-tokenand--auth-hashare mutually exclusive; a flag value overrides the environment variable of the same setting.A colon inside the token is fine: the server also accepts the whole decoded
user:passstring when it equals the token, so clients that split at the first colon (e.g.curl -u user:pass) still authenticate.curl -u :<token>remains the canonical form.Without a token or hash, startup fails on any non-loopback host (
0.0.0.0, a LAN IP, or a hostname other thanlocalhost), so an accidentally exposed instance can never run unauthenticated.Browsers use HTTP Basic, which is Base64, not encryption. When serving termcp beyond your own machine, terminate TLS in a reverse proxy in front of it — the
termcp_tokencookie then gets theSecureflag automatically only when the request arrived over TLS.
Connecting to Remote Hosts
Zero setup: ssh_config="internal" drives the termcp host itself. To reach a remote machine, create an SSH profile — in the Web UI's new-connection dialog (it ships a TOML template and a Test connection button), or via the REST API PUT /api/connections/<name> with a TOML body:
kind = "remote"
host = "192.168.1.100"
user = "pi"
trust_unknown_host = true # first connect to an unknown host
# EITHER a password:
password = "..."
# OR the private key's PEM content itself — a path like "~/.ssh/id_ed25519" will NOT work:
private_key = """-----BEGIN OPENSSH PRIVATE KEY-----
<paste the full content of ~/.ssh/id_ed25519>
-----END OPENSSH PRIVATE KEY-----"""
key_passphrase = "..." # only if the key is passphrase-protected
# Optional bastion (ProxyJump) hop:
[jump]
host = "bastion.example.com"
user = "ops"
password = "..."Profiles live in data-dir/ssh_configs/<name>/config.toml; list them with ssh_config(action=list). Credentials written this way are never readable back. Agents can create profiles too, but only when termcp was started with --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 installdownloads termcp and its dependencies through the Go module proxy.GOPROXYdefaults togoproxy.cnand 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
Containers must bind to 0.0.0.0, and a non-loopback bind requires authentication — pass the token (or its hash) via TERMCP_AUTH_TOKEN / TERMCP_AUTH_HASH or the matching flags, or startup fails.
# 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
# Persist the data directory as a volume; authenticate with a token via env
docker run -d --name my-app-termcp \
-p 18765:18765 \
-v termcp-data:/data \
-e TERMCP_AUTH_TOKEN=change-me-to-a-long-random-secret \
--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 \
-e TERMCP_AUTH_TOKEN=change-me-to-a-long-random-secret \
--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-termcpIf the original application must run in the same container, start termcp from the existing entrypoint or process manager:
export TERMCP_AUTH_TOKEN="change-me-to-a-long-random-secret"
/usr/local/bin/termcp --host 0.0.0.0 --port 18765 --data-dir /dataA 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"]
environment:
- TERMCP_AUTH_TOKEN=change-me-to-a-long-random-secret
ports:
- "18765:18765"
volumes:
- termcp-data:/data
volumes:
termcp-data:docker compose up -d --buildConnecting AI Clients (MCP)
termcp speaks both MCP transports on the same port (18765). Choose whichever your client supports — the tool surface is identical.
termcp is a long-running service: the same port serves the Web UI, any number of MCP clients, and session persistence. It therefore offers HTTP transports only — Streamable HTTP and SSE — and does not support stdio (there is no local subprocess mode).
Alternative: the Agent Skill drives the same sessions over plain curl — the instance serves it at /skills.md. The MCP server is one interface layer of the platform, embeddable into any MCP-capable host — Claude Code, Cursor, Codex, Open WebUI, or your own client.
Option A — Streamable HTTP (/stream)
The modern MCP transport; a single endpoint, no separate message path. Use this for Claude Code, Open WebUI, and most current clients.
{
"mcpServers": {
"termcp": {
"type": "http",
"url": "http://your-server:18765/stream"
}
}
}claude mcp add --transport http termcp http://localhost:18765/streamSame machine:
http://127.0.0.1:18765/stream.Open WebUI in 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.
Option B — SSE (/sse)
The legacy transport. Configure only /sse; the SDK posts JSON-RPC to /message automatically.
{
"mcpServers": {
"termcp": {
"type": "sse",
"url": "http://your-server:18765/sse"
}
}
}claude mcp add --transport sse termcp http://localhost:18765/sseCheat sheet
Streamable HTTP →
http://<host>:18765/streamSSE →
http://<host>:18765/sse(JSON-RPC goes toPOST /message)
The Web UI's API / MCP / SKILLS page (/api.html) offers copy-ready config for both transports, plus the Agent-docs and skill-download addresses for this instance.
Agent Skill (curl-only, no MCP)
Don't want to configure an MCP client? The instance ships an installable
Agent Skill that teaches any agent to drive termcp with curl alone —
including the termcp:// locators users paste from the Web UI.
# Public endpoint: no token needed for the download itself
curl -fsS http://<host>:18765/skills.md -o /tmp/termcp-SKILL.md
# Claude Code reads ~/.claude/skills/<name>/SKILL.md
mkdir -p ~/.claude/skills/termcp && cp /tmp/termcp-SKILL.md ~/.claude/skills/termcp/SKILL.md
# Other agents that follow the shared convention read ~/.agents/skills/<name>/SKILL.md
mkdir -p ~/.agents/skills/termcp && cp /tmp/termcp-SKILL.md ~/.agents/skills/termcp/SKILL.mdRestart the agent session after installing (skills are loaded at session start).
Claude Code has no per-skill CLI command — adding is "drop the file in", removing
is rm -rf ~/.claude/skills/termcp (or claude plugin install/uninstall when the
skill ships as a plugin).
Once installed, a request as simple as "open termcp://rock64 and run uname -a"
works end to end: the skill resolves the locator via
GET /api/resolve?url=..., creates the session with that ssh_config, sends the
command, and polls the output. The same skill is registered as the MCP resource
<origin>/skills.md, and /api.html shows the exact install command for the
instance you are looking at.
Connecting Scripts / Programs (REST API)
Skip MCP and use the same session layer programmatically: the full REST API and live WebSocket channel.
# List sessions (same --auth-token protection)
curl -H "Authorization: Bearer $TERMCP_AUTH_TOKEN" http://127.0.0.1:18765/api/sessions
# Create a session
curl -X POST http://127.0.0.1:18765/api/sessions \
-H "Authorization: Bearer $TERMCP_AUTH_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"ssh_config":"internal","command":"bash","mode":"pty"}'
# Read output / upload files / port forwards — see docs/api.mdLive terminal I/O runs over WebSocket /api/ui/ws; files support direct HTTP URLs with Range resume. Full endpoint list in docs/api.md.
With authentication enabled
When the server runs with --auth-token/--auth-hash, every MCP request needs the token as an Authorization: Bearer header:
claude mcp add --transport http termcp http://your-server:18765/stream \
--header "Authorization: Bearer $TERMCP_AUTH_TOKEN"{
"mcpServers": {
"termcp": {
"type": "http",
"url": "http://your-server:18765/stream",
"headers": { "Authorization": "Bearer <your-token>" }
}
}
}Keep the token out of URLs and out of shared configs/screenshots. curl and scripts use the same header:
curl -H "Authorization: Bearer $TERMCP_AUTH_TOKEN" http://your-server:18765/api/sessionsTool Reference
termcp exposes 31 MCP tools. Full parameters, return shapes, and error codes live in docs/mcp-tools.md.
Area | Tools |
Sessions (connection containers) |
|
Shells (terminal channels) |
|
Notifications |
|
SSH profiles |
|
Port forwarding |
|
Files (SFTP) |
|
History & messages |
|
Host discovery |
|
Run a command as shell_input + shell_key(key="enter") + shell_output. Failed tools return isError=true with a JSON body carrying a stable error_code.
Known Limitations
historyscreenshots are ASCII-only.history(action=screenshot)renders the persisted text as a fixed-bitmap terminal image; it is not a pixel-accurate rendering of non-ASCII glyphs.File and forward tools need a live connection. On
exited/archived sessions those tools returnsession_not_running; output reading still works viashell_output.No command allowlisting or directory jail. termcp does not enforce command whitelists, path restrictions, or policy-based risk tiers. Risk control is human-in-the-loop instead: interrupt the Agent from the Web UI at any time, and privileged prompts (
sudo/ password / MFA) are by default handed to you — Agents follow a no-guessing, no-echoing convention and pause for you to type. Whether the Agent may type them anyway is your call; termcp does not forbid it.Basic authentication needs TLS outside localhost. The browser login challenge uses HTTP Basic, whose credentials are only Base64-encoded. Put a TLS-terminating reverse proxy in front of termcp when exposing it beyond a trusted local network; the static token is still never logged or placed in a URL.
This server cannot be deployed
Maintenance
Related MCP Connectors
Remote MCP server for AI.TV creators — delegate account operations to your AI agent over MCP.
Run commands and read/write files on your servers over Termalin's keyless tunnels (hosted MCP).
Real-time chat for AI agents. Claude Code, Cursor, Cline and Codex join channels over MCP.
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Related MCP Servers
- AlicenseAqualityCmaintenanceMCP server for managing interactive processes, enabling AI agents to start, interact with, and terminate long-running programs like SSH sessions, REPLs, and installers via read/write operations.88MIT
- AlicenseAqualityCmaintenanceMCP server that gives AI agents real interactive terminal sessions for running REPLs, SSH, database clients, and any interactive CLI with clean text output and smart completion detection.738 npm18MIT
- AlicenseNot gradedqualityDmaintenanceMCP server that enables AI agents to run fully interactive SSH sessions (via tmux) and execute commands like a human operator, with persistent sessions and multiple concurrent connections.6MIT
- AlicenseBqualityDmaintenanceLocal + remote terminal interaction control MCP Server. Lets AI agents control interactive TUI programs the way a human would.295 npmMIT