Migration notes¶
Migration and deprecation notes for libtmux-mcp are here, see Changelog for the full release log.
Welcome on board! 👋
📌 For safety, always pin the package version in your install
📖 Check the migration notes (You are here)
📣 If a deprecation interrupted you - past, present, or future - voice your opinion on the tracker.
We want to make libtmux-mcp fun, reliable, and useful for users.
API changes can be painful.
If we can do something to draw the sting, we’ll do it. We’re taking a balanced approach. That’s why these notes are here!
(Please pin the package. 🙏)
libtmux-mcp 0.1.0a21 (2026-08-30)¶
LIBTMUX_SAFETY now crashes the server on load¶
readonly, mutating and destructive are gone. Tools belong to four
unordered toolsets named for what they do.
A server started with LIBTMUX_SAFETY still set raises while the module
loads, before it serves a request. Every value crashes, the former default
mutating included. Your MCP client reports a server that failed to start;
the message naming the replacement goes to the process’s stderr, so read the
client’s server log if the failure looks silent.
The variable is not ignored, and that is deliberate: one that silently stopped working would leave you believing a surface was narrower than it is.
The new default names no environment variables¶
An unset LIBTMUX_TOOLSETS selects inspect,manage,execute — the surface
mutating gave you. If you were on the old default, delete LIBTMUX_SAFETY
from your client config and put nothing in its place:
{
"mcpServers": {
"tmux": {
"command": "uvx",
"args": ["libtmux-mcp"]
}
}
}
Name a variable only to move off that default.
Environment variables¶
Before |
After |
|---|---|
|
|
|
nothing — the default is |
|
|
Two variables are new. LIBTMUX_TOOLS enables individual tools
regardless of toolset, and LIBTMUX_EXCLUDE_TOOLS refuses them
regardless of every
enable above. An unknown name in any of the three fails startup the same way.
Surfaces the tiers could not express¶
The tiers accumulated upward, so every surface was a prefix of the ladder. The toolsets are a set, so this is now legal:
$ LIBTMUX_TOOLSETS=inspect,teardown libtmux-mcp
An agent that can look and clean up, but not type.
Tool names¶
Before |
After |
|---|---|
|
|
|
removed — call the tool directly |
|
removed — call the tool directly |
A batch gives every nested call the wrapper’s name, so a client rule keyed
on kill_session never fires for a kill_session run inside one. That is
tolerable for reads and not for writes.
Which toolset a tool is in¶
inspect
: Every list_*, get_*, show_*, capture_*, snapshot_pane,
search_panes, find_pane_by_position,
display_message, wait_for_text,
call_read_tools_batch.
manage
: rename_*, select_*, resize_*, move_window,
swap_pane, set_pane_title, enter_copy_mode,
exit_copy_mode, wait_for_channel,
signal_channel, load_buffer.
execute
: create_session, create_window,
split_window, respawn_pane, run_command,
send_keys, send_keys_batch, paste_text,
paste_buffer, pipe_pane, set_option,
set_environment.
set_option and set_environment are here rather than in manage
because tmux runs some stored values later: a #(...) job in a status
format runs when tmux draws it and repeats on the status interval, and
default-command decides what every future pane runs.
teardown
: kill_pane, kill_window, kill_session,
kill_server, clear_pane, delete_buffer.
Documentation¶
The safety topic is now the Trust model page. The old URL redirects.
MCP annotations¶
Every tool that requests a tmux operation now explicitly advertises
readOnlyHint: false,
destructiveHint: true, idempotentHint: false, and openWorldHint: true.
An existing tmux server can use aliases and hooks to replace or extend the
operation libtmux-mcp requests, so no stronger static promise holds for every
target. The optional prompt adapter tools render text without contacting tmux
and retain their narrower hints. Use the project-owned toolsets to distinguish
the direct operation libtmux-mcp requests.
libtmux-mcp 0.1.0a19 (2026-07-25)¶
wait_for_text takes patterns, and wait_for_content_change is gone¶
wait_for_text accepted a single pattern string. It now takes patterns, a
list — or null to wait for any new output at all. The schema rejects the old
argument rather than silently ignoring it, so a call written against the old
signature fails loudly with Remove or correct the unrecognized argument(s): pattern.
Before¶
{"tool": "wait_for_text", "arguments": {"pane_id": "%1", "pattern": "ready"}}
After¶
{"tool": "wait_for_text", "arguments": {"pane_id": "%1", "patterns": ["ready"]}}
wait_for_content_change and its ContentChangeResult are removed. Pass
patterns: null instead — it waits for any new output and additionally
excludes pre-existing scrollback and stale paint from the change predicate,
which the old tool did not.
{"tool": "wait_for_text", "arguments": {"pane_id": "%1", "patterns": null}}
Waits are capped by the server¶
wait_for_text, wait_for_channel, and
run_command are all bounded by
LIBTMUX_MCP_WAIT_MAX_SECONDS (30 seconds by default, clamped to [1, 120]).
An over-large timeout is clamped, not rejected — the call succeeds and
reports the value actually enforced, so read effective_timeout rather than
assuming your value was honoured. A wait that previously blocked for an hour
now returns at the ceiling.
Raise the ceiling with the environment variable if your workload needs it, or call again — the command keeps running in the pane between calls.
WaitForTextResult reports an outcome¶
The result’s loose booleans are replaced by one outcome field taking
matched, any_output, stopped, alternate_screen, or timeout.
risk_band_warned is removed; the history-limit trim signal is delivered as an
MCP warning notification instead. Clients that cannot surface notifications
should compose tmux wait-for -S into the command and use
wait_for_channel,
which does not read the pane at all.
Self-bounded tools cannot be batched¶
run_command, wait_for_text, and
wait_for_channel are rejected by the
batch wrappers per operation, because batching one multiplied the wait ceiling
by the operation count. Use send_keys_batch for command sequences, or call
the tool directly.
libtmux-mcp 0.1.0a6 (2026-05-09)¶
Recommended registration slug: libtmux → tmux¶
Earlier docs and install widgets recommended registering the server as
libtmux. From 0.1.0a6 onward the recommended slug is tmux, matching
the value of serverInfo.name returned in the MCP handshake and the
mcp__tmux__* tool prefix that clients namespace tool calls under.
Existing installations continue to work. The slug is a per-install
user choice — your client looks up the server by whatever name you
registered. Migration is optional; it only matters if you want the new
tmux prefix on tool calls. Claude Code’s claude mcp remove <name>
auto-detects the registration scope (verified against
claude --version 2.1.138), so the commands below work whether you
originally registered at local, user, or project scope.
Before¶
$ claude mcp add libtmux -- uvx libtmux-mcp
→ tools surface as mcp__libtmux__list_panes, mcp__libtmux__send_keys, …
After¶
$ claude mcp remove libtmux
$ claude mcp add tmux -- uvx libtmux-mcp
→ tools surface as mcp__tmux__list_panes, mcp__tmux__send_keys, …
What’s unchanged¶
PyPI package name:
libtmux-mcpPython module:
libtmux_mcpGitHub repository: https://github.com/tmux-python/libtmux-mcp
Existing
mcp__libtmux__*references in CLAUDE.md / AGENTS.md templates and agent histories continue to work if you keep thelibtmuxslug.