This release is a pre-release and may not be stable for production use.
libtmux-mcp
A Model Context Protocol server for tmux, built on libtmux.
[!WARNING] Alpha. Releases carry an
-alphaprerelease tag. The API is not settled, and any release may change or remove exported identifiers without a deprecation period. Pin an exact version. Not recommended for production.
Give your AI agent hands inside the terminal — create sessions, run commands, read output, orchestrate panes.
Tools
| Module | Tools |
|---|---|
| Server | list_servers, list_sessions, create_session, kill_server, get_server_info |
| Batch | call_read_tools_batch |
| Session | list_windows, get_session_info, create_window, rename_session, select_window, kill_session |
| Window | list_panes, get_window_info, split_window, rename_window, select_layout, resize_window, move_window, kill_window |
| Pane | run_command, send_keys, send_keys_batch, paste_text, capture_pane, capture_since, snapshot_pane, search_panes, find_pane_by_position, get_pane_info, wait_for_text, wait_for_channel, signal_channel, display_message, select_pane, swap_pane, resize_pane, set_pane_title, clear_pane, pipe_pane, enter_copy_mode, exit_copy_mode, respawn_pane, kill_pane |
| Options | show_option, set_option |
| Environment | show_environment, set_environment |
| Buffers | load_buffer, paste_buffer, show_buffer, delete_buffer |
| Hooks | show_hooks, show_hook |
Quickstart
Requirements: Python 3.10+, tmux >= 3.2a on $PATH.
The distribution is libtmux-mcp, the import is libtmux_mcp, and the
installed executable is libtmux-mcp.
Install and run:
$ uvx libtmux-mcp
Claude Code
$ claude mcp add tmux -- uvx libtmux-mcp
Codex CLI
$ codex mcp add tmux -- uvx libtmux-mcp
Gemini CLI
$ gemini mcp add tmux uvx -- libtmux-mcp
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"tmux": {
"command": "uvx",
"args": ["libtmux-mcp"]
}
}
}
More clients and JSON config: client setup docs
What it feels like
You: Create a session called "api" and run
pytest tests/api/ -xin it.Agent: Created session
apiwith windowtests. Running pytest now. Here's the output — 14 passed, 2 failed. The failures are intest_auth.py::test_token_refreshandtest_auth.py::test_expired_session. Want me to open those files?
The agent manages tmux directly. No copy-pasting terminal output. No switching windows to check on long-running processes.
When the server earns its keep
For a single tmux send-keys, the server doesn't. It earns its keep
the moment the agent has to wait, inspect, or avoid damaging the
terminal it is using — pytest finishing, a dev server printing its
port, a deploy log settling. The difference then is not more access
to tmux, but a better place to put the control loop.
The server-side moves are:
Running. run_command
sends an authored shell command, waits for deterministic completion,
and returns exit status plus tail-preserved output as one typed value.
The command and its completion signal reach the shell as one
space-prefixed event, so best-effort
history suppression
keeps agent-generated input out of shell history by default. The
alternative — hand-rolled send-keys plus wait-for plus a pane
capture — leaves every typed command, signal included, in shell
history.
Driving. send_keys_batch
sends several ordered raw-input operations for TUIs and persistent
shell interaction. It is deliberately not a workflow DSL; command
completion stays in run_command, and repeated observation stays in
capture_since.
Waiting. wait_for_text
blocks inside the server until a condition fires for output the agent
does not author. The alternative is the model polling capture-pane
in a loop, paying both context tokens and round-trip latency for every
turn.
Reading. snapshot_pane
returns content, cursor, copy-mode state, and scroll offset as one
typed value. The alternative is several tmux invocations stitched
together with regex.
Observing. capture_since
returns a cursor with the current pane content, then returns only
newly written or rewritten rows on follow-up calls. The alternative is
re-sending the same scrollback to the model on every check.
Guarding. The server detects the agent's own pane across sockets
and declines to end its own — kill_session
on itself fails loudly instead of silently terminating the host
environment the agent is running in. LIBTMUX_TOOLSETS
(inspect, manage, execute, teardown) drops whole toolsets from the
client's tool list before any prompt is built. The sets are unordered, so
inspect,teardown is a legal surface. Dropping one is inventory and MCP
tool-call configuration, not containment: an enabled execute tool can type
the equivalent of anything it hides.
Documentation
Full docs, guides, and tool reference: libtmux-mcp.git-pull.com
Development
Clone and install:
$ git clone https://github.com/tmux-python/libtmux-mcp.git
$ cd libtmux-mcp
$ uv sync --all-extras --dev
Run the server locally:
$ uv run libtmux-mcp
Run tests:
$ uv run pytest
See CONTRIBUTING.md for the gates, and WRITING.md for how this project writes prose, docstrings, and MCP tool descriptions.
Related projects
- libtmux — Python API for tmux
- tmuxp — tmux session manager
- The Tao of tmux — the book
License
MIT
Release files for libtmux-mcp 0.1.0a22
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| libtmux_mcp-0.1.0a22.tar.gz | 828.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| libtmux_mcp-0.1.0a22-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 964.2 kB
Release files / libtmux_mcp-0.1.0a22.tar.gz
| Download URL | libtmux_mcp-0.1.0a22.tar.gz |
|---|---|
| Size | 828.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
67a2491f9c3d414bfc088a811bfbae668436869e0cf2d482d7c7c9a885409e7c
|
|
BLAKE2b-256 checksum How to use checksums |
2db6c337d02086265f712500d6fcc5b2cdc4700cddbcb0ac6b33d6d6ab4466c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.
Transparency logRelease files / libtmux_mcp-0.1.0a22-py3-none-any.whl
| Download URL | libtmux_mcp-0.1.0a22-py3-none-any.whl |
|---|---|
| Size | 136.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
152a4881e5f7dd7a70321bc74cdb216c4a41dfaa60cb60c57d960e71a7a9ae75
|
|
BLAKE2b-256 checksum How to use checksums |
dd6ada01c68a4c0bffbc6fed836c193274163c8b5174d14f8f3811f1907b2bd1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.
Transparency log