An MCP server for creating, messaging, and steering Codex tasks through a running App Server on the same host.
Requires Python 3.11+, uv, and an authenticated Codex App Server with a Unix WebSocket control socket. Git is required for worktree launches. The bridge runs as the same user and on the same host as App Server.
From a clone of this repository:
uv sync --frozen --no-dev
.venv/bin/codex-thread-bridge --help
codex mcp add codex-thread-bridge -- /absolute/path/codex-thread-bridge/.venv/bin/codex-thread-bridgeThe default socket is $CODEX_HOME/app-server-control/app-server-control.sock;
CODEX_HOME defaults to ~/.codex. Use --socket /path/to.sock to override it.
Authentication and model usage belong to the existing App Server.
On Windows, the bridge uses codex app-server proxy --sock as a raw WebSocket
byte relay. On Unix, it connects directly to the socket. Use --transport proxy
to select the relay explicitly, and --codex-binary /path/to/codex if the CLI
is not on PATH. The equivalent environment variables are
CODEX_THREAD_BRIDGE_TRANSPORT and CODEX_THREAD_BRIDGE_CODEX.
After changing bridge code or MCP configuration, request a refresh with:
uv run --locked codex-thread-bridge-reloadThe command accepts --socket, asks for y/N confirmation, and queues a refresh
for loaded tasks. Its response does not confirm that every task has refreshed.
| Tool | Behavior |
|---|---|
get_capabilities |
Report server identity and bridge capabilities |
create_thread |
Create a retained task in an existing directory, with an optional title and initial prompt |
create_worktree_thread |
Create a retained, locked Git worktree and a task at a specified commit |
update_thread_permissions |
Apply and verify permissions for an idle task with an expected identity |
send_message_to_thread |
Resume an idle task and start a turn without settings overrides |
steer_thread |
Append a message to the active turn identified by expected_turn_id |
list_threads |
List unarchived backend tasks without loading them |
read_thread |
Read task metadata and paginated history without resuming |
wait_thread |
Wait up to 50 seconds for a specified recent turn |
get_goal |
Read persistent Goal state |
get_operation |
Read the retained receipt for a mutation request |
Tool schemas are exposed through MCP. Their definitions are in server.py.
Call create_thread with these MCP arguments:
{
"request_id": "repository-overview-001",
"cwd": "/absolute/path/to/project",
"title": "Repository overview",
"prompt": "Summarize the project structure."
}Pass the returned threadId and turnId to wait_thread. Use
send_message_to_thread for an idle task or steer_thread for an active turn.
Each intentional new message requires a new request_id.
create_threaddefaults to sandboxread-onlyand approval policynever. Expliciton-requestapproval requires App Server Auto-review. Omitted model and reasoning effort use server defaults. Creation rejects explicit network-enabled read-only policies; permission updates accept them.- Permission updates require the task's expected identity and an idle task. The idle check and update are separate operations, so concurrent clients can race them. Workspace writable roots cannot be existing files, sockets, or devices.
- Each mutation uses a stable
request_id. Repeating it with matching arguments returns the recorded receipt without repeating or continuing the operation.acceptedreports API acceptance; turn completion is reported bywait_thread. Failed or uncertain operations can leave tasks, turns, or worktrees behind;get_operationreturns the recorded outcome and known IDs. - Receipts persist in
$XDG_STATE_HOME/codex-thread-bridge, defaulting to~/.local/state/codex-thread-bridge.--state-diroverrides this location. Deleting this state discards request deduplication history. - Worktree launches require a full local commit ID and an absent, canonical
absolute destination outside existing repositories. Worktrees are detached,
locked, and retained until manual cleanup. Dirty files are not copied, and Git
hooks and checkout filters are disabled. Approval policy is
never;expected_sandbox_policyverifies returned settings rather than applying overrides. - Project IDs belong to App Server's registry. Desktop controls its own project association and task listing. Worktrees created by the bridge have a manual lifecycle rather than a Desktop-managed lifecycle.
- New and resumed turns carry bridge instructions as
toolOutputwith the bridge tool's name. The bridge leaves client-side tool calls and approval requests unanswered so it cannot consume another client's shared callback. A capable client such as Desktop must be subscribed to the thread to handle them; the bridge does not establish that subscription or provide interactive approvals. Dispatch keeps the shared connection open so concurrent reads can finish.
uv sync --frozen --group dev
uv run pytest
uv run ty check src
uv run ruff check .
uv run ruff format --check .
uv buildTests use a fake App Server and temporary Git repositories. Test temporary
directories must be outside existing repositories; pytest accepts --basetemp.
The source and tests define the detailed behavior. Contribution requirements are in CONTRIBUTING.md.
- Codex App Server API documentation
- RPC method definitions
- Request, response, and notification types
- App Server implementation
- Shared callback routing in Codex 0.153.4
MIT licensed. Independent project, not affiliated with or endorsed by OpenAI.