Skip to main content
Glama

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)가 →

    1. pmux-mcp-init으로 .purplemux-mcp/agents-reply와 reply 도구 응답 계약을 준비하고

    2. 필요하면 pmux-mcp-configure-agents로 Codex/Claude 설정에 purplemux MCP와 reply 도구 approval을 심고

    3. pmux_agent_start로 claude/codex CLI를 탭에 런치하고 (훅 주입 + 부트 검증까지 자동)

    4. pmux_agent_wait_ready로 부트스트랩 echo 완료 증거를 확인하고

    5. pmux_agent_turn으로 턴 단위 작업을 던져 응답을 무손실 회수하고

    6. 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를 바로 쓰려면, 오케스트레이터 세션에서 한 번 준비한다.

  1. pmux_list_workspaces로 대상 workspaceId와 실제 디렉터리를 확인한다.

  2. pmux-mcp-init {workspaceId}를 실행해 <workspace>/.purplemux-mcp/agents-reply를 만든다.

  3. pmux-mcp-configure-agents {workspaceId, target:"both"}로 dry-run 결과를 확인한다.

  4. 문제가 없으면 pmux-mcp-configure-agents {workspaceId, target:"both", apply:true}를 실행한다.

  5. 이후 새로 시작하는 Codex/Claude 서브에이전트부터 설정이 적용된다.

권한 패치는 안전 병합 방식이다. 기존 파일이 있으면 백업하고, JSON은 파싱 후 필요한 값만 추가한다.

  • Codex: ~/.codex/config.toml에 purplemux MCP 서버와 pmux-agent-reply approval만 추가

  • Claude MCP 서버: ~/.claude.json의 mcpServers.purplemux

  • Claude 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 \n 1개는 자동 제거된다. 브라우저 툴은 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 tools
pmux_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

    A4/5.0

    Scored across 23 tools

    Disambiguation4/5

    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.

    Naming Consistency5/5

    All tools follow the consistent pattern 'pmux_<category>_<action>', with clear prefixes for agent, browser, and tab operations. No mixing of conventions.

    Tool Count4/5

    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.

    Completeness4/5

    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

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers