
tmux
io.github.libtmux由 GitHub 账号 libtmux 发布v0.0.1-alpha.4更新于 Oct 24, 2026
Drive one tmux server: sessions, windows, panes, and the output they produce.
概览
让助手驱动一个 tmux 服务器:创建和管理会话、窗口与窗格,执行命令并观察窗格输出。
- 可以做什么
- 把一个 tmux 服务器提供给 MCP 客户端,暴露会话、窗口、窗格及其输出。工具涵盖检查、管理、命令执行和拆除,包括返回退出状态与输出的 run_shell_command、用于等待窗格写入的 wait_for_text,以及只返回上次查看之后新增内容的 capture_since。读取有上限,批量工具一次可执行最多十六个检查操作。它还会报告某个窗格是否就是服务器自身所在的窗格。
- 适用场景
- 当助手需要等待、观察或检查终端输出,而不是只执行一次 shell 命令时值得加入,例如等待开发服务器打印端口、测试运行结束或部署日志稳定下来。若只是发送一次按键,则没有必要。
- 运行要求
- 作为本地子进程通过 stdio 运行。安装需要 Go 1.26 或更高版本,以及 PATH 中 tmux 3.2a 或更高版本。未声明账号、API 密钥或请求头。套接字、可执行文件和配置在启动时通过命令行标志或环境变量选择,例如 LIBTMUX_SOCKET、LIBTMUX_SOCKET_PATH、LIBTMUX_TMUX_BIN 和 LIBTMUX_TMUX_CONFIG。
安装
在 SourceWeft 中
- 打开 控制台中的 tmux,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
mcp
Serve one tmux server to Model Context Protocol clients, built on the tmux module and the Go MCP SDK.
Releases are numbered 0.1.N, and each release increments N. The API is not
settled: any release may change or remove exported identifiers, and the
changelog marks each break. Pin an exact version to avoid one.
Contents — Quick start · Connect another client · Choose which tmux it drives · See an agent work · Run work and wait for it · The tools · Limiting what a client can do · Settings · The pane it runs in · Known limits · Troubleshooting · An agent-shaped program · Embedding it · Packages · What it leaves out · Support and status · See also
Quick start
You need Go 1.26 or newer and tmux 3.3a or newer on PATH. The install
command above puts libtmux-mcp in GOBIN when that is
set, and in $(go env GOPATH)/bin otherwise.
An MCP client launches it as a subprocess and speaks to it over stdin and
stdout. Closing the client ends the MCP process and its owned connections;
tmux sessions remain running. If your shell cannot find libtmux-mcp, add
that directory to PATH.
The Python server installs a command of the same name. Run
command -v libtmux-mcp to see which one comes first, and
libtmux-mcp -version to name this one.
claude mcp add: tell Claude Code about it
Claude Code starts each server it lists, to check that it connects:
libtmux-mcp -doctor: check what it reaches
It answers without a client in the way, and prints something like this:
Then ask the client for something only tmux can do, such as "create a tmux session called demo and tell me what panes it has".
Connect another client
Each client takes the same command and the same flags. Connect an MCP client on libtmux.org covers startup and shutdown.
codex mcp add: Codex CLI
gemini mcp add: Gemini CLI
claude_desktop_config.json: Claude Desktop
Claude Desktop starts its servers without your shell's PATH, so give it the
path command -v libtmux-mcp prints. Flags go in args and the environment in
env:
Choose which tmux it drives
The choice is made once, when the server starts. A client cannot change it afterwards. Settings lists the other flags, and the contract has the precedence rules.
-socket-name: pick a socket by name
With no flag and neither LIBTMUX_SOCKET_PATH nor LIBTMUX_SOCKET set, the
server passes tmux no socket, so tmux picks the server. Started inside tmux,
that is the server you are in. Started elsewhere, it is tmux's default socket,
which holds the sessions you already have, and an agent given it can change
them. A named socket keeps an agent apart from them:
Tools target the selected socket and still run with your user's authority; tool selection is not confinement.
Once it has made a session, watch it work from another terminal:
To drive the tmux you use every day from outside it, name that socket. tmux
calls its usual one default:
A workspace that tmux-workspace load -L project built
lives on the socket project. To let a client read it and change nothing:
-socket-path and -binary: an exact socket and tmux
-socket-path names the socket by its absolute path, and -binary names the
tmux executable. -doctor reports what a choice selects:
The environment makes the same choices when no flag is given, which is how a
client's configuration sets them. LIBTMUX_SOCKET_PATH names a socket path and
LIBTMUX_SOCKET a socket name, and the path wins when both are set:
See an agent work
These are the calls examples/agent-workflow makes
to run work in a pane beside its own, and what came back. Cursor tokens are
left out, and each reply shows only the fields that answer the call:
The example prints these with -trace, and its page
has the command. The agent drives tmux directly, so nothing is copy-pasted out
of a terminal, and waiting for a server to come up is one call.
Run work and wait for it
For one tmux send-keys, shelling out is shorter. The server earns its keep
once the agent has to wait, watch, inspect, or leave your
terminal alone.
A dev server printing its port, a test run finishing, or a deploy log settling turns a shell-out into a polling loop. That loop reads the shell's echo of its own command and reports success before anything happened.
split_window: make room beside your pane
split_window adds a pane and returns its id. A new pane is
given time to start, so run_shell_command can follow at
once.
The trace splits %0 to the right with "percent":40 and gets back
{"paneId":"%1"}.
wait_for_text: wait for what a pane prints
wait_for_text watches a pane and returns when a pattern
appears, or when a stop pattern appears first.
capture_since returns what a pane wrote since the last
look.
The trace waits for agent-workflow-ready and names agent-workflow-failed as
the stop pattern. It gets "outcome":"matched".
A wait longer than the ceiling is shortened, and the reply says so. The
ceiling is LIBTMUX_MCP_WAIT_MAX_SECONDS.
If the pane goes away mid-wait, the reply's outcome is paneDied and lines
holds what it wrote first. If only the output stream ends and the pane is
alive, it is streamLost. The contract has the rest.
run_shell_command: run a command and read its exit status
run_shell_command waits for the command and returns its
exit status and output, without reading the screen at all.
send_keys and paste_text send input and return.
The trace runs a command that prints "bounded work" and gets back
"exit_status":0.
run_shell_command refuses a pane linked with others by
synchronize-panes, because one exit status cannot describe several panes.
Keep reads small
Other parts of the design exist because an agent's context and its turn are the scarce resources.
- Reads are bounded. Captures keep the newest lines asked for and say what they left out. Searches have fixed limits, which the contract lists.
- One call can make several reads.
call_read_tools_batchanswers a list ofinspectcalls with one row each. - Checking is not capturing. The listing tools report what exists without
reading what any pane shows.
snapshot_panereturns a pane's metadata and content together.
The tools
The tools come in toolsets. A toolset is a named group of tools, and it is what an operator grants or withholds:
inspectreads tmux and what panes show, and changes nothing.managerearranges what exists: it renames, resizes, selects, and moves.executecreates sessions, windows, and panes, and sends input to them.teardownkills sessions, windows, and panes, and clears scrollback.
TOOLS.md has every tool's arguments and what it returns, and the documentation site gives each tool the page linked above. That reference is for searching, which is why it is not here.
Four behaviours matter before you grant execute:
- Input goes where tmux sends it. With
synchronize-paneson, tmux types into every pane of the window.send_keysreports the linked panes before it sends. - A new pane is given time to start. Input tools wait for its shell to
reach the prompt, so
split_windowthenrun_shell_commandworks. - Copy mode is left to the person. Reads never take over an attached
view, and
get_pane_inforeports when a pane is in a mode. - A pane someone is viewing is refused. The input tools do not type into a
pane a tmux client is showing, unless you launch the server with
LIBTMUX_ALLOW_ATTENDED_INPUT.
The contract has the rest of each.
Limiting what a client can do
LIBTMUX_TOOLSETS: choose the toolsets
It takes toolset names separated by commas, in any order. Without it the
server grants inspect, manage, and execute.
teardownis never in that default. Ask for it by name.- A value that is set and empty grants no toolset, and there is no
nonekeyword.
To see the effect without a client, list what the server offers with one toolset:
A client gets the same selection from the environment it starts the server with:
LIBTMUX_TOOLS and LIBTMUX_EXCLUDE_TOOLS: name exact tools
LIBTMUX_TOOLS adds tools by name to what the
toolsets grant, and
LIBTMUX_EXCLUDE_TOOLS then removes
tools by name. Excluding a tool also removes it from what
call_read_tools_batch may call.
This lists the default tools without send_keys and
send_keys_batch:
A name that matches no tool, or an empty item in either list, stops the server at startup, before it opens tmux.
Choosing tools shapes what a client is offered. Every call runs with your user's authority. The contract covers the variables from earlier releases.
LIBTMUX_ALLOW_ATTENDED_INPUT: allow input to a pane someone is viewing
Every input tool refuses a pane that a tmux client is viewing, so an agent does
not type into the window a person is looking at. That refusal is the default.
To let the agent type into the window you are viewing, launch the server with
LIBTMUX_ALLOW_ATTENDED_INPUT=1:
The setting lifts that one refusal. A dead pane, a pane with input disabled, a
pane in a mode, and a synchronized pane that has such a member are still
refused. The only accepted value is 1. Any other value, including an empty
one, stops startup with a message that names the variable.
The server reads it once, at startup. tmux://capabilities reports it as
allowAttendedInput, and libtmux-mcp -doctor prints it.
libtmux-mcp -tools: see what a client would be offered
It prints the tools the server would advertise: each one's toolset, which processes it can reach, and a sentence on what it does. Give it the flags and environment the client gives the server, because they decide the listing.
tmux://capabilities: what each tool says about itself
Each tool describes what it reaches and changes, under
_meta["com.git-pull.libtmux-mcp/capability"]. The server's one resource,
tmux://capabilities, reports the same descriptions beside the selection in
force. The contract lists them.
Settings
Flags choose the tmux server once, at startup:
Other flags answer a question and exit, which is what a config entry that will not start needs:
The environment sets the rest:
- A flag wins over its variable, and everything is fixed when the server starts. The names match the Python server's.
- The tmux executable is resolved once. A bad path fails at startup. A tmux server that is not running is fine, because tmux starts one on demand.
- A long wait is shortened. The reply says so in
effectiveTimeoutSecondsandtimeoutClamped.
The contract has the full text.
The pane it runs in
isCaller: knowing its own pane
Every pane the server reports carries isCaller: true for the pane it runs
in, false for any other, and null when the server is not in a pane at all.
get_server_info answers the same question directly.
The server reads TMUX_PANE and TMUX first. When they say nothing, it finds
the pane whose process is one of its own ancestors.
Asking before it types into your terminal
A write to the pane with isCaller true asks you first, through MCP's
elicitation request: a question the client puts to you on the server's behalf.
- Declining fails the call, and a client that cannot ask is refused.
- A batch asks the same way, and declining stops the batch there.
- With
synchronize-paneson, the question covers every pane the input would reach.
The contract has the rest.
Known limits
- Some tools require a newer tmux. Startup and ordinary tools support
3.3a, including
capture_sinceandrun_shell_command. Non-emptypaste_textrequires 3.4 before staging any buffer;wait_for_textpolls withcapture-panebelow 3.7 and follows control output from 3.7. Restricted tools return an explicit version error on older supported daemons. The runtime uses subprocess commands below 3.7 and a retained control connection from 3.7. - Every tool is annotated as destructive.
list_sessionsincluded, each carriesdestructiveHint=trueand noreadOnlyHint. Classify bytmuxEffectsin each tool's_meta. tools/listis large. More than half of it is the_metadescription. A client that wants a smaller reply can ignore_meta.- Some tools spell results differently.
run_shell_command,send_keys,paste_text, andclear_pane_scrollbackreturn fields such asexit_status; the rest return fields such aspaneId. - An empty
TMUXcounts as set. Input tools refuse whenTMUXorTMUX_PANEis set to nothing. Unset them instead.
The contract gives the reason for each, and PARITY.md covers the result spellings.
Troubleshooting
Ask the server first. -doctor answers most of what follows without a client
in the way:
- The client shows no tmux tools. The server never started. Run the command from your client's config by hand.
- Tools are missing.
LIBTMUX_TOOLSETS,LIBTMUX_TOOLS, orLIBTMUX_EXCLUDE_TOOLSshaped the listing.-toolsprints what a client receives. - It sees none of your sessions. With no socket flag and neither
LIBTMUX_SOCKET_PATHnorLIBTMUX_SOCKET, tmux picks the server: the oneTMUXnames, otherwise its default socket, which may not hold your sessions.-doctornames the socket and what chose it. Point the server at yours with-socket-nameor-socket-path. - It reaches the wrong tmux. A client's environment is not your shell's,
so
TMUX_TMPDIRfrom your profile may be unset for it. - Sessions you can see are reported as nothing there. Compare the tmux
version
-doctorprints withtmux -V, and point-binaryat the right one. - A command works in your shell but not through a tool.
show_environmentreports what a new pane would inherit.
The contract explains each.
An agent-shaped program
examples/agent-workflow is the whole loop in one
file. It finds its own pane, splits one off, starts work there and waits for
what it prints, runs a command and reads its exit status, then reads back what
it built.
It lives in the repository, outside the module you installed, so run it from a clone:
On a socket with nothing on it, it starts a session there and prints:
The client and server are joined in memory, so it is one program. The tool
names, schemas, and results are the ones a client sees over stdin and stdout.
Clean up with tmux -L demo kill-server.
Embedding it
mcp.NewServer: serve one tmux server from your own program
mcp.Run serves a tmux server over standard input and output,
which is all the libtmux-mcp command does. For another transport, build an
Instance and connect it yourself.
This block comes from the package's own example test. It connects one end of the SDK's in-memory transport pair and gives the other end to a client:
This package is named mcp and so is the SDK's, so the block imports this one
as tmuxmcp and the SDK as sdk. NewServer checks the
target and starts nothing.
mcp.AssumeResponseCommit: say a transport writes each response at once
Standard input and output are known to deliver each response as soon as the
write returns. Wrap any other transport in
AssumeResponseCommit, as the block does for the
in-memory one.
Close the instance when you have finished serving. The reference has the rest of what an embedder is held to, and the contract has the full text.
Packages
mcp: the server as a library
mcp.Run and mcp.NewServer serve a tmux server
to a client. Reference: pkg.go.dev
and libtmux.org.
libtmux-mcp: the command a client launches
It serves one tmux server over stdin and stdout. Reference: pkg.go.dev and the command README.
What it leaves out
- A second tmux server. The server serves one tmux server for the life of the process, and a client cannot name another socket in a call.
- Anything but tools. There is one resource, and no prompts, resource templates, completions, or background job handles.
- Confinement. Toolsets shape what a client is offered. Every call runs
with your user's authority, so a client holding
send_keyscan run anything you can. - The Python server's per-call socket. The socket is chosen once, at launch. PARITY.md lists the other differences.
Support and status
- Go 1.26+ and tmux 3.3a or newer. The server refuses an older tmux before the MCP transport starts. CI runs tmux 3.3a and 3.8 on each push, and tmux 3.3a through 3.8 for each release.
- Linux, including WSL, and macOS. CI runs this module's tests on Linux against the same releases. macOS is supported on a best-effort basis, and CI coverage for it is highly limited.
- A module of its own.
go geton the tmux library never pulls in the MCP SDK. - Tagged as
mcp/vN. Pin an exact version in your owngo.mod; the commands here fetch the newest.
See also
来源:mcp/README.md,提交 41bc2a3
工具
0版本历史
1- v0.0.1-alpha.4最新Sep 16, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分