Skip to main content
Glama
jiho-symply

Codex Workspace Bridge

by jiho-symply

Codex Workspace Bridge

ChatGPT가 MCP 도구로 지정된 로컬 작업 공간의 Codex 대화 하나에 작업을 보내고, 파일·실행 결과·diff를 읽는 브리지입니다. ChatGPT 웹페이지의 버튼이나 DOM을 제어하지 않습니다.

An experimental MCP stdio server for one explicitly bound Codex workspace and conversation. Uses Codex App Server; no ChatGPT browser automation, session cookies, or private ChatGPT web endpoints.

ChatGPT developer-mode app
          │ MCP via Secure MCP Tunnel
          ▼
Local tunnel-client → cwb serve → Codex App Server → bound thread / workspace
                          │
                          └── private binding + durable job journal

Status

Prototype, not yet validated end to end inside ChatGPT. Unit tests and an MCP stdio → WebSocket App Server integration test use a fake backend. A local Codex 0.155.0-alpha.9.2 build on Windows was also tested against a dedicated desktop conversation. Its shared-daemon proxy was unavailable. A separate server could read the conversation but thread/resume failed with already has an active writer, even while the desktop task was idle. The official codex queue command successfully delivered a harmless test message and the desktop replied.

The bridge's MCP stdio → queue → real desktop conversation → exact result round trip was then verified, including an identical-request retry producing the same job ID. The reply was CWB_CODEX_TEST_OK; no files or commands were involved. A reader-process quirk that temporarily labels an unfinished desktop turn interrupted is handled by waiting for a persisted completion timestamp. ChatGPT Web and the external tunnel remain untested.

This distinction matters: a separate App Server can load the same saved thread but cannot reliably observe another server's live activity. Start with a dedicated conversation and one writer. Sharing a thread ID is not proof of shared runtime ownership.

Desktop queue mode

For a conversation owned by the running desktop app, --mode queue adds messages using experimental thread/queue/add. It does not resume the thread or take its writer lock. The app consumes the queue; the bridge reads persisted results and identifies the exact turn using a client message UUID saved before submission. A lost response is never blindly replayed.

node dist/cli.js bind --workspace C:\code\my-project --thread THREAD_ID --mode queue --acknowledge-thread-permissions --state-dir "$env:LOCALAPPDATA\cwb-my-project-queue"

Queue mode inherits the desktop conversation's existing permissions, tools and approval settings. The bridge cannot enforce its own read-only, network or approval policy in this mode. --allow-write and --network are therefore rejected, and get_connection reports those permissions as unknown (null). The acknowledgment is required locally. Keep the desktop app running. Results are polled from history; live diff events and remote cancellation are unavailable. Cancel a task in the desktop app. This mode exposes five MCP tools, omitting cancel_job.

Related MCP server: Codex Local Gateway

Install

Requires Node.js 22+, Git, and a signed-in Codex installation supporting the App Server methods below. This repository is not published to npm.

git clone https://github.com/jiho-symply/codex-workspace-bridge.git
cd codex-workspace-bridge
npm ci
npm test

npm test builds dist/ and runs the tests. Run npm run build after editing source. Use node dist/cli.js --help for the CLI. Examples below run from this repository; replace the paths and thread ID with your own. The bridge does not create a conversation: first create the intended task in Codex.

Select one workspace and conversation

The default backend connects to an existing Codex daemon with codex app-server proxy. It never silently falls back to a separate server.

node dist/cli.js threads --workspace /absolute/path/to/project
node dist/cli.js bind --workspace /absolute/path/to/project --thread THREAD_ID --state-dir /private/path/cwb-project
node dist/cli.js doctor --state-dir /private/path/cwb-project

On Windows, for example:

node dist/cli.js threads --workspace C:\code\my-project
node dist/cli.js bind --workspace C:\code\my-project --thread THREAD_ID --state-dir "$env:LOCALAPPDATA\cwb-my-project"
node dist/cli.js doctor --state-dir "$env:LOCALAPPDATA\cwb-my-project"

