terminal-mcp

module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2026 License: MIT

README

terminal-mcp

English | 简体中文

Go Reference MCP Stars

A real PTY terminal for AI agents — with full observability and seamless human takeover.

terminal-mcp is a Model Context Protocol server that gives an LLM agent a real PTY terminal (not a one-shot exec pipe). A human can watch every step the agent takes in real time, take over the exact same session the instant the agent goes down the wrong path, and the agent then resumes with the full context of everything the human just did. Local shells, ssh, containers, gdb, python, top, vim — the agent drives them like a person, and you're never locked out.

One terminal, shared by human and agent. The agent does the driving, you watch live, grab the wheel when it matters, and hand it back — without losing a beat.

Built in Go, single binary, official MCP SDK, Streamable HTTP. Drop it into Cursor, Claude, Comate, or any MCP client.


Why terminal-mcp

Most "run a command" tools hand the model a stateless pipe: one command in, one blob out. It breaks on anything interactive (a login, a REPL, a long-running session), and — worse — it gives the human no way to see what's happening or step in when the agent goes wrong.

terminal-mcp is built around four things:

  • 1. A real PTY, not a pipe. A genuine pseudo-terminal with a persistent session. Interactive and full-screen programs (gdb, python, mysql, top, vim), line editing, colors, prompts, control keys — all work exactly as they do for a human. Not exec one-shots.
  • 2. Full observability — watch the agent live. Every session has a live web terminal URL. Open it and see, in real time, every keystroke and byte the agent produces — the same screen the agent sees. No guessing what your agent did.
  • 3. Instant human takeover — correct course the moment it's wrong. See the agent heading the wrong way? Click take over and type directly into the running PTY. The agent's writes are paused immediately; you fix things by hand — enter a password, run the right command, back it out of a hole.
  • 4. Seamless resume — the agent picks up with full context. When you release control, everything you typed is fed back to the agent as [rc=n] $ command with output, so it continues with complete knowledge of what you just did — no re-explaining, no lost state.

Plus the machinery that makes the above reliable:

  • Precise command boundaries. A sentinel prompt tells the server exactly when a command finished and its exit code — the agent never mistakes "still running" for "done".
  • Survives shell switches. ssh, su, docker exec, entering a container — the sentinel is re-armed automatically so tracking keeps working across hops.
  • LLM-friendly output. ANSI escapes stripped, partial escape sequences held back — the model never gets corrupted bytes; oversized output is spilled and fetched on demand.
  • Local & remote. mode=local runs a shell/command on the host; mode=ssh connects out.
  • Audit & replay. Every tool call logged as JSON (caller IP, user, tool, args, result); every session's raw byte stream saved for replay, with configurable retention.

Quick start

Requires Go 1.25+.

go install github.com/fzxbl/terminal-mcp/cmd/terminal-mcp@latest
terminal-mcp --listen 127.0.0.1:8900

The MCP endpoint is at /mcp; a session's web terminal is at /debug/terminal/<session_id>.

Use it from your AI coding tool

terminal-mcp speaks MCP over Streamable HTTP. Point your client at http://127.0.0.1:8900/mcp.

Generic MCP client config (mcp.json):

{
  "mcpServers": {
    "terminal": { "url": "http://127.0.0.1:8900/mcp" }
  }
}

Then just ask your agent:

"Open a terminal, ssh into staging, tail the service log, and tell me why it's 500ing."

The agent opens a session, runs commands, and streams back results. If it needs a password or you want to intervene, open the returned terminal_url and take over — the agent waits, watches, and resumes.

Human takeover, in 20 seconds

  1. Agent calls terminal_open → gets a terminal_url.
  2. You open it in a browser, click take over.
  3. The session reports held=true; the agent's writes pause.
  4. You type (enter a password, run a risky command, poke around). The agent sees each of your commands reconstructed as [rc=n] $ cmd.
  5. You click release. The agent picks up right where you left off.

Tools

Tool What it does
terminal_open(mode, command?, host?) Start a persistent PTY session. mode=local or mode=ssh. Returns session_id + terminal_url.
terminal_send(session_id, input, wait_ms?) Type a command, wait for it to settle. Returns output, state, exit_code.
terminal_read(session_id, wait_ms?, mode?) Observe output. tail (peek) or since_last (full increment; also the record of human-takeover commands).
terminal_control(session_id, key) Send control keys (ctrl-c, ctrl-d, ctrl-z, …) or recovery actions (flush, hard, rearm).
terminal_status(session_id) Lightweight state / prompt / exit_code / held query.
terminal_close(session_id) Close the session, reclaim the process group.
terminal_list() List active sessions.
terminal_spill_explore(spill_id) Fetch full output that was spilled to disk when a result was too large.

Configure

Copy config.example.toml. Highlights: listen_addr, data_dir, default_shell, ssh_user, ssh_opts, shell_switch_commands (commands that trigger auto re-arm — add your own, e.g. container-enter commands), auto_rearm, transcript_retention_days, log_dir / log_rotate / log_max_age_days.

Customize tool descriptions: use [tool_descriptions] to override the model-facing description per tool (handy when embedding into an external MCP and you want your own wording; missing/empty entries keep the built-in default):

[tool_descriptions]
terminal_open = "Open a persistent terminal session; returns session_id and a read-only web terminal URL."
terminal_send = "Type a command into the session and wait for it to finish; returns new output and status."

Embed it as a library (share one MCP server)

Already run an MCP server and want terminal tools on the same /mcp? go get github.com/fzxbl/terminal-mcp and register onto your own official-SDK server:

mcpserver.Init("config.toml")
mcpserver.SetAdvertiseAddr("10.0.0.5:8080") // host:port used to build terminal_url
mcpserver.SetToolDescriptions(map[string]string{ // optional: reword tool descriptions
    "terminal_open": "Open a persistent terminal session; returns session_id and a web terminal URL.",
})
mcpserver.StartIdleGC(ctx)

mcpserver.RegisterTools(server, auditWriter)          // terminal_* + terminal_spill_explore
mux.Handle("/debug/terminal/", mcpserver.TerminalHandler()) // web terminal (human takeover)

/mcp path is yours to choose; the web terminal prefix /debug/terminal/ is fixed. Tool descriptions can also be overridden via the [tool_descriptions] config table (precedence: SetToolDescriptions > config > built-in default). See docs/EMBEDDING.md for the full public API reference, the shared-/mcp integration pattern, path conventions, authorization notes, and the config reference.

Security

The HTTP service (MCP endpoint + web terminal) is unauthenticated by default. Calling these tools is equivalent to shell access on the host (or over ssh). Bind it to loopback, or put it behind an authenticating reverse proxy, before exposing it beyond a trusted network.

License

MIT. Contributions and stars welcome.

Directories

Path Synopsis
cmd
terminal-mcp command
internal
logging
Package logging 提供按时间(小时/天)切割、按保存周期清理的日志写入器。
Package logging 提供按时间(小时/天)切割、按保存周期清理的日志写入器。
pty

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL