← 返回作品集

pty-mcp

讓 AI Agent 擁有真正的互動式終端——本地 shell、SSH、serial port、持久化 session,一個 MCP server 全部搞定。

Go MCP PTY SSH Serial Port Open Source MIT License

解決什麼問題?

所有 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 斷線後繼續執行,隨時重連看結果。

架構

AI Agent(Claude Code, Cursor, etc.)
MCP Tools: create_local_session, send_input,
send_control, read_output, close_session
JSON-RPC stdio
pty-mcp(MCP Server)
├── LocalSession 本地 PTY(creack/pty)
├── SSHSession 遠端 PTY(x/crypto/ssh)
├── SerialSession Serial port(go.bug.st)
└── RemoteSession 持久化(ai-tmux daemon)
持久化模式:
pty-mcp ──SSH──▶ ai-tmux client ──Unix socket──▶ ai-tmux server
├── PTY: bash
├── PTY: ssh admin@router
└── PTY: tail -f /var/log/syslog

版本演進

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_generatedsecret_injectedinject_failed 事件都送進 audit collector;不含明文、密文、encapped key 或私鑰材料。

# AI 完成 SSH 登入,全程不接觸密碼明文
bundle = get_credential_bundle(session_id) → 生成公鑰 bundle
sealed = cred-mcp.vault_copy(item, bundle) → cred-mcp 封裝憑證
inject_secret(session_id, sealed) → 解密並寫入 PTY
→ {"success": true},AI 從未見過密碼

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 設計,不靜默降級。

# 調整終端視窗大小(例如讓 vim/htop 正確顯示)
resize_session(session_id, rows: 40, cols: 220)
→ { ok: true }
# Audit Log 脫敏:以下指令寫入日誌時密碼會變成 [REDACTED]
send_input(session_id, "mysql -u root -pS3cret123 mydb")
→ 日誌記錄:mysql -u root -p[REDACTED] mydb

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 失敗時繼續執行,不阻斷工作流。

# 初始化設定(自動生成 token,設定 chmod 600)
pty-mcp audit init
→ 建立 ~/.config/pty-mcp/config,顯示設定說明
# 啟動 log 收集器
pty-mcp audit serve --port 9090
→ 在本地或遠端伺服器上接收 JSONL 格式日誌
# 開啟稽核
pty-mcp audit enable
→ 啟用後,所有 send_input 操作都會送至 audit server
# 停用稽核(設定保留,可隨時重開)
pty-mcp audit disable

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.0 以前:兩個 tool call
send_input(session_id, "systemctl restart nginx")
read_output(session_id, wait_for: "Active:", timeout: 30)
# v0.7.0:一個 tool call 搞定
send_input(session_id, "systemctl restart nginx",
wait_for: "Active:", wait_for_timeout: 30)
→ { output: "...", timed_out: false, cursor: 1234 }
# Log 輪轉:超過 10MB 自動切檔,保留最近 5 個
create_ssh_session(host: "server", user: "admin",
log_file: "/tmp/deploy.log",
log_max_size: 10485760, log_max_files: 5)

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 增強

現在回傳 stateawaiting_secretlast_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,精確標記指令輸出的邊界範圍。

# AI agent 不需要 parse 輸出,直接問 terminal 狀態
get_session_state(session_id)
→ { state: "password_prompt", awaiting_secret: true, last_prompt: "sudo password:" }
# BIOS / 單字符選單:不加換行
send_input(session_id, "3", raw: true)
→ 直接送 "3",不附加 \r

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 值。

# 分塊讀取大型輸出
read_output(session_id, max_bytes: 4096)
→ { output: "...", cursor: 4096, has_more: true }
read_output(session_id, since_cursor: 4096, max_bytes: 4096)
→ { output: "...", cursor: 8192, has_more: false }
# 建立 session 同時落盤
create_ssh_session(host: "server", user: "admin", log_file: "/tmp/deploy.log")
→ 所有輸出同步寫入 /tmp/deploy.log

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_outputsince_cursor 參數:只讀上次讀取後的新輸出,避免重複處理已看過的資料。所有回應都附帶 cursor 位置。

結構化錯誤碼

錯誤從純文字改為 { code, message, retryable }SESSION_NOT_FOUNDSSH_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)。

# sudo 需要密碼:AI 送指令,人類輸入密碼
send_input(session_id, "sudo apt upgrade")
→ terminal 顯示 "[sudo] password:"
send_secret(session_id)
→ 彈出原生密碼對話框給操作者
→ AI 收到: { "success": true, "length": 12 }
→ 密碼內容對 AI 永久不可見

v0.2.x:wait_for + Ring Buffer + Bug Fixes

v0.2.0 的核心改進:AI agent 不再需要輪詢。v0.2.1/v0.2.2 修正了實戰中發現的邊界問題。

之前(v0.1.0)

# AI agent 要自己猜什麼時候跑完
send_input(session_id, "docker-compose up")
read_output(session_id) → 還沒好
read_output(session_id) → 還沒好
read_output(session_id) → 還沒好
read_output(session_id) → 好了!(浪費 3 次 tool call)

現在(v0.2.0)

# 一步到位:等到出現 "ready" 或 "error" 再回傳
send_input(session_id, "docker-compose up")
read_output(session_id, wait_for: "ready|error", timeout: 60, context_lines: 3)
→ 自動等待,回傳匹配行 + 3 行上下文

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 實測後修正的邊界問題:

實際使用場景

Sophos XG 防火牆

Sophos 的 SSH CLI 不是傳統 shell——連上去之後是一個數字選單系統。每一層都要選號碼,子選單再選號碼,一直到你要的功能。AI agent 要能在這種環境裡自主導航,需要三個條件:

# SSH 進 Sophos XG
create_ssh_session(host: "sophos-xg", user: "admin")
→ 出現主選單:
→ 1. System
→ 2. Network
→ 3. Firewall
→ Select Menu Number [0-5]:
# classifier 偵測到互動式選單
get_session_state(session_id)
→ { state: "confirmation", last_prompt: "Select Menu Number [0-5]:" }
# 選 "3. Firewall",送單字元不加換行
send_input(session_id, "3", raw: true)
read_output(session_id, wait_for: "Select Menu Number", timeout: 10)
→ 進入 Firewall 子選單
# 繼續導航到要的功能,全程 AI 自主操作
send_input(session_id, "1", raw: true) → 進入 Firewall Rules
read_output(session_id, wait_for: "Select Menu Number", timeout: 10)

Aruba 515 存取點

Aruba AP 的 CLI 是標準 shell 風格,SSH 後直接進入指令模式。常見需求:批次確認多個 AP 的關聯狀態、調整 radio 設定、撈取 debug log。搭配持久化 session,可以讓 AI 在背景跑完整個機房巡查,人不用守著。

# 連進 Aruba 515
create_ssh_session(host: "aruba-515-01", user: "admin",
log_file: "/tmp/aruba-audit.log")
read_output(session_id, wait_for: "#", timeout: 15)
→ AP-515-01#
# 確認目前關聯的用戶端
send_input(session_id, "show ap association")
read_output(session_id, wait_for: "#", context_lines: 50)
→ 列出所有關聯的 MAC address、SSID、RSSI、PHY
# 查 radio 設定
send_input(session_id, "show ap dot11 radio config")
read_output(session_id, wait_for: "#", context_lines: 30)
# 需要密碼提權時
send_input(session_id, "enable")
get_session_state(session_id)
→ { state: "password_prompt", last_prompt: "Password:" }
send_secret(session_id) → 密碼由人輸入,AI 看不到
read_output(session_id, wait_for: "#")
→ AP-515-01(enable)#
# 完成後斷開(log 已落盤 /tmp/aruba-audit.log)
close_session(session_id)

若要批次巡查多台 AP,AI agent 可以循環建立 session、執行相同指令、匯整回傳結果,全程不需要人在旁邊監看。

Linux 伺服器維運

最常見的場景:SSH 到遠端跑長時間任務,中途斷線不影響結果,稍後重連看輸出。

# 建立持久化 session,開始部署
create_ssh_session(host: "prod-server", user: "deploy",
persistent: true, log_file: "/tmp/deploy.log")
send_input(session_id, "cd /opt/app && ./deploy.sh")
detach_session(session_id) → 斷開,部署繼續在背景跑
# 20 分鐘後重連看結果
list_remote_sessions(host: "prod-server", user: "deploy")
create_ssh_session(host: "prod-server", user: "deploy",
session_id: "abc123")
read_output(session_id, wait_for: "SUCCESS|FAILED|ERROR", context_lines: 20)
→ 取得部署最終結果 + 前後 20 行 log
# 同時監看 log 中的警告
create_ssh_session(host: "prod-server", user: "deploy")
send_input(session_id, "tail -f /var/log/app.log")
read_output(session_id, wait_for: "WARN|ERROR|FATAL",
timeout: 600, context_lines: 5)
→ 出現問題立刻回報,不用盲目 polling

MCP Tools

Tool說明
create_local_session啟動本地互動式終端(bash、python3、node 等),可指定 log_file / log_max_size / log_max_files
create_ssh_sessionSSH 到遠端主機(支援 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 使用場景

# 等 server 重啟完成
create_local_session("ping myserver")
read_output(session_id, wait_for: "bytes from", timeout: 300)
→ 最多等 5 分鐘,server 一回應就回傳
# 等 build 結果
send_input(session_id, "make build")
read_output(session_id, wait_for: "BUILD SUCCESS|BUILD FAILURE", timeout: 120)
→ 成功或失敗都會捕捉到
# 等 log 出現特定錯誤
send_input(session_id, "tail -f /var/log/app.log")
read_output(session_id, wait_for: "ERROR|FATAL", timeout: 600, context_lines: 5)
→ 出錯時回傳匹配行 + 前後 5 行上下文

ai-tmux:持久化終端 Daemon

ai-tmux 是專為 AI agent 設計的輕量級 daemon,在遠端 server 上保持 PTY session 存活。概念類似 tmux,但為 AI agent 的使用模式重新設計:

使用場景

# 連到遠端,啟動長時間建置
create_ssh_session(host: "server", user: "admin", persistent: true)
send_input(session_id, "make build") → 開始編譯
detach_session(session_id) → 斷開,編譯繼續
# 稍後(甚至重啟後)重連看結果
list_remote_sessions(host: "server", user: "admin")
create_ssh_session(host: "server", user: "admin", session_id: "abc123")
send_input(session_id, "echo $?") → 檢查編譯結果

安裝

# 方法一:Pre-built binary(推薦)
curl -fsSL https://raw.githubusercontent.com/raychao-oao/pty-mcp/main/install.sh | sh
# 方法二:從 source 安裝
go install github.com/raychao-oao/pty-mcp@latest
go install github.com/raychao-oao/pty-mcp/cmd/ai-tmux@latest
# 註冊到 Claude Code
claude mcp add pty-mcp -- pty-mcp

實測過的環境:macOS、WSL、Linux + KDE Plasma。其餘平台有提供 binary,但沒有實機驗證過——GUI 密碼對話框會因桌面環境而異(KDE 走 kdialog、GNOME 走 zenity)。

技術選擇

為什麼不直接用 tmux?

tmux 是為人設計的——它假設有一個人坐在終端前操作。AI agent 需要的是:

ai-tmux 從頭為這些需求設計,比嵌套 tmux 乾淨很多。

GitHub →
← 返回作品集