Keep the state directory outside the workspace. Binding checks the exact thread ID and canonical working directory. An existing binding cannot be changed to a different thread or backend; choose a new state directory for that. Default execution is read-only, with network disabled. Add --allow-write to bind to permit workspace edits, and --network only when needed. Rebinding the same target locally can change these permissions; stop serve first.

Other connection options:

Mode

Options

Meaning

proxy (default)

--codex /path/to/codex, optional --socket PATH

Existing daemon; availability depends on the installed Codex build and host.

websocket

--mode websocket --endpoint ws://127.0.0.1:PORT, optional --token-env VARIABLE

Existing App Server endpoint, not an MCP endpoint. Non-loopback requires wss://.

spawn

--mode spawn --acknowledge-separate-process on bind

Launch a separate codex app-server --stdio. You must stop all other use of this saved conversation while the bridge owns it.

queue

--mode queue --acknowledge-thread-permissions on bind

Add messages to the desktop-owned thread's queue; inherit its execution permissions.

For read-only discovery, threads --mode spawn does not require the acknowledgment. A notLoaded status in this mode says nothing about whether the desktop app is running that conversation. Do not bind this mode to an active task. No daemon is started, stopped, or reconfigured automatically by proxy mode.

Connect ChatGPT

This version serves stdio only. localhost is not a ChatGPT MCP URL. Use OpenAI Secure MCP Tunnel to reach the local command. It requires a tunnel ID, a runtime API key, tunnel permissions, and association with the intended ChatGPT workspace. Availability is account-dependent; this repo does not provision these resources.

Download tunnel-client using the official guide, supply its CONTROL_PLANE_API_KEY privately, then configure the command with absolute paths:

tunnel-client init --sample sample_mcp_stdio_local --profile cwb --tunnel-id YOUR_TUNNEL_ID --mcp-command "node /absolute/path/codex-workspace-bridge/dist/cli.js serve --state-dir /private/path/cwb-project"
tunnel-client doctor --profile cwb --explain
tunnel-client run --profile cwb

For paths containing spaces, follow your shell's quoting rules for the nested command. Use the tunnel profile's configuration to inspect the resulting command before running it. Let the tunnel launch serve; do not start a second copy with the same state directory.

In ChatGPT, enable developer mode where available, create an app under Plugins, choose Tunnel, and select the configured tunnel. See the official connection guide. If your account lacks tunnel access, this version does not supply a public HTTP/OAuth alternative. Do not expose an unauthenticated stdio-to-HTTP adapter to the internet.

The bridge itself uses the existing local Codex authentication. The tunnel's runtime API key is a separate transport requirement. It is never a ChatGPT browser session token. This architecture uses documented integration surfaces; it does not guarantee account-policy outcomes or bypass usage limits.

Tools and workflow

MCP tool

Purpose

get_connection

Confirm the bound conversation, workspace, permissions and recent jobs.

send_message

Submit a task or a proposed patch as text; receive a durable job ID.

get_result

Read that exact job, optionally waiting up to 20 seconds.

read_output

Page through captured messages, command results, file changes or diff.

read_file

Read bounded text from an allowed relative workspace path.

cancel_job

Interrupt the exact submitted turn; does not undo changes.

Example ChatGPT instruction:

먼저 get_connection으로 연결된 작업 공간과 대화를 확인해. src/app.ts를 읽고 수정안을 만들어. 내 요청 범위 안에서 Codex에 구현과 테스트를 맡긴 뒤, 받은 job_id로 결과를 조회해서 변경사항과 테스트 결과를 알려줘. 전송 결과가 불확실하면 새 요청 ID로 재전송하지 마.

