终端控制工具

PTY-MCP是一个交互式终端控制工具,允许AI代理像人类一样操作终端会话,支持处理交互式提示、REPLs和TUI应用程序。

  • by irvingoujAtDevolution
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 irvingoujAtDevolution/pty-mcp

使用说明

PTY-MCP:AI代理的交互式终端控制

“终端剧作家”-让AI代理完全控制交互式终端会话。

为什么存在

定期执行shell(subprocess, child_process)无法处理:

  • 交互式提示(凭证、Y/N确认、, Read-Host)
  • 需要Ctrl+C停止的程序
  • 维护状态的REPL(Python、Node、PowerShell会话)
  • 全屏TUI应用程序
  • 命令如下 Enter-PSSession 启动交互式子会话

此MCP服务器为代理提供 眼睛 (屏幕缓冲区)和 手 (键盘输入)像人类一样使用终端。

工具

核心工具

工具 说明
spawn_session 启动新终端(pwsh、cmd、bash)
send_keys 键入文本或按特殊键
send_line 新 发送文本+Enter(最常见的操作)
get_snapshot 读取当前屏幕缓冲区
get_buffer_range 新 读取缓冲区行(包括回滚)
get_buffer_info 新 读取缓冲区元数据(长度、视口、光标)
get_cursor 新 获取光标位置(x,y)
resize 更改端子尺寸
list_sessions 列出活动会话
close_session 终止会话

等待工具(用于同步)

工具 说明
wait_for_content 新 等待特定文本/图案出现
wait_for_idle 新 等待屏幕停止更改
wait_for_buffer_lines 新 等待缓冲区行数增加

正确使用

⚠️ 重要提示:使用“Enter”键,而不是“\n”

这是一个 真实终端,不是命令执行器。你必须像人类一样与它互动:

❌ WRONG - sends literal newline characters, triggers continuation prompt
send_keys({ keys: "pwd\nGet-Date\n" })

✅ CORRECT - type command, press Enter, wait, read output
send_keys({ keys: "pwd" })
send_keys({ keys: "Enter" })
get_snapshot()  // read the output

send_keys({ keys: "Get-Date" })
send_keys({ keys: "Enter" })
get_snapshot()  // read the output

基本工作流程(推荐)

1. spawn_session({ command: "pwsh.exe", args: ["-NoProfile", "-NoLogo"] })
   → Returns: { session_id: "abc-123", pid: 12345 }

2. wait_for_content({ session_id: "abc-123", pattern: "PS .*>", is_regex: true })
   → Waits for prompt, returns screen content

3. send_line({ session_id: "abc-123", text: "Get-Date" })
   → Types command + presses Enter (one call!)

4. wait_for_content({ session_id: "abc-123", pattern: "PS .*>", is_regex: true })
   → Waits for next prompt (command finished)
   → Returns screen with output

5. close_session({ session_id: "abc-123" })
   → Clean up when done

替代方案:手动控制

1. spawn_session({ command: "pwsh.exe", args: ["-NoProfile", "-NoLogo"] })

2. get_snapshot({ session_id: "abc-123" })
   → See: "PS C:\Users\jou>" (prompt is ready)

3. send_keys({ session_id: "abc-123", keys: "Get-Date" })
   → Types the command

4. send_keys({ session_id: "abc-123", keys: "Enter" })
   → Executes the command

5. wait_for_idle({ session_id: "abc-123" })
   → Wait for output to finish

6. get_snapshot({ session_id: "abc-123" })
   → See the output

特殊钥匙

使用这些键名 send_keys:

密钥 名称
进入 "Enter"
选项卡 "Tab"
逃跑 "Escape"
后台空间 "Backspace"
删除 "Delete"
箭头键 "Up", "Down", "Left", "Right"
首页/尾页 "Home", "End"
向上/向下翻页 "PageUp", "PageDown"
功能键 "F1" 通过 "F12"

关键点修改器(Ctrl、Alt、Shift)

// Ctrl+C to interrupt
send_keys({ keys: "c", modifiers: { ctrl: true } })

// Ctrl+D to send EOF
send_keys({ keys: "d", modifiers: { ctrl: true } })

// Ctrl+L to clear screen
send_keys({ keys: "l", modifiers: { ctrl: true } })

// Ctrl+Right to move word forward
send_keys({ keys: "Right", modifiers: { ctrl: true } })

