tmux-repl-mcp
An MCP server for interacting with a REPL running inside a tmux pane.
With it running, you might say something like the following to your AI:
I have a Lisp REPL running in the other pane (pane 0) of the current window we're in (window 6). Please debug the function we're writing together using that REPL.
It works with way more than just Lisp -- Python shell, Ruby irb, and Goose itself are all supported. Additional types of REPLs may be specified via environment variable.
Use it with Goose, Cursor, or any other MCP client.
But Why
I was working with my AI to interact with another tmux pane, and it could do it via CLI commands, but it doesn't know how to just get the output of the last command it run. Indeed, tmux doesn't support this directly. You have to ask it for the last e.g. 5000 lines or whatever, hoping that window has your output. But this poisons the context with too many tokens, and it has no mechanism for waiting until the command is finished. You just have to keep sleeping and checking, sleeping and checking. With this tool, I can now send commands to a running REPL and read back the output with perfect timing — no more guessing how long to sleep, no more context poisoning, no more "wait, 1000 lines wasn't enough" nonsense.
Features
| Tool | Description |
|---|---|
is_repl_ready |
Check whether the pane is showing a known REPL prompt |
get_last_command |
Read the last command and its output from the pane history |
execute_command |
Send a command, wait for the REPL to finish, return output |
Quick start
uvx tmux-repl-mcp
Goose configuration
extensions:
tmux-repl-mcp:
type: stdio
cmd: uvx
args:
- tmux-repl-mcp
enabled: true
Tools
is_repl_ready
is_repl_ready(pane="0", max_lines=50)
Returns {"kind": "<kind>"} if a known REPL prompt is detected on the last
non-empty line of the pane, or {"kind": null} if the pane is busy or shows
an unrecognised prompt.
get_last_command
get_last_command(kind, pane="0", max_lines=200)
Looks back through up to max_lines lines of the pane history for a complete
prompt→command→output→prompt block and returns:
{"last_command": "...", "output": "..."}
Both values are null when no complete block is found or the REPL is still
running.
execute_command
execute_command(command, kind, pane="0", max_lines=200, check=2.0)
- Verifies the REPL is ready and of the expected
kind. - Sends
commandto the pane viatmux send-keys. - Waits (polling every
checkseconds) until the REPL prompt reappears. - Returns
{"status": "ok", "last_command": "...", "output": "..."}.
REPL kinds
The following kinds are built-in:
| Kind | Prompt pattern |
|---|---|
python |
^>>> |
ipython |
^In \[\d+\]: |
bash |
[\$\#]\s*$ |
zsh |
[\$\#%]\s*$ |
sh |
[\$\#]\s*$ |
lisp |
^\*\s*$ / ^…>\s*$ / ^\d+\]\s*$ |
sbcl |
^\*\s*$ / ^\d+\]\s*$ |
node |
^> |
irb |
^irb\(.*\):\d+:\d+> $ |
iex |
^iex\(\d+\)> $ |
Adding custom kinds
Set the TMUX_REPL_KINDS environment variable to a JSON object:
export TMUX_REPL_KINDS='{"myrepl": "^myrepl> "}'
Entries here are merged on top of the built-in defaults, so existing kinds can also be overridden.
Development
# Install dev dependencies
uv sync --dev
# Run tests
uv run pytest -v
Goose permission tips
Because is_repl_ready and get_last_command only read tmux state, they are
safe to mark as Always Allow in Goose. Reserve Ask User for
execute_command since it writes to your REPL.
Metadata
Release files for tmux-repl-mcp 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tmux_repl_mcp-0.1.0.tar.gz | 6.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tmux_repl_mcp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 15.3 kB
Release files / tmux_repl_mcp-0.1.0.tar.gz
| Download URL | tmux_repl_mcp-0.1.0.tar.gz |
|---|---|
| Size | 6.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3e06e4e8af9252c58b56b1ef9869612362cc147320fb35bdd1db875e24040de9
|
|
BLAKE2b-256 checksum How to use checksums |
ce293f3ec24ee7b972fb89d4a197a1796d82596c7052ebfdda932a9f48e76919
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 11, 2026.
Transparency logRelease files / tmux_repl_mcp-0.1.0-py3-none-any.whl
| Download URL | tmux_repl_mcp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 8.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
77169ee095f74b43c4405fa4ed44e2564c94081f7f530d5a6cb9a3d27e8bdeb5
|
|
BLAKE2b-256 checksum How to use checksums |
8e32086b42061d3bdfd562981553a8b659ce78af35c7d32b20d8b02e57c71145
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 11, 2026.
Transparency log