send_message needs message and a unique request_id (8–128 letters, digits, underscores, dots, colons or hyphens). Use the same ID and identical message when retrying an uncertain MCP response. Reusing the ID with different content fails. A proposed patch goes through Codex's normal interpretation and execution; there is no blind patch or arbitrary shell tool on the bridge.

The flow is request → job ID → result polling. Results are attached to their exact threadId and turnId, so a later turn cannot overwrite an earlier job. ChatGPT must call the result tool again to fetch later progress. This server cannot wake an already-finished ChatGPT response or initiate messages to it.

Recovery

Before dispatch, the bridge persists a reservation. A lost response becomes unknown, not an automatic retry. Restarting preserves the journal; get_result recovers by the saved turn ID. If no turn ID was confirmed, inspect the conversation locally and stop serve before explicitly releasing the reservation:

node dist/cli.js release-unknown --state-dir /private/path/cwb-project --job JOB_UUID --reason "Inspected Codex and confirmed the outcome" --confirm-inspected

This marks the journal entry failed; it does not undo or repeat execution. Exact recovery depends on experimental App Server history methods. If unsupported, preserve the journal and inspect locally. Completed results remain immutable, including any recorded truncation. The journal retains at most 1,000 jobs and never silently evicts retry IDs; archive it locally before creating a new binding.

Execution and data boundaries

  • A binding exposes one workspace and conversation. Remote tools cannot change the target, sandbox, model, authentication, or network permission.

  • One bridge process owns a state directory. Busy checks catch observed active turns, but there is no atomic lock across every Codex client: do not send manually into the same conversation while the bridge is working. Do not create multiple bindings to the same thread.

  • In direct modes, Codex receives the configured sandbox policy and on-request approvals. The bridge declines permission escalation for its own turns and does not grant approval on behalf of the local user. In queue mode, all execution and approval policy comes from the desktop conversation. Other clients' approval requests are left alone. Sandbox guarantees depend on the Codex version and OS.

  • read_file blocks directory escapes, symlink escapes, common credential paths, binary files and files over 1 MiB. Reads are limited to 500 lines / 50,000 characters. This filter applies to the file tool, not to everything the Codex model can read through its own tools.

  • Outputs are bounded and common token patterns are redacted. These are best-effort filters, not complete secret detection. Returned files and results are shared with the connected MCP client. Only connect a workspace you intend to share. Source text and command output remain untrusted input.

  • The private journal stores captured outputs, diffs, IDs and prompt hashes. Original prompt bodies are not separately stored by the bridge, but outputs may repeat them and Codex keeps its own history. Windows filesystem protection depends on the parent directory ACL; POSIX mode flags alone are not an ACL.

Development and compatibility

npm run typecheck
npm test
npm audit --omit=dev

Tests cover retry deduplication, restart uncertainty, exact-turn recovery, cross-thread isolation, early notifications, permission requests, cancellation, output bounds, filesystem boundaries, MCP schemas and a real child-process stdio round trip. CI runs on Windows and Ubuntu.

The backend implements initialize, thread/list, thread/read, thread/resume, turn/start, turn/interrupt, and experimental thread/turns/list / thread/items/list. Events include item/completed, turn/completed, and turn/diff/updated. Protocol changes can require updates. codex mcp-server is not used. Consult Codex App Server documentation and the installed binary's app-server --help / app-server generate-ts output.

See SECURITY.md for the trust model. MIT licensed; an independent project, not an OpenAI product.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables ChatGPT Web or another MCP client to inspect and develop a local workspace, read local Codex task history, and use the complete installed XcodeBuildMCP catalog through a small set of stable tools.
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Connects ChatGPT to a local developer workspace through MCP, enabling bounded repository analysis, file and image inspection, direct edits, command verification, and Git-aware review.
    22
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables ChatGPT conversations to directly inspect local workspaces and delegate coding tasks to a local Codex agent, with controlled concurrency, reusable sessions, and task/usage tracking.
    1,713 npm
    MIT