MCP Terminal Controller
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., "@MCP Terminal Controllerstart the approved-job command and show me its output"
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.
MCP Terminal Controller
MCP Terminal Controller 是一个通过 MCP stdio 提供受限、异步 POSIX 进程会话的本地服务器。它使用官方 MCP SDK 2.3.0,要求 Python >= 3.11。客户端只能调用配置所有者(Owner)预先批准的 command_id;不能提交 argv、shell 命令、重定向或命令替换。
这是本地进程控制器,不是沙箱,不提供远程访问、Web/云端 UI,也不能在服务重启后恢复会话。
当前状态
项目版本:
0.1.0。默认 profile 和
demo_process.py启动的都是真实 OS 子进程,不是模拟器或内存假实现;它们仅用于可控的本地演示与测试。2026-10-22 实测:本机全量 83 passed,新目录/新虚拟环境复现 83 passed;标准 MCP 客户端独立完成 16 个场景,安装后的 console entry 也完成真实闭环。完整范围与证据见 ACCEPTANCE_REPORT.md。
Manus 初始连接已实测创建、交互输入、游标续读和终止;加载最终修复后的重连返回 transport closed,原因 UNKNOWN。最终版本以官方标准客户端验收,不声称 Manus 最终重载成功。
Related MCP server: ptywright
工作方式与边界
服务进程只使用标准输入/输出(
stdio)承载 MCP 协议。不得向服务的 stdout 写普通日志或业务文本;入口将日志写入 stderr。terminal_start接收固定 profile 的command_id,由 Owner 本地 JSON 配置映射为固定、真实的argv(其中可执行项argv[0]必须是绝对路径)。服务使用asyncio.create_subprocess_exec(),不启动 shell。每个会话分别连接子进程的
stdin、stdout、stderr。它们是 pipe,不是 PTY(伪终端):没有终端模拟、TTY 行编辑、窗口尺寸、控制序列解释或 job control 语义。交互程序可能因为isatty()为假而表现不同。输出以带
stream: "stdout" | "stderr"标签的记录返回。两个 pipe 的跨流到达顺序由调度决定;请勿假定 stdout 与 stderr 有全局行序。输出 buffer、会话记录和子进程状态都只在内存中保存。服务器重启、崩溃或被强制杀死后没有会话重新连接、历史回放或孤儿进程恢复机制。
安装
在项目根目录选择一种方式安装测试额外依赖:
uv sync --locked --extra test
source .venv/bin/activate或:
python -m pip install '.[test]'上述依赖声明包括 mcp==2.3.0;项目要求 Python >=3.11。仅支持具有 POSIX 进程组的系统;非 POSIX 平台会拒绝配置。
生成 Owner 本地配置
仓库提供 scripts/make_config.py,它调用 Config.defaults(),把 dataclass 字段导出为 JSON。生成内容中的工作目录、允许根目录、Python 可执行文件和演示脚本路径均为本机绝对路径,不含 ~ 或相对路径。
python scripts/make_config.py \
--root /绝对/允许/工作目录 \
--output /绝对/路径/mcp-terminal-controller.json选项:
选项 | 含义 |
| 必填;要写入的本地 Owner JSON 文件。父目录不存在时会创建。 |
| 可选;默认是运行脚本时的当前工作目录( |
该脚本只生成本机的 Owner 配置;它不能、也不会开放客户端任意命令执行。生成的默认 stream、interactive 等 profile 仍然是指向本地 demo_process.py 的固定真实子进程。生产 Owner 应审核并按需要替换为最小权限的固定 profile,而不是把用户输入拼进 argv。
配置格式与校验
启动时传入的 JSON 只能含 Config 的 dataclass 字段;未知字段会被拒绝。所有 allowed_roots 和 default_cwd 必须是存在的绝对目录,实际使用时会解析符号链接,并要求 cwd 位于至少一个允许根内。
{
"allowed_roots": ["/absolute/allowed/root"],
"default_cwd": "/absolute/allowed/root",
"commands": {
"approved-job": {
"argv": ["/absolute/path/to/executable", "--fixed-option"],
"allowed_env": ["SAFE_LABEL"]
}
},
"max_sessions": 8,
"max_records": 32,
"buffer_bytes": 1048576,
"buffer_records": 65536,
"default_timeout_ms": 30000,
"max_timeout_ms": 300000,
"retention_seconds": 300,
"max_input_bytes": 65536
}commands 中的每个 profile 必须有非空、固定的 argv,且 argv[0] 必须是绝对路径。command_id 最长 128 个字符;最多 128 个 profile。参数含义与合法范围如下。
字段 | 默认值 | 合法范围/规则 |
| 无 | 至少一个存在的目录;客户端 |
| 生成时的 | 存在且位于允许根内。 |
| 默认演示 profiles | 字典;每项为固定 |
| 8 | 1–64 个同时未结束会话。 |
| 32 | 1–1024 个保留会话记录;不得小于 |
| 1,048,576 | 4–16,777,216,单会话保留输出的 UTF-8 字节上限。 |
| 65,536 | 1–1,048,576,单会话保留输出记录上限。 |
| 30,000 | 100–3,600,000;不得大于 |
| 300,000 | 100–3,600,000。 |
| 300 | 1–86,400;最终状态会话记录的 TTL。 |
| 65,536 | 1–1,048,576;一次 |
子进程环境从固定的 PATH=/usr/bin:/bin、LANG=C.UTF-8、LC_ALL=C.UTF-8 开始,不会继承服务进程的 os.environ。客户端最多传 32 个环境变量,只有 profile allowed_env 中的名称才可覆写;名称还会拒绝 PYTHON*、LD_*、DYLD_*、PATH、HOME、SHELL、ENV、BASH_ENV、IFS、CDPATH 以及包含 TOKEN、SECRET、PASSWORD、CREDENTIAL、API_KEY、PRIVATE_KEY 的名称。另外拒绝 NODE_OPTIONS、PERL5OPT、RUBYOPT、GCONV_PATH、Java 启动选项等已知运行时注入变量。其他允许名称仍需 Owner 审核业务语义;黑名单不是通用安全保证。
启动与客户端配置
先激活已安装本项目的环境,生成或审核 Owner JSON,然后启动:
python -m mcp_terminal stdio --config /绝对/路径/mcp-terminal-controller.json省略 --config 会使用当前目录作为允许根的安全默认演示 profiles;生产使用建议显式提供 Owner 审核过的配置。stdio 是唯一 transport 参数。
以下是标准 mcpServers 配置形状示例。请用本机的绝对 Python 路径和配置路径替换占位符;示例不会、也不应修改用户现有客户端配置文件。
{
"mcpServers": {
"terminal-controller": {
"command": "/absolute/path/to/python",
"args": [
"-m",
"mcp_terminal",
"stdio",
"--config",
"/absolute/path/to/mcp-terminal-controller.json"
]
}
}
}客户端通过 MCP 的 tools/list 发现工具,并通过协议的 JSON 请求调用它们;不要把交互式 shell 文本写到服务 stdin。若客户端启动器需要环境变量,应由客户端自行管理,不要用它替代 Owner JSON 的命令批准策略。
五个 MCP 工具
所有应用错误均使用 {"ok": false, "error": {"code": "…", "message": "…"}} 的 MCP tool error 返回;原始 OS 异常文本不会返回给客户端。工具 调用入口拒绝未知参数,且整数为严格整数(布尔值和数字字符串不被当作整数接受)。
工具 | 参数(默认值) | 行为 |
|
| 启动 Owner 批准的固定 profile 并立即返回会话快照。没有 |
|
| 从绝对 cursor 非消费式读取输出。无新记录且会话仍运行时,可最多等待 |
|
| 将精确 UTF-8 文本写入运行中的子进程。需要换行时由客户端自行在 |
|
| 查询会话状态、真实退出码/信号、终止原因、输出可用性和 cursors。 |
|
| 幂等地终止该会话进程组:发送 |
启动、状态和终止快照包含 session_id、command_id、process_id、status、exit_code、exit_signal、termination_reason、stdin_closed、input_uncertain、base_cursor、next_cursor、created_at、last_activity_at、output_complete、output_incomplete。terminal_read 返回 records、base_cursor、next_cursor、truncated、has_more,以及当前 status 和输出完成标志。
推荐读取流程
调用
terminal_start,保存返回的session_id,初始读取 cursor 使用0,避免跳过启动期间已生成的输出。调用
terminal_read(session_id, cursor=上次 next_cursor);处理每一条{cursor, stream, text}记录。始终将下一次 cursor 更新为响应的
next_cursor。当has_more=true时立即继续读取;运行中无输出时可使用有限的wait_ms。用
terminal_status或 read 响应的output_complete判断尾部输出是否已完全排空。进程退出并不等于 pipe 尾部已经读取完毕。需要中止时调用
terminal_terminate;最终记录仍会在 TTL 内可读。
Cursor、Unicode 与截断恢复
Cursor 是绝对输出记录序号,不是字节偏移,也不是行号。buffer 将文本拆成 Python Unicode 码点,每个记录都保留 stdout 或 stderr 标签。max_bytes 约束所返回文本的 UTF-8 字节总量,不是 JSON 线长。每页还固定最多返回 1,024 条记录,达到上限时 has_more=true;它不改变 cursor 的计数单位。
buffer 达到 buffer_bytes 或 buffer_records 上限时,会淘汰最旧记录,并将 truncated 设为 true。如果客户端请求的 cursor 小于当前 base_cursor,服务返回 CURSOR_EXPIRED 和可恢复的 base_cursor,而不是静默丢失数据。此时表示已经出现不可见输出缺口;客户端应记录该缺口,将 cursor 移至错误中给出的 base_cursor,再继续读取。cursor 大于 next_cursor 则为 INVALID_CURSOR。
从子进程 pipe 读取时采用增量 UTF-8 解码;无效字节以替换字符表示。输出 reader 被取消、失败或在尾部排空期限内未完成时,output_incomplete=true,此时不要把已收到输出当作完整审计记录。
写入确认与背压
terminal_write 成功的 accepted_bytes 仅代表数据已被控制器接受并完成 pipe drain();它不是目标应用已经读取、解析或处理输入的确认。如需应用级确认,应由固定 profile 的协议通过 stdout/stderr 显式返回。
单次写入受 max_input_bytes 限制。若 drain 在 1 秒内无法完成,服务会关闭该会话 stdin 并返回 INPUT_BACKPRESSURE;此时字节可能已部分送达,不得盲目重试同一输入。进程关闭输入时会返回 STDIN_CLOSED;结束会话写入则为 SESSION_NOT_RUNNING。
写入排队后若请求被取消,已发送字节不能撤回;控制器关闭 stdin,并在状态中设置 input_uncertain=true。同一会话再次写入会被拒绝,客户端不得把取消视为“从未写入”,也不能跨新会话盲目重放。
资源配额、超时与生命周期
整个实例所有保留会话的 max_records × buffer_records 不得超过 2,097,152 条,max_records × buffer_bytes 不得超过 67,108,864 字节;超额配置被拒绝。这限制对象数与文本容量,不是操作系统 RSS/CPU 的硬隔离。默认 32 个保留会话。MCP 输入帧解析前限制为 1 MiB(含换行),实际 text/env 仍受更低的配置或字节限制。
同时运行会话达到
max_sessions时,新的启动返回SESSION_LIMIT。已保留会话(包括最终状态但尚未到 TTL 的会话)达到
max_records时,新的启动返回RECORD_LIMIT;服务不会为腾出空间而静默驱逐仍承诺保留的最终输出。会话到达
timeout_ms后,控制器按超时原因终止它;默认超时和最大可选超时由 Owner 配置决定。完成后,会话输出和状态保存
retention_seconds。TTL 到期后记录被移除,随后查询会得到SESSION_NOT_FOUND。TTL 是最终记录的保留时间,不是进程运行时限。最终状态为
EXITED、TERMINATED或FAILED;运行中可见RUNNING,终止过程中可见TERMINATING。自然退出的原因是natural;用户终止、超时、正常服务关闭分别会标为user、timeout、shutdown。
进程组清理与其边界
每个 profile 通过 start_new_session=True 启动,POSIX 会为它建立新 session/进程组(setsid 语义)。控制器以子进程 leader PID 为进程组 ID,使用 killpg() 向该组发信号:用户终止/超时/关闭时先 SIGTERM,等待所选宽限期后才 SIGKILL;若 leader 自然结束,仍会对其原组发送 SIGKILL,以避免已知同组后代继续持有 pipe 或存活。
这是有限的进程组清理,不是容器隔离:
只有仍在这个进程组内的后代会被处理。主动
setsid()、另建进程组、委托给守护进程/服务管理器或跨越其他权限边界的工作可能逃离,控制器不保证回收它们。SIGKILL不可捕获,目标应用没有机会执行优雅清理、刷新文件或发送自己的完成确认;因此可能产生不完整输出或外部副作用。无法向进程组发信号、退出无法在确认期限内完成或服务遭到非正常杀死时,不能承诺清理成功。服务正常关闭会尝试终止已知会话,但不存在重启后的恢复/补救。
如果业务需要强隔离、网络限制、文件系统隔离、资源控制或可恢复编排,请在本控制器之外使用操作系统账户、容器/VM、服务管理器和相应审计机制。
默认演示 profiles
默认配置包含以下固定 profile:stream、interactive、long、unicode、flood、exit7、empty、children、closed-stdin、split-utf8、invalid-utf8、eof、ignore-term。它们均由真实 Python 子进程运行 demo_process.py:例如 interactive 读取并回显输入,flood 产生足以触发 buffer 截断的输出,children 建立同进程组后代,ignore-term 用于验证 TERM→KILL 路径。它们不是生产命令批准清单。
测试与独立 MCP 验证
测试与验证脚本是两条独立命令,请分开运行。随包 evidence 保存已执行结果;这不替代你在目标环境的复现。
pytest
# 仅真实 wire-level 测试:pytest -m e2epytest 会发现 tests/。端到端测试会通过官方 MCP stdio client 启动新服务器子进程;其他测试还覆盖会话和输出 buffer 行为。
独立证据脚本不在进程内调用 SessionManager,而是使用官方 StdioServerParameters 和 ClientSession 启动实际 python -m mcp_terminal stdio,从 wire protocol 记录响应。示例:
python scripts/verify_mcp.py --output /tmp/mcp-evidence.json可用 --scenario 名称 重复选择单个或多个场景;省略时运行全部。--output 对验证脚本是必填项,并且无论成功或失败都会写出 JSON 证据;失败时脚本以非零状态退出。该脚本使用其自身路径定位项目,可从无关当前目录运行。运行前请确认依赖已安装,并自行检查 JSON 中的 success、failure、断言和调用记录。
安全说明
部署、配置所有权、威胁模型和漏洞报告方式见 SECURITY.md。最重要的原则是:仅让可信 Owner 写配置,仅批准确有必要的固定可执行文件与根目录,并将本服务视为在其运行用户权限下执行真实本地代码的接口。
SDK 兼容说明与来源
官方 SDK 2.3.0 的默认 stdio 文件读取在 stdin 保持打开时可能阻塞 SIGTERM 停机。本项目 transport.py 用 asyncio fd readiness 提供可取消的文件适配器,仍由官方 stdio_server 解析、序列化及处理协议。该模块集中使用 SDK _lowlevel_server 入口;另在不完整输出清理时使用 asyncio Process 的私有 transport 关闭句柄。它们是已记录的兼容风险,升级 SDK/Python 必须重跑真实协议与停机测试。支持 pipe,未实现 PTY、网络服务或重启恢复。
依赖包含 uv.lock 及带哈希的 requirements.lock / requirements-test.lock。需要 pip 哈希锁定时,在新虚拟环境中安装 python -m pip install --require-hashes -r requirements-test.lock,再执行 python -m pip install --no-deps .。不要把示例绝对路径直接复制到另一台机器;用 make_config.py 重新生成。
Available Tools
5 toolsterminal_readARead-onlyIdempotent
Read non-consuming output records starting at cursor, with a bounded optional wait.
Cursor is an absolute record sequence, not a byte index. Continue with next_cursor. Old cursors return CURSOR_EXPIRED with base_cursor, never silent loss. stdout/stderr retain stream labels. output_complete only becomes true after tail output is drained.
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | No | ||
| wait_ms | No | ||
| max_bytes | No | ||
| session_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, it discloses non-consuming reads, bounded wait behavior, absolute cursor semantics, CURSOR_EXPIRED behavior with base_cursor, stream label retention, and when output_complete becomes true. These are valuable behavioral details not captured by annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense and front-loaded: it starts with the core operation, then clarifies cursor semantics, continuation, error handling, stream labels, and completion. Every sentence adds useful operational detail with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given readOnly annotations and an output schema, the description covers the important behavioral details an agent needs: cursor handling, continuation, expiry behavior, stream labels, and completion. It is only missing explicit guidance for max_bytes and session_id.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explains cursor semantics and implies bounded wait behavior for wait_ms, but max_bytes and session_id are not explained, leaving half the parameters without additional meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: read non-consuming output records from a terminal session. It clearly distinguishes the operation from terminal_write by specifying non-consuming reads, and from terminal_status/start/terminate by focusing on output records.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage context for reading output and explicitly says to continue with next_cursor. However, it does not name alternatives such as terminal_status or state when not to use this tool versus other terminal siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
terminal_startB
Start a real approved process and immediately return its persistent session ID.
Default profiles: stream, interactive, long, unicode, flood, exit7, empty, children, closed-stdin, split-utf8, invalid-utf8, eof, ignore-term. Owner config replaces profiles. No client argv or shell substitution is accepted. cwd must remain under approved roots.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No | ||
| env | No | ||
| command_id | Yes | ||
| timeout_ms | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the safety profile (not read-only, not idempotent, not destructive, closed-world). The description adds real behavioral context beyond that: the call returns immediately with a session ID rather than blocking, commands must be pre-approved with no argv/shell substitution, and cwd is confined to approved roots. It does not disclose lifecycle obligations (sessions persist until terminated) or what timeout_ms governs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core behavior is front-loaded in the first sentence, and the constraint sentences are terse and non-redundant. The profile list is a dense run-on line whose purpose is unclear in context, slightly blunting the structure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values are covered, and the safety posture is annotated. But for a session-creating tool with four undocumented parameters, the description leaves gaps: what timeout_ms applies to (start vs. process lifetime), what env is merged into, and whether the started session must later be terminated to avoid leaking resources.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for all four parameters, so the description must carry the load. It only clarifies cwd ('must remain under approved roots') and gestures at command_id via the 'Default profiles' list without ever saying those are valid command_id values. env and timeout_ms receive no explanation at all.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Start a real approved process') plus the immediate outcome ('return its persistent session ID'), which is enough to distinguish it from terminal_write/read/status/terminate. It does not explicitly name those siblings, but the session-ID framing makes the start-then-attach relationship clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'approved process' framing and the constraint list ('No client argv or shell substitution is accepted') imply you must already have an approved command_id and then use terminal_write/read to interact, but the description never states the sequencing or when-not-to-use explicitly. Usage is inferable rather than spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
terminal_statusBRead-onlyIdempotent
Query lifecycle, real exit code/signal, termination reason and output availability.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish that this is a read-only, idempotent, closed-world operation. The description adds useful behavioral detail that it reports lifecycle, real exit code/signal, termination reason, and output availability, but it does not clarify edge cases such as unknown or expired session ids, nor does it add much beyond the output schema's likely contents.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is a single compact sentence with no filler, and the most important status aspects are front-loaded. Every phrase contributes directly to describing what the query returns.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter read-only status tool with annotations and an output schema, the description is mostly sufficient to call it. Gaps remain around the required session_id and the distinction from terminal_read, so it is adequate but not fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description never mentions the sole required parameter, session_id. The parameter name is fairly intuitive, but the description does not compensate for the missing schema semantics by explaining what session_id refers to or how it should be obtained.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb, 'Query', and names concrete status aspects: lifecycle, real exit code/signal, termination reason, and output availability. This clearly identifies the tool as a terminal-session status query, though it does not explicitly contrast itself with siblings such as terminal_read or terminal_terminate.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the mention of lifecycle and output availability, suggesting it should be used to check terminal state before reading or acting. However, it gives no explicit when-to-use guidance, no exclusions, and no comparison to terminal_read, which is the most likely alternative when an agent wants actual output.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
terminal_terminateADestructiveIdempotent
Idempotently terminate the session process group: TERM, grace, KILL, confirm exit.
Final output and status remain readable for the configured retention interval.
| Name | Required | Description | Default |
|---|---|---|---|
| grace_ms | No | ||
| session_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructive and idempotent, so the description's added value is the concrete kill mechanism: escalation from TERM through a grace window to KILL, verification of exit, and the retention window for final output. It does not say what happens to the process group's children or whether an already-exited session is a no-op error, but the operational sequence is well disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two terse sentences, each earning its place: the first gives the mechanism, the second gives a post-condition the caller needs. The action is front-loaded with no preamble.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the retention sentence covers the one post-call question an agent will have. The remaining gap is permission/authorization requirements and the exact behavior of the grace_ms parameter, minor for a 2-parameter tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the burden. 'TERM, grace, KILL' usefully implies grace_ms is the interval between the polite and forced signal, and session_id is self-explanatory by name. However, units, the 0–2000ms clamp, and the 500ms default for grace_ms are left entirely to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — terminate the session process group — plus the exact escalation sequence (TERM, grace, KILL, confirm exit), which no sibling does. It never names terminal_start or terminal_status, but the verb alone makes it unmistakable next to read/write/status/start.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: the note that output and status remain readable after termination hints that terminal_read/terminal_status are still valid post-call. There is no explicit when-to-use/when-not and no guidance on what to do instead if the caller only wants to interrupt rather than kill.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
terminal_writeA
Write exact UTF-8 text to the running process; append newline yourself if needed.
Optionally close stdin after writing. accepted_bytes means transport acceptance, not application acknowledgement. Never retry blindly after INPUT_BACKPRESSURE.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| session_id | Yes | ||
| close_stdin | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds important behavioral details beyond annotations: newline handling is the caller's responsibility, stdin can optionally be closed, accepted_bytes means transport acceptance rather than application acknowledgement, and blind retries after INPUT_BACKPRESSURE are warned against. These are non-obvious operational semantics that materially help correct invocation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three compact sentences with no filler; the core action and key caveats are front-loaded and each sentence carries useful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with annotations and an output schema, the description covers the critical operational caveats and return-value semantics. It still lacks an explanation of session_id and explicit sibling routing, so it is strong but not fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It clarifies that text is exact UTF-8 and explains newline and close_stdin behavior, but it never explains the required session_id parameter, leaving one required parameter undocumented.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Write') and resource ('exact UTF-8 text to the running process'), so it is not tautological and is immediately understandable. It does not explicitly name or distinguish itself from siblings like terminal_read, terminal_start, or terminal_terminate, which keeps it from a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Implies the tool should be used against an already-running process and gives a caveat about retrying after INPUT_BACKPRESSURE, but does not explicitly say when to use this versus terminal_read, terminal_start, or terminal_terminate. Usage is inferable but not clearly routed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
terminal_read - First observed
terminal_start - First observed
terminal_status - First observed
terminal_terminate - First observed
terminal_write
TDQS
Scored across 5 tools
Each tool maps to a distinct lifecycle stage: start, write, read, status, terminate. The only near-overlap is status reporting 'output availability' versus read returning output, but the descriptions make clear status is metadata-only while read consumes records from a cursor.
All five tools share a uniform terminal_ prefix with a single-word verb suffix (start, write, read, status, terminate). Fully predictable and consistent.
Five tools is exactly the minimal complete set for process session control, with no redundant operations. Each tool earns its place in the lifecycle.
Start/write/read/status/terminate covers the full session lifecycle including graceful and forced termination. Minor gaps exist for interactive/pty use: no terminal_resize and no dedicated signal-send tool (Ctrl-C must be emulated via write), and no session listing, but agents can work around these.
Maintenance
Related MCP Connectors
Start and manage Reason cloud coding agents, projects and sessions from any MCP client.
Hosted MCP memory and agent control plane for durable conversations, jobs, and operations.
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
Manage Sprites: sandboxed compute environments with exec, services, and checkpoints.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables MCP clients to spawn and control Codex CLI and Claude Code sessions on the host machine, with session management and filesystem access.4MIT
- AlicenseNot gradedqualityCmaintenanceEnables MCP clients to launch and interact with terminal/TUI programs, providing tools to inspect and control live CLI/TUI sessions.2 npm1Apache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables management of long-running development processes (such as dev servers, compilers, and watchers) from MCP hosts. Provides tools to start, stop, restart, check status, view logs, and send input to managed processes.MIT
- AlicenseNot gradedqualityDmaintenanceProvides persistent interactive shell sessions via pseudo-terminals for MCP agents, enabling bidirectional communication, incremental reads, and stateful command execution across steps.7 npmMIT