purplemux-mcp
purplemux-mcp
한국어 · English
Claude Code / Codex에서 로컬 purplemux(subicura의 tmux + LLM 워크스페이스 매니저)를 제어하는 MCP 서버다. 워크스페이스·탭·터미널·(Electron)브라우저·서브에이전트 오케스트레이션을 26개 툴로 다룬다.
purplemux CLI는 localhost HTTP API를 감싼 얇은 래퍼일 뿐이라, 이 서버는 그 API를 MCP 툴로 그대로 노출한다(CLI로 셸아웃하지 않고 HTTP를 직접 호출). 그래서 에이전트가 터미널을 오케스트레이션하고, 나아가 Claude·GPT 계열을 넘나드는 크로스 LLM 서브에이전트(다른 AI-CLI 세션)까지 직접 운전할 수 있다.
Node ≥ 20 + 같은 호스트에 purplemux 실행이 필요하다.
왜 만들었나 — 크로스 LLM · 구독형 CLI를 서브에이전트로
이 프로젝트의 진짜 목적은 tmux(purplemux) 위에서 돌아가는 구독형 CLI(claude-code, codex-cli)를, 서로 다른 LLM을 넘나드는(크로스 LLM) 서브에이전트로 부려먹는 것이다.
크로스 LLM 오케스트레이션. 하나의 오케스트레이터가 Claude 계열(claude-code)과 GPT 계열(codex-cli)을 동시에 서브에이전트로 띄워 쓸 수 있다. 같은 문제를 서로 다른 모델에 던져 **교차 검증·합의(consensus)**를 시키거나, 강점이 다른 모델에 작업을 라우팅하는 식으로 — 한 모델 계열에 갇히지 않는다.
구독 정액 활용. 서브에이전트를 API로 붙이면 토큰 종량 과금이 붙지만, Claude Code(Claude 구독)·Codex CLI(ChatGPT/Codex 구독)는 정액 구독으로 돌아가는 대화형 세션이다. 이 세션들을 워커로 재활용한다.
다리 역할. purplemux는 이 구독형 CLI들을 각각 tmux 페인(탭)으로 띄워 주고, 그걸 제어할 로컬 HTTP API를 갖고 있다. 이 MCP가 그 API를 열어주는 다리다. 오케스트레이터(예: 지금 이 Claude Code)가 →
pmux-mcp-init으로.purplemux-mcp/agents-reply와 reply 도구 응답 계약을 준비하고필요하면
pmux-mcp-configure-agents로 Codex/Claude 설정에 purplemux MCP와 reply 도구 approval을 심고pmux_agent_start로 claude/codex CLI를 탭에 런치하고 (훅 주입 + 부트 검증까지 자동)pmux_agent_wait_ready로 부트스트랩 echo 완료 증거를 확인하고pmux_agent_turn으로 턴 단위 작업을 던져 응답을 무손실 회수하고pmux_close_tab으로 정리한다.
pmux_create_tab(claude-code/codex-cli 타입) +pmux_send_input조합은 서브에이전트 실행 경로가 아니다 — 그 panelType은 UI 패널이라 빈 셸일 수 있고, readiness·응답 회수를 아무도 관리하지 않는다. 저수준 툴은 일반 터미널 작업과 수동 폴백 전용.
즉 여러 LLM의 구독 CLI 세션을 "호출 가능한 워커 에이전트"로 바꿔 팬아웃(fan-out) 오케스트레이션을 하는 게 핵심 시나리오다. 여러 탭에 작업을 나눠 병렬로 돌리고, 상태를 폴링하고, 서로 다른 모델의 결과를 합치는 흐름 전체를 자연어 지시로 굴릴 수 있다.
참고: 이 저장소 자체도 그 정신으로 만들어졌다 — 추출→설계→작업→리뷰→테스트 5단계를 각각 크로스 LLM 3개 서브에이전트(Claude Sonnet / Claude Opus / Codex gpt-5.5-high)의 합의로 진행했다. 서로 다른 모델이 교차 검증한 덕에 실제로 한쪽만으론 놓쳤을 것들(예:
send자동 제출 동작, 포트 인젝션 토큰 유출)을 잡아냈다.
Related MCP server: TmuxControlLib MCP Server
빠른 시작
# 1. purplemux 실행 중이어야 함 (서버가 ~/.purplemux/{port,cli-token}을 기록)
# 2. 빌드
npm install && npm run build # -> dist/index.js
# 3. 등록 (절대경로)
claude mcp add purplemux -s user -- node "$PWD/dist/index.js"
codex mcp add purplemux -- node "$PWD/dist/index.js"Claude Code / Codex 세션을 재시작하면 pmux_* 툴이 뜬다. 포트·토큰은 호출마다 ~/.purplemux/에서 자동으로 읽으므로(캐시 없음), purplemux를 재시작하거나 포트가 바뀌어도 이 서버는 재시작할 필요가 없고 일반 환경에선 env 설정도 필요 없다.
서브에이전트 사전 작업
크로스 LLM 서브에이전트가 pmux-agent-reply를 바로 쓰려면, 오케스트레이터 세션에서 한 번 준비한다.
pmux_list_workspaces로 대상workspaceId와 실제 디렉터리를 확인한다.pmux-mcp-init {workspaceId}를 실행해<workspace>/.purplemux-mcp/agents-reply를 만든다.pmux-mcp-configure-agents {workspaceId, target:"both"}로 dry-run 결과를 확인한다.문제가 없으면
pmux-mcp-configure-agents {workspaceId, target:"both", apply:true}를 실행한다.이후 새로 시작하는 Codex/Claude 서브에이전트부터 설정이 적용된다.
권한 패치는 안전 병합 방식이다. 기존 파일이 있으면 백업하고, JSON은 파싱 후 필요한 값만 추가한다.
Codex:
~/.codex/config.toml에 purplemux MCP 서버와pmux-agent-replyapproval만 추가Claude MCP 서버:
~/.claude.json의mcpServers.purplemuxClaude tool allow:
<workspace>/.claude/settings.local.json의permissions.allow에mcp__purplemux__pmux-agent-reply
<workspace>는 선택한 purplemux workspace의 directories[0]이다. 예를 들어 workspace가 /home/yoway030를 가리키면 생성 위치도 /home/yoway030/.claude/settings.local.json이고, 현재 git repo 아래 .claude/가 아니다.
툴 (26개)
에이전트 오케스트레이션 (v2 — 권장 진입점): pmux-mcp-init · pmux-mcp-configure-agents · pmux_agent_start · pmux_agent_wait_ready ·
pmux_agent_send · pmux_agent_capture · pmux_agent_status · pmux_agent_turn · pmux-agent-reply
claude/codex를 훅 주입으로 부팅해(purplemux 네이티브
cliState/command상태 채널 활용) readiness·busy를 결정론적으로 판정하고, 부트 검증(SessionStart 부트 신호 + bootstrap echo)으로 "프로세스가 떴고 모델이 실제로 응답했다"는 증거를 확보한 뒤, 응답은pmux-agent-reply도구가.purplemux-mcp/agents-reply/<agentId>-<turn>-<requestId>.md에 쓰는 파일 프로토콜(req 신원 + EOF 커밋 이중 게이트)로 무손실 회수한다.pmux_agent_turn은 send→폴링→회수를 턴당 1콜로 묶은 복합 툴. 설계·근거: docs/worklog-20260707-workflow/design-v2.md, design-v22.md, worklog/plan-boot-signal-echo.md
터미널/탭 (headless에서도 동작): pmux_list_workspaces · pmux_list_tabs ·
pmux_create_tab · pmux_get_tab · pmux_send_input · pmux_tab_status ·
pmux_capture_pane · pmux_close_tab
브라우저 (Electron 필요): pmux_browser_url · pmux_browser_screenshot ·
pmux_browser_console · pmux_browser_network · pmux_browser_network_body ·
pmux_browser_eval
메타/유틸: pmux_guide(이 서버의 오케스트레이션 가이드 — LLM 셀프 문서) · pmux_api_guide(purplemux HTTP API 레퍼런스) · pmux_connection_info(토큰값은 절대 노출 안 함)
접속하는 LLM에는 MCP
instructions로 툴 계층·골든 패스가 initialize 시점에 자동 전달되고, 상세 가이드(실패 모드·복구 패턴 포함)는pmux_guide한 번으로 회수할 수 있다.
pmux_send_input은 자동 제출된다(서버가 Enter를 침) — 개행을 붙이지 말 것. trailing\n1개는 자동 제거된다. 브라우저 툴은 headless(비 Electron) purplemux에서 503을 반환하고,web-browser탭 생성 직후엔 409 "not attached yet"(잠시 후 재시도)가 날 수 있다.
claude/codex CLI를 pmux_agent_*로 서브에이전트로 부리는 cookbook을 포함한 전체 기능·설치 옵션·사용 예시: docs/USAGE.md.
개발 / 테스트
npm run build && npm run typecheck
npm run smoke # handshake + 26툴 + 라이브 list_workspaces
npm run unit # 순수 함수 단위테스트 (fixture 기반)
npm run e2e # 실행 중 purplemux 대상 라이브 라운드트립 12케이스구조
src/ # config, http, errors, schemas, tools, agents, boot, guide, pane, paths, profiles, index
test/ # smoke + 라이브 e2e (Node, 프레임워크 없음)
docs/
USAGE.md # 기능 · 설치 · 사용법
01-cli-features.md # purplemux CLI 추출 정본
02-mcp-design.md # MCP 서버 설계 정본
worklog/ # 단계별 작업기록 (추출→설계→작업→리뷰→테스트)
panel/ # 3에이전트(Sonnet/Opus/Codex) 단계별 초안
reference/ # 추출에 사용한 고정 입력(api-guide 등)어떻게 만들었나
추출 → 설계 → 작업 → 리뷰 → 테스트 5단계. 각 단계를 세 서브에이전트(Claude Sonnet, Claude Opus, Codex gpt-5.5-high)의 합의로 통과시키고, 이견은 오케스트레이터가 라이브 서버 실측으로 판정했다(예: send 자동 제출 동작 확정, 리뷰 단계에서 포트 인젝션에 의한 토큰 유출 취약점 발견·차단). 자세한 내용은 docs/worklog/.
라이선스
MIT (이 서버). purplemux는 subicura의 별도 프로젝트다.
Available Tools
23 toolspmux_agent_captureA
Primary agent orchestration tool: recover a v2.1 agent response. Use pmux_capture_pane only as a low-level fallback. If requestId is supplied, first read the report file at workspaceDir/.pmux-agents//turn-.md and require matching status line plus EOF marker. Without requestId, file recovery is skipped and pane BEGIN/END fallback is used. Returns structured complete/blocked/working/inconsistent/partial/missing results; partial/working means do not send the next turn yet.
Inputs: turn (required), tabId (required), agentId (required), workspaceId (required), +1 more.
pmux_agent_sendA
Primary agent orchestration tool: validate provider-specific readiness/busy/error state, optionally verify a previous DONE signal or END marker, append the v2.1 PMUX footer, and send the prompt. Use pmux_send_input/pmux_capture_pane only as low-level fallbacks. For fileOutput=true previous turns, pass expectPrevTurnEnd together with expectPrevRequestId so shortened req-keyed markers can be matched. On turn <= 1 only, pane fallback input_queued is treated as a composer placeholder and sent with validation.warning; later turns remain strict. fileOutput defaults true: requestId is generated when omitted, workspaceDir is resolved from workspaces[].directories[0], and expectedReportFile is returned. Use fileOutput:false when pmux_agent_start returned recommendedFileOutput:false; read-only/plan agents cannot write report files. fileOutput=false uses the pane BEGIN/END fallback. agent_busy returns {sent:false, reason:"busy"}. Caller contract: if pmux_agent_capture returns partial/working, do not call pmux_agent_send again until the current turn completes or is explicitly abandoned.
Inputs: turn (required), tabId (required), prompt (required), agentId (required), +12 more.
pmux_agent_startA
Primary agent orchestration tool: create a terminal tab, poll briefly for shell readiness, then send an interactive agent CLI command. ORCHESTRATOR CONTRACT: before launching, ask the user which model/effort (and codex sandbox / claude permissionMode) each subagent should use, unless the user already specified them. Use pmux_send_input/pmux_capture_pane only as low-level fallbacks. Returns recommendedFileOutput: false for read-only/plan agents that should be sent fileOutput:false. Boot verification: returns bootId — by default (bootstrapEcho:true) the CLI is launched with a fixed initial prompt that makes the model print a DONE marker (req=bootId), and a SessionStart hook writes a boot-signal file; verify with pmux_agent_wait_ready {bootId, expectEcho:true}, then send user work from turn=1 (bootstrap consumed turn 0; do not pass expectPrevTurnEnd on turn 1). bootstrapEcho costs one tiny model turn — pass false to skip. codex hook trust (실측 2026-07-08): the FIRST launch that wires the boot hook requires a one-time interactive trust approval in the codex TUI — until approved, boot.fileSeen stays false while the echo still works; treat fileSeen:false + echoSeen:true on codex as this case, not a failure. This is non-blocking: after a successful start return, use pmux_agent_wait_ready before sending work. wait_ready launch_failed is meaningful only after start has successfully sent the command; an idle shell before command send is indistinguishable to the stateless wait tool. Session lifetime contract: keep the tab open until the task is finished, then close it with pmux_close_tab. Codex command: codex --no-alt-screen -s ; Claude permissionMode choices are based on claude 2.1.201 and intentionally exclude bypassPermissions; claude effort maps to the --effort flag (claude >=2.1.202).
Inputs: provider (required), workspaceId (required), name, model, +5 more.
pmux_agent_statusA
Primary agent orchestration tool: return a no-wait v2.1 status snapshot. Use pmux_tab_status/pmux_capture_pane only as low-level fallbacks. Includes tab alive, provider-specific readiness, optional DONE signal for agentId/turn/requestId, optional report-file check, runtimeError when detected, and pane tail. No server-side state is kept.
Inputs: tabId (required), provider (required), workspaceId (required), turn, +6 more.
pmux_agent_turnA
Primary agent orchestration tool for one full turn: send a prompt, poll for completion evidence, then return the recovered response. Safe to call immediately after a previous turn; transient pre-send busy/starting states are retried within the same pollTimeoutMs budget. Use pmux_agent_capture with the returned marker to resume after timeout; use pmux_send_input/pmux_capture_pane only as low-level fallbacks. Completion evidence from a valid report file or pane markers wins over readiness/runtime-error signals. Without completion evidence, ready plus runtimeError returns status:"agent_error".
Inputs: turn (required), tabId (required), prompt (required), agentId (required), +14 more.
pmux_agent_wait_readyA
Primary agent orchestration tool: poll a tab until an agent is ready, still starting/busy, launch_failed, exited, or timeout. Use pmux_send_input/pmux_capture_pane only as low-level fallbacks. agent_busy is non-terminal and keeps polling. Boot verification (recommended after pmux_agent_start): pass {bootId, expectEcho:true} — agent_ready is then returned ONLY on the bootstrap DONE marker (completion evidence; supersedes ready heuristics, requireBusyTransition and runtimeError), and every response carries boot.fileSeen (SessionStart boot-signal file — diagnostic only; on echo timeout, fileSeen:false suggests launch/hook-trust failure while fileSeen:true suggests the model never answered). Default timeout rises to 90s under expectEcho. requireBusyTransition defaults false for boot readiness; set true when waiting after send so ready is returned only after busy was observed or an initial non-ready baseline later changes to ready. In boot mode only (and never under expectEcho), pane fallback input_queued can be treated as a composer placeholder and returned ready; send validation remains strict. Uses pane capture + tab_status only; no server-side registry is kept. Session lifetime contract: keep the tab open until the task is finished, then close it with pmux_close_tab.
Inputs: tabId (required), provider (required), workspaceId (required), bootId, +8 more.
pmux_api_guideA
Return the purplemux application's HTTP API reference as markdown (fetched from the running purplemux). This documents the underlying REST endpoints, NOT how to use this MCP server's tools — for orchestration guidance use pmux_guide.
Inputs: no named parameters.
pmux_browser_consoleA
Get browser console entries { tabId, entries[] } (ring buffer, last 500). since=ms is an incremental polling cursor; level filters by console level. Electron-only (503/409).
Inputs: tabId (required), workspaceId (required), level, since.
pmux_browser_evalA
Evaluate a JavaScript expression in the page and return { tabId, value } (CDP Runtime.evaluate, returnByValue + awaitPromise, 10s timeout). A JS exception/timeout surfaces as 409. Electron-only: 503 = not under Electron (hard); 409 'Browser tab not attached yet' = webview not dom-ready (transient, retry shortly).
Inputs: tabId (required), expression (required), workspaceId (required).
pmux_browser_networkA
Get browser network entries { tabId, entries[] } (ring buffer, last 500). Filters: since=ms cursor, method (upper-cased server-side), url (substring), status (exact int). Electron-only (503/409). Use pmux_browser_network_body for a single response body.
Inputs: tabId (required), workspaceId (required), url, since, +2 more.
pmux_browser_network_bodyA
Get a single network response body by requestId: { tabId, requestId, body }. Body is cached after the first call. 404 'Response body unavailable' if not cached/available. Electron-only (503/409).
Inputs: tabId (required), requestId (required), workspaceId (required).
pmux_browser_screenshotA
Screenshot a web-browser tab. Default: returns MCP image content (PNG). With savePath: writes raw PNG bytes to that path and returns { saved, bytes }. full=true captures beyond the viewport. Electron-only (503 hard / 409 'not attached yet' transient).
Inputs: tabId (required), workspaceId (required), full, savePath.
pmux_browser_urlA
Get the browser tab's { tabId, url, title }. Browser tools are Electron-only: 503 = not running under Electron (hard, don't retry); 409 'Browser tab not attached yet' = webview not dom-ready (transient, retry shortly). 400 'Tab is not a web-browser panel' on a non-browser tab.
Inputs: tabId (required), workspaceId (required).
pmux_capture_paneA
Low-level fallback for manual pane inspection; for agent orchestration prefer pmux_agent_* tools. Capture the current pane snapshot as { content }. Not meaningful for web-browser tabs. 409 'Tab session is not running' if the session is dead.
Inputs: tabId (required), workspaceId (required).
pmux_close_tabB
Close a tab. Returns the real { ok:boolean } body (surfaced faithfully; the CLI would hide it). For web-browser tabs the tmux kill is skipped.
Inputs: tabId (required), workspaceId (required).
pmux_connection_infoA
Local diagnostic: { baseUrl?, portSource, tokenSource, hasToken }. NEVER returns the token value. When port/token are missing it returns partial diagnostics (source "none", hasToken:false) rather than erroring.
Inputs: no named parameters.
pmux_create_tabA
Create a tab in a workspace. panelType is one of terminal | claude-code | codex-cli | agent-sessions | web-browser | diff (default terminal); invalid → 400 with validPanelTypes. WARNING: claude-code/codex-cli panelType creates a UI panel, NOT a managed agent session — the pane may be an empty shell before the UI attaches, and sending prompts into it is unreliable. To run a subagent, use pmux_agent_start instead (it launches the CLI in a terminal tab under full protocol control). Creating claude-code/codex-cli without the CLI installed → 409 with suggestedCommand. Returns the created-tab object.
Inputs: workspaceId (required), name, panelType.
pmux_get_tabA
Get info for a single tab by id.
Inputs: tabId (required), workspaceId (required).
pmux_guideA
Return the orchestration guide for THIS MCP server as markdown: tool layers (agent_* primary vs low-level fallbacks), the golden path for running claude/codex subagents, boot verification semantics, fileOutput routing, failure modes and recovery patterns. Call this before orchestrating subagents for the first time, or whenever an agent_* result is unclear. (For the purplemux HTTP API reference, use pmux_api_guide instead.)
Inputs: no named parameters.
pmux_list_tabsA
List tabs, optionally filtered by workspaceId. Omit workspaceId to list across all workspaces. Unknown workspaceId returns {tabs:[]}, not an error.
Inputs: workspaceId.
pmux_list_workspacesA
List purplemux workspaces: { workspaces:[{id,name,directories}] }. Start here to get workspaceId values for the other tools.
Inputs: no named parameters.
pmux_send_inputA
Low-level fallback for manual tab input; for agent orchestration prefer pmux_agent_* tools. Send text to a tab. The server AUTO-SUBMITS (delivers as a bracketed paste then presses Enter) — do NOT append a newline to submit. Exactly one trailing '\n' is stripped from content; other whitespace is preserved. Returns { status:"sent" }. 409 'Tab session is not running' if the tmux session is dead.
Inputs: tabId (required), content (required), workspaceId (required).
pmux_tab_statusA
Get tab runtime status. NOTE: for web-browser tabs alive:false is NORMAL (they are Electron webviews, not tmux) — probe health via the browser tools instead. claudeSessionId is a legacy alias of agentSessionId (same value).
Inputs: tabId (required), workspaceId (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 23 tools
Tools are clearly described with explicit guidance on primary vs fallback usage, reducing ambiguity. However, some overlap exists between pmux_agent_turn and the manual send+capture pattern, which could still cause misselection.
All tools follow the consistent pattern 'pmux_<category>_<action>', with clear prefixes for agent, browser, and tab operations. No mixing of conventions.
23 tools is slightly above the typical 3-15 range but still well-scoped for a server covering agent orchestration, browser control, and tab management. Each tool has a distinct purpose.
Agent lifecycle is well-covered (start, send, capture, status, turn, wait_ready). Browser tools lack a navigate action, but the set is otherwise comprehensive. Minor gaps.
Maintenance
Related MCP Connectors
Use your Mac, Windows or Linux computer from ChatGPT, Claude or Codex: files, commands, documents.
Work on your own computers from Claude or ChatGPT: run commands, edit and search files.
Source-checked CLI guides and model-aware planning for Claude Code, Codex, and Grok Build.
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables Claude to execute commands and manage directory-aware panes within tmux sessions for a shared terminal experience. It features smart output capture, interactive prompt detection, and background task management.2MIT
- AlicenseNot gradedqualityDmaintenanceEnables Claude to control tmux sessions, manage windows and panes, and search/extract text from terminal output.2MIT
- AlicenseNot gradedqualityDmaintenanceGives Claude Code terminal control and multi-agent coordination through tmux sessions.4MIT
- AlicenseAqualityDmaintenanceGives Claude Code full control over tmux sessions, windows, and panes, with an optional Sonnet-based safety classifier for destructive commands.11MIT