关于 tmux
这是一个供编码 Agent 检查和操作单个 tmux 服务的 MCP 服务,可管理会话、窗口、窗格及其输出。它提供有界读取、等待工具和可选工具集,便于监控任务并限制客户端可执行的操作。
主要功能
- 01检查会话、窗口和窗格
- 02创建并调整 tmux 窗格
- 03发送输入并运行 shell 命令
- 04等待窗格输出或匹配文本
- 05选择工具集和单个工具
适用场景
- 01等待测试运行结束
- 02在独立窗格中运行命令
- 03让 Agent 检查专用 tmux 服务
MCP 相关
向 MCP 客户端提供 tmux 检查、管理、执行和拆除工具。服务启动时选定一个 tmux 服务,也可限制其可用工具集。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
$ go install github.com/libtmux/libtmux-go/mcp/cmd/libtmux-mcp@latest
版本号采用 0.1.N 格式,每次发布都会递增 N。API 尚未稳定:任何版本都可能更改或移除导出的标识符,变更日志会标明每项不兼容变更。请固定到精确版本,以避免此类变更。
目录 — 快速开始 · 连接其他客户端 · 选择它控制的 tmux · 查看 Agent 工作 · 运行任务并等待完成 · 工具 · 限制客户端的操作 · 设置 · 它运行的窗格 · 已知限制 · 故障排除 · Agent 形态的程序 · 嵌入使用 · 软件包 · 它不包含的内容 · 支持与状态 · 另请参阅
快速开始
你需要 Go 1.26 或更高版本,以及位于 PATH 中的 tmux 3.3a 或更高版本。上面的安装命令会在设置了 GOBIN 时将 [libtmux-mcp][libtmux-mcp-command] 安装到其中,否则安装到 $(go env GOPATH)/bin。
MCP 客户端会将其作为子进程启动,并通过 stdin 和 stdout 与其通信,因此它不会持续运行。如果你的 shell 找不到 libtmux-mcp,请将该目录添加到 PATH。
Python 服务也会安装一个同名命令。运行
command -v libtmux-mcp 可查看哪个命令排在前面,运行
libtmux-mcp -version 可确认这是哪个版本。
claude mcp add:告知 Claude Code
$ claude mcp add tmux -- libtmux-mcp
Claude Code 会启动其列出的每个服务,以检查连接是否正常:
$ claude mcp list
[libtmux-mcp -doctor][guide-diagnose-startup]:检查它能连接到什么
$ libtmux-mcp -doctor
无需客户端介入即可运行,并会打印类似这样的内容:
libtmux-mcp doctor
tmux: 3.6 (requires 3.3a or newer)
socket: /tmp/tmux-1000/libtmux-mcp (from default dedicated socket)
holds: nothing — no tmux server is running on that socket
(not a fault; tmux starts one when something asks it to)
caller: not running inside a tmux pane
然后请客户端执行只有 tmux 才能完成的操作,例如“创建一个名为 demo 的 tmux 会话,并告诉我它有哪些窗格”。
连接其他客户端
每个客户端都使用相同的命令和标志。[在 libtmux.org 上连接 MCP 客户端][guide-connect-client]介绍了启动和关闭方式。
codex mcp add:Codex CLI
$ codex mcp add tmux -- libtmux-mcp
gemini mcp add:Gemini CLI
$ gemini mcp add tmux libtmux-mcp
claude_desktop_config.json:Claude Desktop
Claude Desktop 启动服务时不会使用 shell 的 PATH,因此请提供 command -v libtmux-mcp 输出的路径。标志放在 args 中,环境变量放在 env 中:
{
"mcpServers": {
"tmux": {
"command": "/path/to/libtmux-mcp",
"args": ["-socket-name", "my-application"],
"env": {"LIBTMUX_TOOLSETS": "inspect,manage,execute"}
}
}
}
选择它控制的 tmux
此选择只在服务启动时确定一次,客户端之后无法更改。设置列出了其他标志,[契约][contract-which-tmux]说明了优先级规则。
[-socket-name][guide-choose-a-server]:按名称选择套接字
如果不指定标志,服务会控制一个独立的 tmux 服务,该服务使用名为 libtmux-mcp 的套接字,并通过软件包附带的最简配置启动。获得该权限的 Agent 无法触碰你已有的会话。
创建会话后,你可以在另一个终端中查看它的工作:
$ tmux -L libtmux-mcp attach
若要让它控制你日常使用的 tmux,请指定该套接字的名称。tmux 将常用套接字称为 default:
$ claude mcp add tmux -- libtmux-mcp -socket-name default
通过 [tmux-workspace load -L project][workspace-cli-load] 创建的工作区位于 project 套接字上。若要允许客户端读取它而不做任何更改:
$ claude mcp add tmux \
-e LIBTMUX_TOOLSETS=inspect \
-- libtmux-mcp -socket-name project
[-socket-path 和 -binary][guide-choose-a-server]:指定确切的套接字和 tmux
-socket-path 通过绝对路径指定套接字,-binary 指定 tmux 可执行文件。-doctor 会报告所选配置:
$ libtmux-mcp \
-doctor \
-socket-path /tmp/my-application.sock
环境变量也能进行相同的配置,这也是客户端设置这些选项的方式:
$ LIBTMUX_SOCKET=my-application libtmux-mcp -doctor
查看 Agent 执行工作
以下是 examples/agent-workflow 为了在与自身相邻的窗格中执行工作而发出的调用,以及返回的内容。省略了游标令牌,每条回复只展示回答该调用所需的字段:
→ split_window {"direction":"right","pane_id":"%0","percent":40}
← {"paneId":"%1"}
→ paste_text {"enter":true,"pane_id":"%1","text":"if sleep 1; then printf 'agent-workflow-%s\\n' ready; else printf 'agent-workflow-%s\\n' failed; fi"}
← {"bytes":97}
→ wait_for_text {"pane_id":"%1","patterns":["agent-workflow-ready"],"stop":["agent-workflow-failed"],"timeout":30}
← {"found":true,"matched":"agent-workflow-ready","outcome":"matched"}
→ run_shell_command {"command":"printf 'bounded work\\n'","pane_id":"%1","timeout":30}
← {"exit_status":0,"output":["bounded work"],"timed_out":false}
示例使用 -trace 打印这些内容,示例页面中提供了命令。Agent 直接驱动 tmux,因此无需从终端复制粘贴内容,等待服务启动也只需一次调用。
执行工作并等待结果
如果只需执行一次 tmux send-keys,直接调用 shell 更简单。只有当 Agent 需要等待、监视、检查或不打扰你的终端时,这项服务才真正派得上用场。
开发服务器打印端口、测试运行结束或部署日志稳定下来时,调用 shell 就会变成轮询循环。这个循环会读取 shell 对自己命令的回显,并在事情发生之前就报告成功。
[split_window][split_window]:在窗格旁腾出空间
[split_window][split_window] 会新增一个窗格并返回其 ID。新窗格会获得启动时间,因此可以立即调用 [run_shell_command][run_shell_command]。
跟踪记录将 %0 向右分割,参数为 "percent":40,并返回 {"paneId":"%1"}。
[wait_for_text][wait_for_text]:等待窗格输出内容
[wait_for_text][wait_for_text] 会监视窗格,直到出现匹配模式时返回;如果 stop 模式先出现,也会返回。
[capture_since][capture_since] 会返回窗格自上次查看以来写入的内容。
跟踪记录等待 agent-workflow-ready,并将 agent-workflow-failed 指定为停止模式。它返回 "outcome":"matched"。
如果等待时间超过上限,等待时长会被缩短,回复也会说明这一点。上限由 [LIBTMUX_MCP_WAIT_MAX_SECONDS][mcp-waitceilingenvironmentvariable] 指定。
如果窗格在等待期间消失,回复中的 outcome 为 paneDied,lines 保存它先前写入的内容。如果只有输出流结束,而窗格仍然存活,则结果为 streamLost。[契约][contract-wait-ends]中介绍了其余情况。
[run_shell_command][run_shell_command]:运行命令并读取退出状态
[run_shell_command][run_shell_command] 会等待命令执行完毕并返回其退出状态和输出,全程不读取屏幕内容。
[send_keys][send_keys] 和 [paste_text][paste_text] 会发送输入并返回。
跟踪记录运行了一条打印 "bounded work" 的命令,并返回 "exit_status":0。
如果窗格通过 synchronize-panes 与其他窗格关联,[run_shell_command][run_shell_command] 会拒绝执行,因为单个退出状态无法描述多个窗格。
让读取保持精简
设计中的其他部分也有其用意,因为 Agent 的上下文和轮次都是稀缺资源。
- 读取有上限。 捕获会保留指定数量的最新行,并说明省略了哪些内容。搜索也有固定上限,详见[契约][contract-bounded-reads]。
- 一次调用可执行多次读取。
[
call_read_tools_batch][call_read_tools_batch] 会用一行结果回答一组inspect调用。 - 检查不会捕获内容。 列表工具会报告有哪些对象,而不读取任何窗格显示的内容。[
snapshot_pane][snapshot_pane] 会同时返回窗格元数据和内容。
工具
这些工具分为[工具集][topic-tool-selection]。工具集是由一组工具组成的命名分组,操作者可以授权或禁用整个工具集:
inspect读取 tmux 及窗格显示的内容,不做任何更改。manage重新安排现有对象:重命名、调整大小、选择和移动。execute创建会话、窗口和窗格,并向其中发送输入。teardown终止会话、窗口和窗格,并清除回滚缓冲区。 | 工具集 | 工具 | | --- | --- | |inspect|call_read_tools_batch,capture_pane,capture_since,find_pane_by_position,get_pane_info,get_server_info,get_session_info,get_tmux_variables,get_window_info,list_panes,list_sessions,list_windows,search_panes,show_environment,show_hooks,show_option,snapshot_pane,wait_for_text| |manage|move_window,rename_session,rename_window,resize_pane,resize_window,select_layout,select_pane,select_window,set_history_limit,set_mouse_enabled,set_pane_title,signal_channel,swap_pane,wait_for_channel| |execute|create_session,create_window,paste_text,respawn_pane,run_shell_command,send_keys_batch,send_keys,set_synchronize_panes,split_window| |teardown|clear_pane_scrollback,kill_pane,kill_session,kill_window|
TOOLS.md 列出了每个工具的所有参数及其返回内容,文档网站也为每个工具提供了上方链接所指向的页面。该参考资料用于搜索,因此这里不再列出。
授予 execute 权限前,有三种行为需要注意:
- 输入会发送到 tmux 指定的位置。 开启
synchronize-panes后,tmux 会将输入发送到窗口的每个窗格。发送前,[send_keys][send_keys] 会报告已关联的窗格。 - 新窗格会留出启动时间。 输入工具会等待其 Shell 出现提示符,因此 [
split_window][split_window] 后接 [run_shell_command][run_shell_command] 可以正常工作。 - 复制模式由用户自行处理。 读取操作不会接管已连接的视图,而 [
get_pane_info][get_pane_info] 会报告窗格是否处于某种模式。
[契约][contract-input] 介绍了其余每项内容。
限制客户端可以执行的操作
[LIBTMUX_TOOLSETS][mcp-toolsetsenvironmentvariable]:选择工具集
工具集名称以逗号分隔,顺序不限。未设置时,服务会授予 inspect、manage 和 execute。
- 仅当此进程在
libtmux-mcp套接字上启动了 tmux 服务时,teardown才会加入默认工具集。在其他情况下,请按名称请求它。 - 设置为空值时,不会授予任何工具集,也没有
none关键字。
若要在不使用客户端的情况下查看效果,请列出服务在指定单个工具集时提供的内容:
$ LIBTMUX_TOOLSETS=inspect libtmux-mcp -tools
客户端会从其启动服务时使用的环境中获取相同的选择:
$ claude mcp add tmux \
-e LIBTMUX_TOOLSETS=inspect \
-- libtmux-mcp -socket-name default
[LIBTMUX_TOOLS][mcp-toolsenvironmentvariable] 和 [LIBTMUX_EXCLUDE_TOOLS][mcp-excludetoolsenvironmentvariable]:指定确切的工具
[LIBTMUX_TOOLS][mcp-toolsenvironmentvariable] 会按名称添加工具集所授予的工具,随后 [LIBTMUX_EXCLUDE_TOOLS][mcp-excludetoolsenvironmentvariable] 会按名称移除工具。被排除的工具也会从 [call_read_tools_batch][call_read_tools_batch] 可调用的工具中移除。
以下命令列出默认工具,但不包括 [send_keys][send_keys] 和 [send_keys_batch][send_keys_batch]:
$ LIBTMUX_EXCLUDE_TOOLS=send_keys,send_keys_batch libtmux-mcp -tools
如果名称与任何工具都不匹配,或者任一列表中包含空项,服务会在启动时、打开 tmux 之前停止。
选择工具会影响客户端可以使用哪些工具。每次调用都以你的用户权限运行。[契约][contract-exact-tools] 涵盖了早期版本中的这些变量。
[libtmux-mcp -tools][guide-inspect-the-selection]:查看客户端可以使用哪些工具
$ libtmux-mcp -tools
此命令会打印服务将公布的工具:每个工具所属的工具集、它可以访问的进程,以及对其用途的简短说明。请提供客户端传给服务的标志和环境变量,因为它们会决定列表内容。
[tmux://capabilities][mcp-capabilitiesresourceuri]:各工具对自身能力的说明
每个工具都会在 _meta["com.git-pull.libtmux-mcp/capability"] 下说明其访问和更改的内容。服务的唯一资源 tmux://capabilities 会在当前生效的选择旁报告相同的说明。[契约][contract-capability-disclosure] 列出了这些说明。
设置
标志会在启动时选择 tmux 服务:
| 标志 | 含义 |
|---|---|
-socket-path | 显式指定套接字路径;设置后优先级最高 |
-socket-name | tmux 套接字名称;设置后优先于下面两个套接字变量 |
-binary | tmux 可执行文件;留空时使用 [LIBTMUX_TMUX_BIN][mcp-binaryenvironmentvariable],然后在 PATH 中查找 tmux |
其他标志用于查询并退出,适用于无法启动的配置项:
| 标志 | 查询内容 |
|---|---|
-version | 当前构建的版本 |
-tools | 客户端可见的工具和工具集 |
-doctor | 它连接到哪个套接字、套接字上有什么,以及它是否运行在该 tmux 本身内部 |
其余设置由环境变量指定:
| 变量 | 作用 |
|---|---|
[LIBTMUX_TOOLSETS][mcp-toolsetsenvironmentvariable] | 选择工具集的任意子集,顺序不限 |
[LIBTMUX_TOOLS][mcp-toolsenvironmentvariable] | 在展开工具集后,包含精确匹配的工具名称 |
[LIBTMUX_EXCLUDE_TOOLS][mcp-excludetoolsenvironmentvariable] | 在包含所有工具后,移除精确匹配的名称 |
[LIBTMUX_SOCKET_PATH][mcp-socketpathenvironmentvariable] | 选择绝对套接字路径;不能与 [LIBTMUX_SOCKET][mcp-socketenvironmentvariable] 同时使用 |
[LIBTMUX_SOCKET][mcp-socketenvironmentvariable] | 未通过套接字标志选择套接字时,指定 tmux 套接字名称 |
[LIBTMUX_TMUX_CONFIG][mcp-tmuxconfigenvironmentvariable] | 选择非空的绝对 tmux 配置路径 |
[LIBTMUX_TMUX_BIN][mcp-binaryenvironmentvariable] | -binary 留空时,选择 tmux 可执行文件 |
[LIBTMUX_MCP_WAIT_MAX_SECONDS][mcp-waitceilingenvironmentvariable] | 任意一次等待可运行的最长时间;默认为 300 秒 |
[LIBTMUX_AUDIT][mcp-auditenvironmentvariable] | 使用 stderr 或指定路径,记录每次调用 |
- **标志优先于对应变量,**所有设置在服务启动时确定。名称与 Python 服务中的一致。
- **tmux 可执行文件只解析一次。**路径无效会导致启动失败。tmux 服务尚未运行也没有关系,因为 tmux 会按需启动服务。
- **过长的等待会被缩短。**回复会在
effectiveTimeoutSeconds和timeoutClamped中说明这一点。
[契约][contract-settings]提供了完整说明。
它运行所在的窗格
isCaller:识别自身窗格
服务报告的每个窗格都带有 isCaller:运行服务的窗格为 true,其他窗格为 false;如果服务不在任何窗格中运行,则为 null。
[get_server_info][get_server_info]会直接回答同一问题。
服务会先读取 TMUX_PANE 和 TMUX。如果这两个变量都没有提供信息,它会查找进程属于自身某个祖先进程的窗格。
在向你的终端输入内容前先征求同意
向 isCaller 为 true 的窗格写入内容时,会先通过 MCP 的征询请求向你确认:客户端代表服务向你提出问题。
- 拒绝会导致调用失败;无法发起询问的客户端会被拒绝。
- 批量操作也会以同样方式询问;如果你拒绝,批量操作会就此停止。
- 如果启用了
synchronize-panes,询问会涵盖输入内容将影响的所有窗格。
其余内容见[契约][contract-caller-pane]。
已知限制
- 部分工具需要较新版本的 tmux。 启动和常规工具支持 3.3a,包括
capture_since和run_shell_command。非空的paste_text在暂存任何缓冲区前需要 3.4;wait_for_text在 3.7 以下通过capture-pane轮询,在 3.7 起则跟踪控制输出。受限工具在较旧的受支持守护进程上会返回明确的版本错误。运行时在 3.7 以下使用子进程命令,在 3.7 起使用保留的控制连接。 - 每个工具都标记为具有破坏性。 包括 [
list_sessions][list_sessions] 在内,每个工具都带有destructiveHint=true,且没有readOnlyHint。请根据各工具_meta中的tmuxEffects进行分类。 tools/list内容很大。 其中一半以上是_meta描述。需要更小回复的客户端可以忽略_meta。- 部分工具返回结果的字段名不同。 [
run_shell_command][run_shell_command]、[send_keys][send_keys]、[paste_text][paste_text] 和 [clear_pane_scrollback][clear_pane_scrollback] 返回exit_status等字段;其余工具返回paneId等字段。 - 空的
TMUX也算已设置。 如果TMUX或TMUX_PANE已设置为空,输入工具会拒绝执行。请取消设置,而不是将其设为空。
[契约][contract-known-limits]说明了每项限制的原因,PARITY.md介绍了结果字段名。
故障排除
先询问服务。-doctor 无需客户端介入,就能回答以下大部分问题:
$ libtmux-mcp -doctor -socket-name default
- 客户端没有显示 tmux 工具。 服务从未启动。手动运行客户端配置中的命令。
- 缺少工具。 [
LIBTMUX_TOOLSETS][mcp-toolsetsenvironmentvariable]、[LIBTMUX_TOOLS][mcp-toolsenvironmentvariable] 或 [LIBTMUX_EXCLUDE_TOOLS][mcp-excludetoolsenvironmentvariable] 会影响工具列表。-tools会打印客户端收到的内容。 - 看不到你的任何会话。 如果没有指定
-socket-name,它会驱动自己的 tmux 服务。-doctor会显示套接字名称。 - 连接到了错误的 tmux。 客户端的环境与 shell 的环境不同,因此客户端可能无法获取配置文件中的
TMUX_TMPDIR。 - 明明能看到会话,却报告没有会话。 将
-doctor打印的 tmux 版本与tmux -V输出进行比较,并将-binary指向正确的可执行文件。 - 命令在 shell 中可运行,通过工具却不行。 [
show_environment][show_environment] 会报告新窗格将继承的环境。
[契约][contract-troubleshooting]解释了每种情况。
面向 Agent 的程序
examples/agent-workflow 用一个文件实现了完整的工作循环。它会找到自己的窗格,分出一个新窗格,在其中启动任务并等待输出,运行命令并读取其退出状态,然后读取构建结果。
它位于仓库中,不在你安装的模块内,因此请从克隆的仓库中运行:
$ git clone https://github.com/libtmux/libtmux-go.git
$ go -C libtmux-go/mcp run ./examples/agent-workflow -socket-name demo
在没有任何活动的套接字上运行时,它会在那里启动一个会话并打印:
no tmux server on that socket yet; starting one
not running inside this tmux server; using active pane %0
split into %1
2 panes in this window while the work runs
the work printed agent-workflow-ready
the command exited 0 and printed:
| bounded work
the window now holds 2 panes: %0 %1
客户端和服务在内存中连接,因此它们是一个程序。工具名称、架构和结果与客户端通过 stdin 和 stdout 看到的一致。使用 tmux -L demo kill-server 清理。
嵌入
[mcp.NewServer][mcp-newserver]:在自己的程序中服务一个 tmux 服务
[mcp.Run][mcp-run] 会通过标准输入和输出服务 tmux 服务,libtmux-mcp 命令所做的也正是如此。若要使用其他传输方式,请构建一个 [Instance][mcp-instance] 并自行连接。
此代码块来自该包自身的示例测试。它连接 SDK 内存传输对的一端,并将另一端交给客户端:
// Given: ctx context.Context; target tmux.Server; serverTransport sdk.Transport
instance, err := tmuxmcp.NewServer(target)
if err != nil {
return nil, nil, err
}
serverSession, err := instance.Connect(
ctx, tmuxmcp.AssumeResponseCommit(serverTransport), nil,
)
此包和 SDK 都将包命名为 mcp,因此代码块将此包导入为 tmuxmcp,将 SDK 导入为 sdk。[NewServer][mcp-newserver] 会检查目标,但不会启动任何内容。
[mcp.AssumeResponseCommit][mcp-assumeresponsecommit]:声明传输层会一次性写入每个响应
已知标准输入和标准输出会在写入返回后立即传递每个响应。对于其他传输层,请用
[AssumeResponseCommit][mcp-assumeresponsecommit] 封装,就像此代码块对内存中的传输层所做的那样。
服务完成后,请[关闭实例][mcp-instance-close]。[参考文档][mcp-reference]介绍了嵌入者需要遵守的其余要求,[契约][contract-embedding]则提供了完整文本。
软件包
mcp:作为库的服务端
[mcp.Run][mcp-run] 和 [mcp.NewServer][mcp-newserver] 会向客户端提供 tmux 服务。参考文档:pkg.go.dev
和 [libtmux.org][mcp-reference]。
libtmux-mcp:客户端启动的命令
它通过标准输入和标准输出为一个 tmux 服务提供服务。参考文档: [pkg.go.dev][libtmux-mcp-command] 和 命令 README。
不包含的内容
- 第二个 tmux 服务。 服务端在整个进程生命周期内只为一个 tmux 服务提供服务,客户端也无法在调用中指定其他套接字。
- 工具以外的功能。 只有一个资源,不包含提示词、资源模板、补全功能或后台任务句柄。
- 访问限制。 工具集决定向客户端提供哪些内容。每次调用都以你的用户权限运行,因此持有 [
send_keys][send_keys] 的客户端可以执行你能执行的任何操作。 - Python 服务端的逐次调用套接字。 套接字在启动时选择一次。PARITY.md 列出了其他差异。
支持与状态
- Go 1.26+ 和 tmux 3.3a 或更高版本。 MCP 传输启动前,服务端会拒绝较旧版本的 tmux。CI 使用 tmux 3.3a 至 3.8 运行测试。
- Linux(包括 WSL)和 macOS。 CI 会在 Linux 上使用 tmux 3.3a 至 3.8 运行此模块的测试。macOS 按尽力而为的原则提供支持,CI 对其覆盖非常有限。
- 独立模块。 对 tmux 库运行
go get不会引入 MCP SDK。 - 标记为
mcp/vN。 在你自己的go.mod中固定确切版本;此处的命令会获取最新版本。
另请参阅
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。