通用的MCP(模型上下文协议)服务器,用于双向tmux终端交互。
使AI助手(如Claude Code)能够读取并可选地写入tmux终端面板,创建一个共享的终端会话视图。
\n → 回车键转换自然书写命令!write_tmux_pane("ls\n") 自动按下回车键。
可选提示检测防止在用户输入时写入:
write_tmux_pane(session="work", text="ls\n", wait_for_prompt=True)
阻塞命令执行并自动完成检测:
execute_and_wait(session="work", command="git clone ...", timeout=30)
# 当提示符重新出现或超时时返回
get_pane_info() 现在包括:
prompt_detected: Shell是否准备好接收输入?command_running: 是否有命令正在执行?last_line: 面板当前的最后一行获取面板的所有内容(而不仅仅是差异):
read_tmux_pane(session="work", force_full_read=True)
读取(默认,安全):
写入(可选,需要显式配置):
\n → 回车键转换┌─────────────────────────────────────────────┐
│ Claude Code (MCP 客户端) │
│ - 通过MCP读取终端缓冲区 │
│ - 可选地发送命令 │
└─────────────────┬───────────────────────────┘
│ JSON-RPC通过标准输入输出
┌─────────────────┴───────────────────────────┐
│ MCP Tmux Server (Python) │
│ - MCP协议处理器 │
│ - 缓冲管理器(差异跟踪) │
│ - Tmux阅读器(捕获面板) │
└─────────────────┬───────────────────────────┘
│ tmux命令
┌─────────────────┴───────────────────────────┐
│ Tmux会话 │
│ - 用户的终端窗口 │
│ - 共享视图:用户看到 + AI读取 │
└─────────────────────────────────────────────┘
read_tmux_pane描述: 从tmux面板读取自上次读取以来的新内容 参数:
session (字符串,必需) - tmux会话名称window (整数,默认值:0) - 窗口索引pane (整数,默认值:0) - 面板索引返回:
{
"target": "session:0.0",
"new_lines": ["line1", "line2", ...],
"total_lines": 150,
"timestamp": "2025-10-15T16:30:00"
}
备注: 读取后清除缓冲区。仅返回自上次调用以来的新行。
get_tmux_sessions描述: 列出所有活动的tmux会话 参数: 无
返回:
{
"sessions": [
{"name": "gm-robo", "windows": 3, "panes": 2},
{"name": "monitoring", "windows": 1, "panes": 2}
],
"count": 2
}
备注: 如果设置了allowed_sessions配置,则进行过滤。
get_pane_info描述: 获取特定面板的详细信息 参数:
session (字符串,必需)window (整数,默认值:0)pane (整数,默认值:0)返回:
{
"target": "session:0.0",
"width": 120,
"height": 40,
"current_command": "./monitor_diarization.sh",
"active": true
}
clear_buffer描述: 手动清除面板的缓冲区 参数:
target (字符串,可选) - 特定目标,如"session:0.0",或省略以清除所有返回:
{"cleared": "session:0.0"}
get_server_info描述: 获取服务器版本和功能 参数: 无
返回:
{
"version": "1.0.0",
"write_enabled": false,
"tmux_available": true,
"config_path": "/home/user/.config/mcp-tmux/config.json",
"buffer_count": 3
}
write_tmux_pane (可选,需要write_enabled: true)描述: 向tmux面板发送文本(就像打字一样) 参数:
session (字符串,必需)window (整数,默认值:0)pane (整数,默认值:0)text (字符串,必需) - 要发送的文本(使用\n表示回车键)返回:
{
"target": "session:0.0",
"sent": "ls -la\n",
"timestamp": "2025-10-15T16:30:00"
}
安全性: 需要在配置中设置write_enabled: true。建议使用命令白名单。
send_keys_tmux (可选,需要write_enabled: true)描述: 向tmux面板发送特殊键/键盘快捷键 参数:
session (字符串,必需)window (整数,默认值:0)pane (整数,默认值:0)key (字符串,必需) - 特殊键或键组合支持的键:
C-c (Ctrl+C),C-u (清除行),C-k,C-w,C-a,C-e,C-l,C-d,C-zEnter,Escape,Tab,BSpace (退格),SpaceUp,Down,Left,RightF1到F12返回:
{
"target": "session:0.0",
"key": "C-u",
"timestamp": "2025-10-15T16:30:00"
}
示例:
# 清除当前命令行
send_keys_tmux(session="work", key="C-u")
# 中断正在运行的过程
send_keys_tmux(session="work", key="C-c")
# 清屏
send_keys_tmux(session="work", key="C-l")
# 导航历史记录
send_keys_tmux(session="work", key="Up")
安全性: 需要在配置中设置write_enabled: true。
# 在~/workplace克隆/创建
cd ~/workplace/mcp-tmux-server
# 安装依赖项
pip install -r requirements.txt
# 运行服务器(JSON-RPC通过标准输入输出)
python3 src/mcp_server.py
位置: ~/.config/mcp-tmux/config.json
默认配置(自动创建):
{
"version": "1.0.0",
"write_enabled": false,
"allowed_sessions": [],
"buffer_size": 1000,
"auth_token": null
}
选项:
write_enabled (布尔值) - 启用写入功能(默认值:false)allowed_sessions (数组) - 会话名称白名单(空 = 允许所有)buffer_size (整数) - 每个面板缓冲区的最大行数auth_token (字符串) - 写操作的身份验证令牌带有安全性的示例:
{
"version": "1.0.0",
"write_enabled": true,
"allowed_sessions": ["gm-robo-monitor", "diarization"],
"buffer_size": 2000,
"auth_token": "your-secret-token-here"
}
# 开始tmux会话用于监控
tmux new -s gm-robo-monitor
# 运行你的程序
./monitor_diarization.sh
# 在另一个终端启动MCP服务器
cd ~/workplace/mcp-tmux-server
python3 src/mcp_server.py
添加到Claude Code的MCP配置(~/.config/claude-code/mcp.json):
{
"mcpServers": {
"tmux": {
"command": "python3",
"args": ["/home/zdendys/workplace/mcp-tmux-server/src/mcp_server.py"]
}
}
}
用户: "监控中发生了什么?"
Claude: [调用read_tmux_pane(session="gm-robo-monitor")]
"Worker 0 正在处理 dummy_2024-02-20_session_1.m4a 的95%"
mcp-tmux-server/
├── src/
│ ├── mcp_server.py # 主MCP协议处理器
│ ├── tmux_reader.py # Tmux命令包装器
│ ├── buffer_manager.py # 差异跟踪和缓冲区管理
│ └── __init__.py
├── config/
│ └── example_config.json # 示例配置
├── tests/
│ ├── test_tmux_reader.py
│ ├── test_buffer_manager.py
│ └── test_mcp_protocol.py
├── docs/
│ └── API.md # 详细的API文档
├── README.md # 本文件
├── CLAUDE.md # Claude Code在此项目上的规则
├── requirements.txt # Python依赖项
└── setup.py # 安装脚本
自动化测试(尚未实现):
# 运行所有测试
python3 -m pytest tests/ -v
# 运行特定测试
python3 -m pytest tests/test_buffer_manager.py -v
# 包含覆盖率
python3 -m pytest tests/ --cov=src --cov-report=html
手动测试检查清单:
tmux new -s testpython3 src/mcp_server.pyecho '{"jsonrpc":"2.0","id":1,"method":"get_server_info","params":{}}' | python3 src/mcp_server.py
echo '{"jsonrpc":"2.0","id":2,"method":"read_tmux_pane","params":{"session":"test"}}' | python3 src/mcp_server.pyMCPTmuxServer (mcp_server.py)
TmuxReader (tmux_reader.py)
capture_pane(),list_sessions(),get_pane_info(),send_keys()shell=True(安全性 - 总是数组参数)BufferManager (buffer_manager.py)
_find_new_lines()用户在tmux面板中输入
↓
AI调用read_tmux_pane(session="foo")
↓
MCPTmuxServer._read_tmux_pane()
↓
TmuxReader.capture_pane("foo:0.0") → List[str]
↓
BufferManager.get_new_lines("foo:0.0", current_lines)
├─ 与存储的缓冲区比较
├─ 查找新行(差异算法)
└─ 更新缓冲区以反映当前状态
↓
仅返回新行给AI
问题: 终端输出滚动和换行。如何找到仅有的新行?
解决方案(BufferManager._find_new_lines):
示例 - 简单追加:
旧缓冲区:["line1", "line2", "line3"]
新内容:["line1", "line2", "line3", "line4", "line5"]
结果:["line4", "line5"] # 仅返回新行
示例 - 滚动:
旧缓冲区:["line1", "line2", "line3"] # 终端显示最后3行中的50行
新内容:["line2", "line3", "line4"] # 向上滚动,line1消失
结果:["line4"] # 查找公共后缀(line2,line3),返回其后的内容
通信: 标准输入输出(标准输入/标准输出) 格式: JSON-RPC 2.0(每行一个请求)
请求格式:
{"jsonrpc":"2.0","id":1,"method":"read_tmux_pane","params":{"session":"foo"}}
成功响应:
{"jsonrpc":"2.0","id":1,"result":{"target":"foo:0.0","new_lines":["..."]}}
错误响应:
{"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"未找到会话"}}
重要事项:
JSON-RPC错误码:
-32700 解析错误-32600 无效请求-32601 方法未找到-32602 无效参数-32603 内部错误-32000 自定义错误(未找到tmux,未找到会话等)所有tmux操作优雅地处理错误: