pty-mcp
讓 AI Agent 擁有真正的互動式終端——本地 shell、SSH、serial port、持久化 session,一個 MCP server 全部搞定。
解決什麼問題?
所有 AI coding agent(Claude Code、Cursor、Copilot)都跑在 non-interactive shell 裡。這表示它們不能:
不能互動
無法對正在執行的程式送 stdin、ctrl+c。程式跑飛了只能等 timeout。
不能用 REPL
python3、node、psql 這類互動式環境完全無法操作。
不能保持狀態
每次指令都是新 shell。cd 換目錄、export 設變數,下一次指令全部消失。
不能斷線重連
SSH 到遠端跑長任務,斷線就沒了。無法回去看結果。
pty-mcp 給 AI agent 一個真正的 PTY session,以上問題全部解決:
完整互動
送 ctrl+c、ctrl+d、方向鍵、tab,操作任何終端程式。
REPL 支援
啟動 python3,送程式碼,讀輸出,送 ctrl+d 退出。完整流程。
Session 狀態
cd、export、alias 持續生效。跟你自己開 terminal 一樣。
持久化 + 重連
透過 ai-tmux daemon,SSH session 斷線後繼續執行,隨時重連看結果。
架構
版本演進
v0.11.0:AI-native PAM — 憑證透過 HPKE 密封通道注入 PTY,明文不進 LLM
v0.11.0 整合 cred-mcp 的 HPKE 密封傳遞協議,讓 AI 可以在完全不接觸明文的情況下完成需要密碼的操作。整個流程只有密文在 LLM context 中流通。
get_credential_bundle(新工具)
生成簽名的 ConsumerBundle:Ed25519 identity key + ephemeral X25519 session key。AI 將此 bundle 傳給 cred-mcp,cred-mcp 用它封裝憑證後回傳 SealedBox。明文從不出現。
inject_secret(新工具)
接收 cred-mcp 回傳的 SealedBox,在本地 HPKE 解密後直接以 WriteRaw 寫入 PTY,記憶體清零。只回傳 {"success":true},AI 永遠看不到明文。
Session key 單次使用
每個 session_id 的 session key 只能使用一次。第二次呼叫 inject_secret 使用同一 session_id 必定報錯,防止重放攻擊。
Credential Audit Log
bundle_generated、secret_injected、inject_failed 事件都送進 audit collector;不含明文、密文、encapped key 或私鑰材料。
v0.10.0:resize_session、Audit Log 脫敏、Remote Session 全面修正
v0.10.0 補齊 Remote Session 的三個長期缺陷,並新增終端視窗調整與 Audit Log 憑證脫敏功能。
resize_session(新工具)
調整終端視窗大小(rows / cols),支援本地、SSH、serial、持久化四種 session 類型。列數上限 1000、行數上限 500,防止 uint16 wrap-around。
Audit Log 憑證脫敏
send_input 的指令與輸出在寫入稽核日誌前自動掃描:password=、token=、api_key=、Authorization: Bearer/Basic/Token 標頭、PEM private key 區塊一律替換為 [REDACTED],稽核日誌不再有洩漏風險。
Remote Session 三項修正
send_input(wait_for=...) 在持久化 session 上提前返回的問題已修正;send_control 的輸出不再丟失;raw=true 的非控制字元現在透過新的 send_raw protocol 傳送,不再多附一個 \r。
ai-tmux 版本檢查
建立遠端持久化 session 前,自動驗證遠端主機上的 ai-tmux --version;binary 不存在或版本低於 0.9.0 時立即回傳明確錯誤,fail closed 設計,不靜默降級。
v0.9.1:修正 PowerShell PTY 在 macOS 上的亂碼問題
v0.9.1 修正 create_local_session 啟動 pwsh 時,含有 $true、$false、~ 或 Unicode 字元的指令會輸出 d@@@@: The term ... is not recognized 亂碼的問題。
根本原因:PSReadLine 會發送 ESC[6n 游標位置查詢,pty-mcp 未回應導致渲染偏移,產生 StripANSI 無法處理的損壞序列。修正方式:讀取 goroutine 攔截 ESC[6n 並回應 ESC[1;1R,同時在 pwsh 啟動時注入 Remove-Module PSReadLine,並停用 $PSStyle.Progress OSC indicator。
v0.9.0:prepare_secret — 預先準備密碼,自動在對的時機送出
v0.9.0 解決 serial console 和某些 CLI 裝置的密碼時序問題:密碼輸入對話框太慢,登入提示已過,造成靜默失敗。prepare_secret 讓操作者提前輸入密碼並暫存在 session 中,偵測到 password_prompt 時自動送出,不再與設備時序賽跑。
預先暫存密碼
呼叫 prepare_secret 時立即彈出對話框,密碼暫存在 session。後續的 send_secret 直接用暫存,不等人工輸入。
自動偵測送出
開啟 auto_send: true,session 偵測到 password_prompt 狀態時自動送出密碼,搭配 settle detection 確認完成。
line_ending 控制
新增 line_ending 參數(\r / \r\n / \n),由 agent 依裝置需求選擇,修正 serial 裝置的空密碼問題。
仍然不進 log
和 send_secret 相同,prepare_secret 暫存和送出的密碼永遠不出現在 Audit Log。
v0.8.0:Audit Log — 完整記錄 AI Agent 的每一個操作
v0.8.0 新增稽核日誌(Audit Log)功能,讓你知道 AI agent 在終端裡做了什麼、得到了什麼回應。適合合規要求、安全審查、以及排查 AI 操作問題。
內建 Log 收集器
pty-mcp audit serve 啟動一個 HTTP JSONL 日誌收集伺服器。每次 send_input 都會產生兩筆記錄:執行前(指令)+ 執行後(輸出),完整還原操作流程。
send_secret 永不記錄
密碼輸入 send_secret 在設計上永遠不進入 audit log。稽核記錄裡只有指令和輸出,密碼本體不會出現。
一鍵初始化與開關
pty-mcp audit init 自動生成含隨機 token 的設定檔(chmod 600)。audit enable / audit disable 可隨時切換,停用時設定保留,重啟不需要重新設定。
strict / best-effort 模式
strict 模式:若 audit 失敗,操作中止(合規環境)。best-effort 模式:audit 失敗時繼續執行,不阻斷工作流。
v0.7.0:send_input 整合 wait_for + Log 輪轉
v0.7.0 讓最常見的「送指令、等結果」操作從兩個 tool call 縮減成一個,同時修正 prompt 匹配的長期問題,並加入 Log 輪轉支援。
send_input 內建 wait_for
send_input 新增 wait_for / wait_for_timeout 參數,可以在同一個 tool call 裡完成送指令+等待 pattern 出現。減少 AI agent 的往返次數,也讓意圖更清晰。
Prompt 匹配修正 + timed_out 欄位
修正 wait_for 無法匹配沒有 trailing newline 的提示字元的問題(如 console>、#),這類 pattern 現在能立即匹配。回傳結果新增 timed_out 欄位,agent 不需 parse 錯誤字串就能判斷是否逾時。
Log 輪轉(Log Rotation)
所有 create_*_session 工具新增 log_max_size / log_max_files 參數。搭配 log_file,長時間任務的 log 檔不會無限增長,按大小自動切檔並保留最近 N 個。
list_remote_sessions 狀態過濾
list_remote_sessions 新增 status 參數,可在 client 端過濾只列出特定狀態的持久化 session,減少不必要的資訊量。
v0.7.1 / v0.7.2:穩定性與安裝修正
v0.7.1 修正 Gemini 2.5 Pro 和 OpenAI Codex 代碼審查發現的問題:Log 輪轉的執行緒安全(sync.Mutex 保護)、逾時不覆蓋輸出(保留供後續 read_output 讀取)。v0.7.2 修正 install.sh 在 SessionStart hook 環境下的靜默失敗問題,包含 curl 超時設定、checksum 驗證修正,以及 hook 超時從 30 秒延長至 60 秒。
v0.6.0:Prompt Classifier + Raw Input
v0.6.0 讓 AI agent 能判斷「終端現在在等什麼」,不再需要靠猜測或固定 pattern 判斷狀態。
Prompt Classifier
新的 classifier.go 分析最後 2KB 輸出,自動判斷終端狀態:at_prompt(等指令)、password_prompt(等密碼)、confirmation(yes/no)、pager(less/more)、running(執行中)、unknown。
get_session_state 增強
現在回傳 state、awaiting_secret、last_prompt。AI agent 可以直接問「這個 session 在幹嘛」,不需要 parse 原始輸出。
Raw Input Mode
send_input 新增 raw=true 參數,不自動附加換行。修正 Sophos、router CLI、BIOS 單字符選單的操作問題。
Cursor Boundary Tracking
send_input 回傳 cursor_start/cursor_end,精確標記指令輸出的邊界範圍。
v0.5.0:分塊讀取 + Log 落盤
解決長輸出截斷和長時間 session 的 observability 問題。
分塊讀取(Chunked Read)
read_output 新增 max_bytes 參數。has_more=true 表示還有未讀資料,再次呼叫取下一塊,直到 has_more=false。cursor 追蹤實際已讀位置。
Log 落盤(log_file)
建立 session 時加 log_file 參數,所有 PTY 輸出同步寫入指定檔案。適合長時間的建置、部署任務,留下完整記錄。
Buffer 擴大
預設 Ring Buffer 從 256KB 提升至 1MB,最大上限從 4MB 提升至 32MB。長輸出不再被意外截斷。
Cursor 語義修正
ReadSinceMax 的 cursor 現在夾緊到實際已寫位置,防止無效的 cursor 值。
v0.4.0:Cursor 讀取 + 結構化錯誤 + get_session_state
v0.4.0 讓 AI agent 的讀取操作更精確,錯誤處理更可靠。
get_session_state(新工具)
回傳 session type、target host、is_alive、buffer cursor、建立時間和最後活動時間。AI agent 可以不讀輸出就知道 session 的狀態。
Cursor-based 增量讀取
read_output 的 since_cursor 參數:只讀上次讀取後的新輸出,避免重複處理已看過的資料。所有回應都附帶 cursor 位置。
結構化錯誤碼
錯誤從純文字改為 { code, message, retryable }。SESSION_NOT_FOUND、SSH_AUTH_FAILED 等錯誤碼讓 AI agent 可以程式化處理,而非 parse 錯誤字串。
向後相容
所有改動向後相容,舊版 client 忽略新欄位即可,無需修改現有整合。
v0.3.0 / v0.3.1:send_secret + 安全加固
v0.3.0 解決了 AI agent 輸入密碼的核心困境:要怎麼讓 agent 輸入密碼,但又不讓它「看到」密碼?
send_secret:密碼不經 AI
呼叫 send_secret 時,系統向人類操作者彈出原生密碼輸入對話框,密碼直接送入 PTY。AI 只收到 {"success": true, "length": N},永遠看不到密碼本體。
跨平台支援
macOS 用 osascript(原生密碼對話框),WSL2 用 PowerShell Get-Credential(Windows GUI),Linux 有 display 用 zenity/kdialog,無 display 用 /dev/tty fallback。
v0.3.1 安全加固
修正 AppleScript/PowerShell/zenity injection 漏洞,session 數量限制(pty-mcp 50、ai-tmux 100),session ID 升級為 crypto/rand,serial device path 白名單驗證,安裝腳本加入 SHA256 校驗。
TOCTOU 修正
Unix socket 建立前呼叫 syscall.Umask 修正競爭條件,known_hosts 缺失時明確報錯(不再靜默 fallback)。
v0.2.x:wait_for + Ring Buffer + Bug Fixes
v0.2.0 的核心改進:AI agent 不再需要輪詢。v0.2.1/v0.2.2 修正了實戰中發現的邊界問題。
之前(v0.1.0)
現在(v0.2.0)
Pattern Matching 引擎
支援 regex + plain text fallback,自動 strip ANSI escape codes,處理不完整的行。
Ring Buffer(256KB)
取代無上限的 bytes.Buffer。長時間 session(tail -f、SSH)不會記憶體爆炸。可透過 PTY_MCP_BUFFER_SIZE 調整。
Channel-based Signaling
用 chan struct{} 做 context-aware blocking,不是 sleep 輪詢。精確、高效、可取消。
SSH 遠端也支援
PollRemote 讓 wait_for 跨 SSH 連線也能用,持久化 session 同樣受惠。
v0.2.1 / v0.2.2 Bug Fixes
用 telehack 和 PTT BBS 實測後修正的邊界問題:
\r取代\n— Enter 鍵改送 carriage return,修正 telnet/BBS 指令不執行的問題- wait_for 不再匹配舊資料 — pattern matching 從上次讀取位置開始掃,不是從頭
- read_output 不再空回傳 — 等待實際輸出,不會 300ms 沒東西就以為穩定
- AdvanceMarkBy race fix — WaitForSettle 和 Mark 之間的競爭條件,防止資料丟失
- wait_for 連續呼叫修正(v0.2.3)— 完成 pattern match 後 advance mark 到當前位置,連續 wait_for 不再重複匹配舊輸出
實際使用場景
Sophos XG 防火牆
Sophos 的 SSH CLI 不是傳統 shell——連上去之後是一個數字選單系統。每一層都要選號碼,子選單再選號碼,一直到你要的功能。AI agent 要能在這種環境裡自主導航,需要三個條件:
- 知道現在在哪一層(prompt classifier 分類為
confirmation或pager) - 送單字元不加換行(
raw=true,否則選單不動) - 等選單刷新後再讀(wait_for 等到下一個
Select Menu Number)
Aruba 515 存取點
Aruba AP 的 CLI 是標準 shell 風格,SSH 後直接進入指令模式。常見需求:批次確認多個 AP 的關聯狀態、調整 radio 設定、撈取 debug log。搭配持久化 session,可以讓 AI 在背景跑完整個機房巡查,人不用守著。
若要批次巡查多台 AP,AI agent 可以循環建立 session、執行相同指令、匯整回傳結果,全程不需要人在旁邊監看。
Linux 伺服器維運
最常見的場景:SSH 到遠端跑長時間任務,中途斷線不影響結果,稍後重連看輸出。
MCP Tools
| Tool | 說明 |
|---|---|
| create_local_session | 啟動本地互動式終端(bash、python3、node 等),可指定 log_file / log_max_size / log_max_files |
| create_ssh_session | SSH 到遠端主機(支援 SSH config aliases),可指定 log_file / log_max_size / log_max_files |
| create_serial_session | 連接 serial port 裝置(IoT、embedded、網路設備),可指定 log_file / log_max_size / log_max_files |
| send_input | 送指令,等輸出穩定後回傳;raw=true 跳過換行;wait_for/wait_for_timeout 合併等待(v0.7.0);回傳 cursor_start/cursor_end,逾時時附 timed_out |
| read_output | 讀取輸出;wait_for 等待 pattern(regex、timeout、context_lines);since_cursor 增量讀取;max_bytes 分塊讀取(has_more) |
| send_secret | 向操作者彈出原生密碼對話框,密碼直送 PTY,AI 看不到密碼本體 |
| prepare_secret | 預先彈出對話框暫存密碼;auto_send: true 偵測到 password_prompt 時自動送出;line_ending 控制換行符(v0.9.0) |
| get_session_state | 回傳 session 狀態(type、is_alive、cursor、state 分類、last_prompt) |
| resize_session | 調整終端視窗大小(rows / cols),支援所有 session 類型;上限 500 rows / 1000 cols(v0.10.0) |
| get_credential_bundle | 生成 HPKE ConsumerBundle(Ed25519 + X25519),傳給 cred-mcp 封裝憑證用;明文不進 LLM(v0.11.0) |
| inject_secret | 接收 cred-mcp 的 SealedBox,HPKE 解密後直接寫入 PTY,記憶體清零;只回傳 {"success":true}(v0.11.0) |
| send_control | 送控制鍵(ctrl+c、ctrl+d、方向鍵、tab、escape) |
| list_sessions | 列出所有活躍的 session |
| close_session | 關閉 session(終止遠端 PTY) |
| detach_session | 斷開連接,但保持遠端 PTY 繼續執行 |
| list_remote_sessions | 列出遠端主機上的持久化 session;status 參數可過濾特定狀態(v0.7.0) |
更多 wait_for 使用場景
ai-tmux:持久化終端 Daemon
ai-tmux 是專為 AI agent 設計的輕量級 daemon,在遠端 server 上保持 PTY session 存活。概念類似 tmux,但為 AI agent 的使用模式重新設計:
- ai-tmux server — daemon 模式,監聽 Unix socket,管理 PTY session
- ai-tmux client — bridge 模式,透過 stdin/stdout 轉發 JSON protocol(pty-mcp 經 SSH 呼叫)
- 自動啟動 — pty-mcp 連線時若 daemon 未啟動,自動拉起
- 30 分鐘閒置自動清理 — 不會殘留無用 session
使用場景
安裝
實測過的環境:macOS、WSL、Linux + KDE Plasma。其餘平台有提供 binary,但沒有實機驗證過——GUI 密碼對話框會因桌面環境而異(KDE 走 kdialog、GNOME 走 zenity)。
技術選擇
- Go — 編譯成單一 binary,跨平台部署零依賴。PTY、SSH、serial port 都有成熟的 Go library
- MCP(Model Context Protocol) — Anthropic 主導的標準協議,所有支援 MCP 的 AI agent 都能直接使用
- Unix socket 通訊 — ai-tmux daemon 用 Unix socket 而非 TCP,安全且效能好
- Settle detection — 送完指令後自動偵測輸出是否穩定,不需要手動 sleep 猜等待時間
為什麼不直接用 tmux?
tmux 是為人設計的——它假設有一個人坐在終端前操作。AI agent 需要的是:
- JSON protocol 而非 terminal escape sequences
- 程式化建立 / 關閉 / 列出 session
- 自動 settle detection(知道什麼時候輸出完了)
- 閒置自動清理(不留殭屍 session)
ai-tmux 從頭為這些需求設計,比嵌套 tmux 乾淨很多。