mcpField
T
Terminal sessions for agents

Terminal sessions for agents

本地服务
github.com/ryamgoh其他0今天更新

关于 Terminal sessions for agents

为 Agent 提供真实终端会话:运行命令、流式输出、向程序输入内容、终止进程树。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"ryamgoh-terminal": {
"command": "npx",
"args": [
"-y",
"@ryamgoh/terminal-mcp"
]
}
}
}
启动命令npx -y @ryamgoh/terminal-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@ryamgoh/terminal-mcp0.1.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

README 原文English

来自项目 README

README 暂无中文译文,以下为英文原文;中文介绍见上方。

terminal-mcp

An MCP server that gives agents real terminals. A client can start shells or programs in a pseudo-terminal, run commands and get back exactly their output and exit code, keep reading output of long-running processes by cursor, type into interactive programs (REPLs, prompts, vim), see whether a session is busy, idle, waiting for input or exited, and terminate a session with its whole process tree.

It works with any MCP client. Local clients launch it over stdio; remote or hosted clients (such as Manus) connect over Streamable HTTP with a bearer token. It serves both the 2025-era protocol and the 2026-07-28 revision.

Demo: an MCP client starts a shell, runs commands, reads a long job by cursor, answers a prompt, drives a Python REPL and a web server, then kills every session

This recording is npm run demo -- --npx: a scripted MCP client making the same tool calls an agent would, against the published npm package. Every response shown is the server's real answer. Replay it in your terminal with npm run demo, or play docs/demo.cast with asciinema play. For a real agent, see Manus controlling terminals through terminal-mcp, the transcript of a Manus task using the server as a custom MCP connector.

Status

Version 0.1.0 meets all 8 of 8 requirements in the original brief, and 24 of the 45 features in the full product plan are done (53%), with 2 more partly done. Next up: 0.1.1 fixes two small known defects, then 0.2 lets Manus control terminals on your own Mac. ROADMAP.md has the build timeline, the feature-by-feature table and the release plan.

AreaDonePartialPlanned
Core (sessions, PTY, shell tracking, waits, tools)800
Remote access and clients511
Agent ergonomics615
Safety106
Packaging403
Extras004

Install from npm

No clone or build needed; the client starts the server with npx:

claude mcp add terminal -- npx -y @ryamgoh/terminal-mcp          # Claude Code
{ "mcpServers": { "terminal": { "command": "npx", "args": ["-y", "@ryamgoh/terminal-mcp"] } } }

The JSON form works for Cursor (~/.cursor/mcp.json), Claude Desktop and most other clients. Add server flags after the package name, for example ["-y", "@ryamgoh/terminal-mcp", "--max-sessions", "8"]. In Manus, a command-based custom MCP connector with npx -y @ryamgoh/terminal-mcp gives the agent terminals in its own cloud sandbox; to give it terminals on your machine, use HTTP mode (below). The server is also listed in the MCP Registry as io.github.ryamgoh/terminal-mcp.

Quick start (from source)

npm install
npm run build
npm test            # 91 end-to-end tests against the built server (bash + zsh, stdio + HTTP)
npm run smoke       # narrated 11-step check of one real session, as a local MCP client sees it
npm run demo        # the narrated demo recorded above (add `-- --npx` to run the published package)

Requirements: Node.js 22.12+ (CI tests 22 and 24), macOS or Linux, bash or zsh. node-pty ships prebuilt binaries for macOS; on Linux it compiles during install (needs python3, make, a C++ compiler). On macOS, install (and server start) restores the execute bit that node-pty 1.1.0 omits on its prebuilt spawn-helper (node-pty#850); without it every spawn fails with posix_spawnp failed.

On a Mac? MACOS.md walks through install, tests, the Inspector, connecting Claude Code, Cursor and Claude Desktop, HTTP mode and Manus, step by step.

Releasing? PUBLISHING.md covers the first release to npm and the MCP Registry, and the tag-driven releases after it.

Connect a client

Claude Code

claude mcp add terminal -- node /absolute/path/to/terminal-mcp/dist/cli.js

Cursor, Claude Desktop and other JSON-configured clients (~/.cursor/mcp.json, claude_desktop_config.json, ...)

{
  "mcpServers": {
    "terminal": { "command": "node", "args": ["/absolute/path/to/terminal-mcp/dist/cli.js"] }
  }
}

Desktop apps on macOS do not load your shell's PATH; if node comes from nvm, fnm or Homebrew and the server does not start, use the absolute path from which node as command.

MCP Inspector (interactive testing)

npm run inspect     # same as: npx @modelcontextprotocol/inspector node dist/cli.js

Manus or any remote client (HTTP). A hosted client cannot start a process on your machine, so run the server in HTTP mode and expose it with a tunnel:

node dist/cli.js --http --port 8765 --allowed-host your-name.ngrok-free.dev
# prints where the generated bearer token is stored (~/.terminal-mcp/token), or pass --token / TERMINAL_MCP_TOKEN
ngrok http 8765 --url your-name.ngrok-free.dev

In Manus, add a custom MCP connector with the HTTPS URL https://your-name.ngrok-free.dev/mcp and the header Authorization: Bearer <token>. If a client can only take a URL (no headers), start the server with --url-token and use https://your-name.ngrok-free.dev/mcp/<token>. The server answers in plain JSON (no SSE streams), so it also works through tunnels that do not support streaming, such as Cloudflare quick tunnels. A 403 means the tunnel's hostname is missing from --allowed-host.

Manus can also launch the server itself in its cloud sandbox through a command-based connector (node .../dist/cli.js). The terminals then belong to that sandbox, not to your computer.

Tools

ToolWhat it does
terminal_startStart a session. Without command: your login shell (zsh/bash) with command tracking. With command + args: any program in a PTY (python, vim, ssh, a dev server). Returns session_id, state and the first screen.
terminal_execRun one command line in a shell session and wait (default 20 s) for it to finish. Returns only that command's output, exit_code and the new cwd. If it is still running at the timeout it keeps running and you get completed: false plus a cursor.
terminal_writeType text (input) and/or named keys (enter, ctrl+c, up, escape, f1...). Waits until output settles or until matches and returns the new output. paste: true sends multi-line text as a bracketed paste.
terminal_readRead without sending input. cursor returns only newer output and a next_cursor; wait_for can block for output, command_end (returns the finished command's clean output and exit code) or exit; until waits for a regex; view: "screen" returns the rendered screen for full-screen programs.
terminal_listAll sessions with state, exit code, busy/idle, current command, cwd and cursor.
terminal_killTerminate a session and its whole process tree (SIGHUP, then SIGKILL after escalate_after_ms).

Every response includes the session's state: state (running/exited), exit_code, shell_state (idle/busy), current_command, cwd, cursor, and awaiting_input with input_kind (password when the program turned terminal echo off, prompt when the cursor sits after prompt-like text). Errors explain what to do next, for example how to interrupt a busy shell. Results carry both structuredContent and a text block with the output as plain text.

Typical agent loops:

terminal_start {}                                        -> session_id, shell_state: idle
terminal_exec  {session_id, command: "npm test"}         -> exit_code 1, output: failing test
terminal_exec  {session_id, command: "npm run dev", timeout_ms: 3000}
                                                         -> completed: false, cursor: 18233
terminal_read  {session_id, cursor: 18233, until: "ready on"}   -> matched, next_cursor
terminal_write {session_id, keys: ["ctrl+c"]}            -> dev server stopped, exit 130

What does the work (libraries, not custom code)

The server is a thin, tested layer of glue (about 1,500 lines of TypeScript) over existing libraries and standards.

ConcernProvided by
MCP protocol, both protocol eras, stdio and Streamable HTTP@modelcontextprotocol/server (serveStdio, createMcpHandler), @modelcontextprotocol/node
HTTP app, Host/Origin validation (DNS-rebinding protection), bearer auth with WWW-Authenticate@modelcontextprotocol/express (createMcpExpressApp, requireBearerAuth) on Express 5
Pseudo-terminals, resize, signalsnode-pty (Microsoft, used by VS Code)
Terminal emulation: rendering \r progress bars, cursor movement, colours, the visible screen, alternate screen, scrollback markers, bracketed-paste and cursor-key modes@xterm/headless (xterm.js)
Command start/end, exit codes, command line, cwdVS Code's shell-integration scripts (vendored unmodified, MIT) emitting OSC 633 marks, parsed by xterm's registerOscHandler; bash loads them through a 13-line wrapper (shell-integration/terminal-mcp-bash.sh) that also turns history off
Multi-line commandsBracketed paste, detected with xterm's modes and a registerCsiHandler hook; bash without it (macOS's /bin/bash 3.2) gets the lines as one eval $'…' line
Key names to escape sequencesSPECIAL_KEYS table from pty-manager (vendored, MIT); application-cursor mode from xterm
Password-prompt detectionthe OS's own stty (echo off + canonical mode is what getpass, sudo and ssh set)
Killing the whole process treetree-kill
Input validation and JSON Schema for toolszod 4
Audit log and diagnosticspino (JSONL to ~/.terminal-mcp/audit.jsonl, diagnostics to stderr)
CLIcommander

What is ours: the session model (state machine and waits), the output journal with absolute cursors and loss reporting, tool contracts and error messages, and lifecycle and limits.

Security model

The server runs commands as your user, with your permissions; treat any connected client as having a shell on your machine.

Over stdio, the client that launched the server is the only party that can talk to it. Over HTTP, the server binds to 127.0.0.1 by default and requires a bearer token (constant-time comparison), validates Host (DNS-rebinding protection) and rejects foreign browser Origins. It refuses --no-auth on non-loopback addresses. Child processes do not inherit TERMINAL_MCP_* variables, so the token never reaches the shell.

Agent commands are kept out of your shell history by default (bash: history is off in agent shells; zsh: HIST_IGNORE_SPACE with a leading space; --keep-history to change). Every tool call is appended to the audit log (inputs truncated at 2,000 characters). Limits: 16 running sessions, 2 MB of retained output per session, 10,000 lines of scrollback, a 60 s cap on any blocking wait, and sessions untouched for 60 minutes are killed (--max-sessions, --max-wait, --idle-timeout). When the stdio client disconnects or the server receives SIGINT/SIGTERM/SIGHUP, every session and its children are terminated.

Options

--http                     serve Streamable HTTP instead of stdio
--host <addr>              HTTP bind address (default 127.0.0.1)
--port <n>                 HTTP port (default 8765; 0 = pick a free port)
--allowed-host <name...>   extra Host header names to accept (your tunnel hostname)
--allowed-origin <name...> Origin hostnames to accept from browser-based clients
--allow-any-host           accept any Host header (token still required)
--token <token>            bearer token (or TERMINAL_MCP_TOKEN; default: generated, saved to ~/.terminal-mcp/token)
--url-token                also accept the token as a secret path /mcp/<token>
--no-auth                  disable auth (loopback binds only)
--max-sessions <n>         maximum running sessions (default 16)
--idle-timeout <minutes>   kill sessions untouched this long; 0 disables (default 60)
--max-wait <seconds>       cap on any blocking wait in a tool call (default 60)
--audit-log <file>         audit log path (default ~/.terminal-mcp/audit.jsonl)
--no-audit                 disable the audit log
--keep-history             let agent commands into your shell history

Testing

npm test builds the server and runs the end-to-end suite with the official MCP client against the real binary: the shell scenarios run four times (stdio with a 2025-era client and HTTP with a 2026-07-28 client, each on bash and zsh), plus programs (python REPL, vim), screen rendering, output floods, paging, ten concurrent sessions, limits, disconnect cleanup and HTTP security. npm run smoke drives one session through the main features and prints each step. npm run inspect opens the MCP Inspector UI on the server. To test with macOS's own /bin/bash 3.2 when a newer Homebrew bash comes first on PATH, see MACOS.md. npx tsx test/bench.ts prints exec latency and wait-budget overruns; npx tsx test/remote-check.ts <url> <token> drives a deployed server through a public URL. CI runs on Linux and macOS (.github/workflows/ci.yml).

Known limitations

Windows is not supported yet (node-pty supports ConPTY; the shell integration for PowerShell is vendored but not wired up). Shells other than bash and zsh fall back to bash. Sessions live in the server process and do not survive a restart. Commands that replace the shell (exec), or shells whose startup files disable VS Code's integration, lose command tracking; terminal_write and terminal_read still work. If a shell asks a question while it starts (for example zsh's compinit "insecure directories" check, or a prompt in ~/.zshrc), terminal_start returns awaiting_input: true with the question in hint; answering it with terminal_write lets the shell finish starting, and command tracking begins at its first prompt.

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。