// Ctrl+Shift+Right to select word
send_keys({ keys: "Right", modifiers: { ctrl: true, shift: true } })

例子

运行命令并获取输出

spawn_session({ command: "pwsh.exe", args: ["-NoProfile", "-NoLogo"] })
// Wait for prompt...
get_snapshot()  // Should see "PS ...>"

send_keys({ keys: "Get-Process | Select -First 3" })
send_keys({ keys: "Enter" })
// Wait for output...
get_snapshot()  // See the process list

close_session({ session_id: "..." })

处理交互式提示(读取主机)

send_keys({ keys: "$name = Read-Host 'Enter your name'" })
send_keys({ keys: "Enter" })
get_snapshot()  // See: "Enter your name: "

send_keys({ keys: "Alice" })
send_keys({ keys: "Enter" })
get_snapshot()  // Back to prompt

send_keys({ keys: "Write-Host \"Hello, $name\"" })
send_keys({ keys: "Enter" })
get_snapshot()  // See: "Hello, Alice"

中断长时间运行的命令

send_keys({ keys: "Start-Sleep -Seconds 300" })
send_keys({ keys: "Enter" })
// Oops, that's too long...

send_keys({ keys: "c", modifiers: { ctrl: true } })  // Ctrl+C
get_snapshot()  // Back to prompt

浏览命令历史记录

send_keys({ keys: "Get-Date" })
send_keys({ keys: "Enter" })
// ... do other things ...

send_keys({ keys: "Up" })      // Previous command
get_snapshot()                  // See "Get-Date" on command line
send_keys({ keys: "Enter" })   // Run it again

使用等待工具(推荐)

// Wait for PowerShell prompt
wait_for_content({ session_id, pattern: "PS .*>", is_regex: true })

// Wait for specific output
send_line({ session_id, text: "Get-Process explorer" })
wait_for_content({ session_id, pattern: "explorer" })

// Wait for command to finish (screen stops changing)
send_line({ session_id, text: "Get-Process | Sort-Object CPU -Descending" })
wait_for_idle({ session_id, timeout: 10000 })
get_snapshot({ session_id })

// Wait with timeout
wait_for_content({
  session_id,
  pattern: "Password:",
  timeout: 30000  // 30 seconds
})

调试TUI(vim、htop等)

// Get raw ANSI escape sequences for debugging
get_snapshot({ session_id, include_ansi: true })
→ Returns: { content: "...", rawAnsi: "\x1b[1;1H\x1b[2J..." }

读取回溯(长输出)

send_line({ session_id, text: "Get-Content big.log" })
wait_for_idle({ session_id, timeout: 10000 })

// Read last 200 lines from buffer
get_buffer_range({ session_id, start: -200, count: 200 })

确定性读取(缓冲元数据)

const info = get_buffer_info({ session_id })
// info.total is the buffer length (including scrollback)
get_buffer_range({ session_id, start: info.total - 200, count: 200 })

等待长时间输出(行数)

send_line({ session_id, text: "1..500 | ForEach-Object { \"Line $_\" }" })
wait_for_buffer_lines({ session_id, min_delta: 500, timeout: 10000 })
get_buffer_range({ session_id, start: -50, count: 50, exclude_pattern: "PS ", is_regex: false })

快照格式

get_snapshot 返回:

{
  "content": "  1 | PS C:\\Users\\jou> Get-Date\n  2 | Tuesday, January 28, 2025\n  3 | \n...",
  "cursor": { "x": 20, "y": 2 },
  "rows": 24,
  "cols": 80
}
  • content:带有行号的屏幕缓冲区(如 cat -n)
  • cursor:当前光标位置
  • rows/cols:端子尺寸

AI代理提示

  1. 始终等待提示 在发送下一个命令之前
  2. 一次一个命令 -键入、输入、等待、读取
  3. 使用 get_snapshot 大量地 -你的眼睛盯着航站楼
  4. 使用Ctrl+C 如果某物挂起或进入意外状态
  5. 检查是否有提示 喜欢 [Y/N], Password:, >> (续)
  6. 结束会议 当释放资源时

安装

npm install
npm run build

添加到MCP配置中:

# Codex CLI
codex mcp add pty-mcp -- node /path/to/dist/index.js

# Claude Code
claude mcp add pty-mcp -- node /path/to/dist/index.js

发展

npm test          # Run all tests (116 tests)
npm run typecheck # Type checking
npm run lint      # Linting
npm run build     # Build for production