Codex Control Plane MCP
The Codex Control Plane MCP server provides durable, asynchronous orchestration of Codex Desktop tasks without requiring a long-lived MCP connection. Key capabilities include:
Durable Task & Operation Management
Submit long-running tasks (
codex_submit_task) and poll their status (codex_get_operation_status)Retry-safe idempotency via
client_request_idto recover from timeouts without duplicate turns
Plan Mode Workflows
Start (
codex_start_plan_workflow), poll (codex_get_workflow_status), approve (codex_approve_plan), and execute plans — managing both planning and execution phases
Approvals & Interaction Handling
List and answer pending interactions (
codex_list_pending_interactions,codex_answer_pending_interaction) so active turns can continue
Turn Control
Steer active turns with additional context, interrupt running turns (
codex_interrupt_turn) by turn/thread/operation/workflow ID
Chat & Project Management
List projects and chats, search across history and transcripts, get chat status and full content (
codex_list_projects,codex_search_chats,codex_get_chat, etc.)
Compatibility Write Tools
codex_start_chat,codex_send_message,codex_execute_planfor legacy clients
App-Server Management
Check and restart the
codex-app-serversubprocess (codex_get_app_server_status,codex_restart_app_server)
Runtime Capabilities & Health
Inspect models, sandbox readiness, hooks, and skills (
codex_get_runtime_capabilities); get a quick health check (codex_health_summary)
Diagnostics & Repair
Collect full diagnostic snapshots (
codex_collect_diagnostics), read redacted logs (codex_get_diagnostic_logs), analyze root causes (codex_analyze_issue), and run safe allowlisted repairs (codex_repair_issue, dry-run by default)
Progress Journaling
Compact journal of progress events (assistant text, plan deltas, token usage, model reroutes) available via status tools for orchestrators and troubleshooting
Operation state is persisted in a local SQLite database, enabling recovery across client timeouts and MCP process restarts.
Provides tools for driving Codex Desktop automation via MCP, with support for Hermes as a first-class client. It offers durable async operations, Plan Mode workflows, approvals, diagnostics, and recovery for long-running tasks.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Codex Control Plane MCP start a plan mode workflow to refactor the authentication module"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Codex Control Plane MCP
English | Русский
Reliable Codex Desktop automation for long tasks.
codex-control-plane-mcp turns Codex Desktop and codex-app-server into a
durable worker that an MCP client can drive safely. Send a task, get an
operationId or workflowId right away, poll until the work finishes, approve
Plan Mode when needed, then read the final report.
The server handles the awkward parts that thin wrappers usually leave to the caller: app-server startup, thread and turn creation, retry safety, duplicate prompt protection, Plan Mode, approvals, local history, diagnostics, and repair.
OpenClaw and Hermes are first-class clients, but the server is useful for any local orchestrator that needs Codex Desktop to do long-running work without holding one MCP call open for hours.
The short version
MCP client / orchestrator
-> submit a task or start a Plan Mode workflow
<- receive operationId or workflowId immediately
-> poll status
-> answer approvals or approve the plan
<- read final report, diagnostics, threadId, and turnIdThat gives you a simple contract:
no multi-hour MCP calls;
no duplicate Codex turns after a client retry;
no blind fire-and-forget task submission;
a local SQLite record of operations, workflows, turns, hooks, and diagnostics.
Related MCP server: Codex Control Plane MCP
Why not just call Codex directly?
Capability | Thin Codex wrapper | Codex Control Plane MCP |
Multi-hour tasks | blocking / fragile | durable async operation |
Client timeout recovery | manual | retry-safe |
Duplicate turn protection | no | active prompt detection |
Plan Mode workflow | human / manual | pollable workflow state |
Approvals and questions | blocking / opaque | pending interactions API |
Restart recovery | ad hoc | persisted operation state |
Diagnostics | logs only | health, diagnostics, repair tools |
For a more detailed decision guide, see docs/THIN_WRAPPERS.md.
Current support
Full live target: Windows with Codex Desktop and
codex-app-server.Linux and macOS: protocol-only checks for now.
Local-first: not intended to be exposed as a public network service.
Security model
This is a local-first control plane for trusted Codex Desktop environments.
Do not expose it as a network service without authentication.
Recommended first-run posture:
use
read-onlyfor untrusted repositories;use
on-requestapproval when testing new workflows;Plan Mode never runs with a
read-onlysandbox. If a caller requestsread-only, MCP raises that turn toworkspace-writeand reports the adjustment in status output;keep
state/,logs/,.env, and.codex/private.
What it does
Durable async queue for Codex write operations.
Retry-safe
client_request_idhandling.Active duplicate prompt detection.
SQLite leases and heartbeats for competing MCP processes.
Recovery after MCP restart during
thread/startorturn/start.Durable
turn/steerfor adding context to an active turn without creating a second turn.Durable
thread/forkfor branching an existing thread, with or without an initial message.Plan Mode workflows: start plan, poll, approve, execute, read final report.
Plan Mode runtime floor:
workspace-write, withruntimePolicyAdjustedin status when MCP raises aread-onlyrequest.Code review workflows through app-server
review/start, with polling and final report capture.Structured final reports with
output_schema.Thread lifecycle tools for archive, unarchive, and pollable compaction.
Workflow goal sync with Codex Desktop thread goals.
Image and local image inputs for turns that start through
turn/start.Pending approvals and questions exposed as pollable MCP state.
Turn interrupts by
threadId/turnId,operationId, orworkflowId.Runtime inventory for models, permission profiles, sandbox readiness, hooks, skills, provider features, account status, usage bands, rate-limit state, and supported app-server methods.
Health checks, diagnostics, issue analysis, and dry-run repairs.
MCP-owned hook history in SQLite for search, summaries, and fallback reads.
Redacted app-server progress journal for deltas, warnings, model reroutes, and token usage.
Structured MCP errors that automation code can branch on.
Write and control actions go through codex-app-server. The server does not
mutate Codex internal SQLite databases or transcript files.
Install
Recommended:
pipx install codex-control-plane-mcpOr run directly:
uvx codex-control-plane-mcpFrom GitHub:
python -m pip install "codex-control-plane-mcp @ git+https://github.com/aresyn/codex-control-plane-mcp.git"For local development:
git clone https://github.com/aresyn/codex-control-plane-mcp.git
cd codex-control-plane-mcp
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -e ".[dev]"
python -m pytest -qMCP client config
After installation, generate a config:
codex-control-plane-mcp-admin init --state-db .\state\codex-mcp-state.sqlite3 --projects-root C:\Users\you\ProjectsMinimal stdio entry:
{
"mcpServers": {
"codex-control-plane": {
"command": "codex-control-plane-mcp",
"args": []
}
}
}More copy-paste examples for Claude Desktop, Cursor, VS Code-style MCP clients,
local checkouts, installed packages, and central worker mode are available in
examples/mcp-client-configs.md.
Run the MCP stdio server:
codex-control-plane-mcpOr run it as a module:
py -m codex_control_plane_mcp.serverThe old openclaw-codex-mcp and openclaw-codex-mcp-hooks commands remain as
compatibility aliases for one release line.
Central worker mode
The default inline mode is still the simplest setup: one MCP process can submit
and execute operations. For OpenClaw, Hermes, or any setup with several MCP
clients, use a central worker instead.
Recommended local shape:
every MCP client uses the same
CODEX_HOMEandCODEX_MCP_STATE_DB;OpenClaw gateway entries run with
CODEX_MCP_EXECUTION_MODE=client;one long-running
codex-control-plane-mcp-workerprocess ownscodex-app-server, leases, queue slots, and resource locks;clients call
codex_submit_task, then poll status. They do not execute queued operations themselves.
Worker command:
$env:CODEX_MCP_EXECUTION_MODE = "worker"
codex-control-plane-mcp-workerSafe observation mode, useful before switching a live gateway:
codex-control-plane-mcp-worker --observeConcurrency defaults:
CODEX_MCP_MAX_ACTIVE_TURNS_GLOBAL=4
CODEX_MCP_MAX_ACTIVE_TURNS_PER_PROJECT=3
CODEX_MCP_MAX_ACTIVE_TURNS_PER_AGENT=3
CODEX_MCP_MAX_ACTIVE_TURNS_PER_THREAD=1
CODEX_MCP_MAX_ACTIVE_WRITE_TURNS_PER_PROJECT=1
CODEX_MCP_MAX_APP_SERVER_PENDING_REQUESTS=8For write turns in the same project, pass resource_keys to
codex_submit_task. Without them, workspace-write and danger-full-access
turns take a broad project write lock. With disjoint keys, the worker may run
several write turns in parallel.
New status tools:
codex_get_worker_statuscodex_get_queue_statuscodex_get_concurrency_statuscodex_get_worker_command_status
codex_get_operation_status also returns queueState, workerState,
slotState, and resourceLockState. A running turn has
slotState.claimed=true and a slotClaim with the worker id, slot type, and
claim time. codex_get_queue_status separates queued work from running turn
operations, auxiliary operations, active turn slots, and lock conflicts.
When a workflow is waiting for capacity, codex_get_workflow_status mirrors the
nested operation queue state in workflowOperationQueueState. Use
nextRecommendedAction="wait_for_worker_slot" for slot pressure and
nextRecommendedAction="wait_for_resource_lock" for write lock conflicts. Do
not create another operation for the same work while either action is returned.
First setup
The admin helper can generate a fuller client config, install hooks, and run a protocol smoke:
codex-control-plane-mcp-admin init --state-db .\state\codex-mcp-state.sqlite3 --projects-root C:\Users\you\ProjectsThe command prints a JSON block you can copy into an MCP client config. It does not print secrets or private prompts.
You can also install only the Codex hooks:
codex-control-plane-mcp-hooks install --state-db .\state\codex-mcp-state.sqlite3
codex-control-plane-mcp-hooks status
codex-control-plane-mcp-hooks doctorThe installer backs up ~/.codex/hooks.json, merges its handlers with your
existing hooks, stores stateDb as an absolute path, and writes prompts, visible
agent progress text, final answers, and turn status into the MCP state DB. Tool
calls and command outputs are not recorded by default. Restart Codex after
installing or changing hooks.
For turns launched through codex-app-server, the server mirrors the accepted
prompt, visible assistant messages, and turn status into the same SQLite
history. That keeps search and status reads useful even when app-server does not
execute user hooks itself.
Main workflows
Submit a durable task:
codex_submit_task
-> operationId
codex_get_operation_status(operationId)
-> queued / running / waiting_for_approval / completed / failedUse the same client_request_id when a caller retries after a transport timeout.
The retry returns the existing operation instead of creating another turn.
Attach screenshots or other image evidence:
codex_submit_task(
operation_type="start_chat",
message="Analyze this screen.",
input_items=[
{"type": "localImage", "path": ".\\screens\\error.png", "detail": "low"},
{"type": "image", "url": "https://example.com/screenshot.png", "detail": "high"}
]
)Image inputs are accepted only for operation types that start a new turn:
start_chat, send_message, execute_plan, and fork_thread with an initial
message. MCP sends the path or URL to codex-app-server, but operation status
and diagnostics return only safe metadata such as type, detail, size, extension,
and hashes. Binary image content, raw URLs, and full local image paths are not
stored in public status payloads.
Steer an active turn:
codex_submit_task(operation_type="steer_turn", thread_id=..., expected_turn_id=..., message=...)
-> operationId
codex_get_operation_status(operationId)
-> follows the target turn until completed / failed / interruptedUse steer_turn only while the target turn is active. For a completed thread,
use send_message instead.
Fork a thread:
codex_submit_task(operation_type="fork_thread", source_thread_id=...)
-> operationId
codex_get_operation_status(operationId)
-> completed, threadId=<forkedThreadId>Start work in the fork right away:
codex_submit_task(operation_type="fork_thread", source_thread_id=..., message=...)
-> operationId
codex_get_operation_status(operationId)
-> follows the first turn in the forked threadUse client_request_id for retry-safe fork requests. Without it, each call is
treated as a new fork request. threadId in operation status is the forked
thread; the source thread is reported in forkState.sourceThreadId.
Manage thread lifecycle:
codex_archive_thread(thread_id)
-> completed
codex_unarchive_thread(thread_id)
-> completed
codex_start_thread_compaction(thread_id)
-> actionId
codex_get_thread_compaction_status(actionId)
-> running / completed / unknown_after_app_server_exitArchive and unarchive are audit actions around app-server thread/archive and
thread/unarchive. They refuse to run while the thread has an active turn or a
pending interaction. Compaction uses its own lightweight actionId because
thread/compact/start is asynchronous. Public thread/delete is intentionally
not exposed.
Ask for a structured final report:
codex_submit_task(operation_type="start_chat", message=..., output_schema={...})
codex_approve_plan(workflowId, output_schema={...})
-> operationId / executionOperationId
codex_get_operation_status(operationId)
codex_get_workflow_status(workflowId)
-> finalReport.text + finalReport.structuredoutput_schema is passed to app-server turn/start and is tracked by a schema
hash in status output. Object schemas must use the strict form required by Codex:
set additionalProperties to false. MCP stores the final assistant message
as readable text, then parses JSON object output into finalReport.structured
when Codex returns valid JSON. Plain text still works and stays available in
finalReport.text.
MCP does not extract hidden chain-of-thought and does not store raw tool payloads or command output in final reports.
Drive Plan Mode:
codex_start_plan_workflow
-> workflowId
codex_get_workflow_status(workflowId)
-> wait_plan / review_plan / execute_plan
codex_approve_plan(workflowId)
-> executionOperationId
codex_get_workflow_status(workflowId)
-> finalReportPlan Mode has a runtime floor. The public default write policy is still
read-only and on-request, but Plan Mode needs a writable workspace on
Windows. If the caller or server default resolves to read-only, MCP sends
workspace-write to codex-app-server and returns requestedSandbox,
effectiveSandbox, and runtimePolicyAdjusted in workflow and operation
status.
Mirror a workflow goal into Codex Desktop when the client has one:
codex_start_plan_workflow(goal="Review the migration plan", goal_completion_action="clear")
codex_get_workflow_status(workflowId, refresh_live_goal=true)
-> threadGoal.syncState + threadGoal.currentGoalMCP writes a thread goal only when the client passes goal. Managed goals use
clear after completion by default. Use set_complete or leave when the goal
should remain visible after the workflow ends. Normal workflow polling is
passive; use refresh_live_goal=true only when you want MCP to call live
app-server goal methods.
Run a Codex code review:
codex_start_review_workflow(thread_id=..., target_type="base_branch", base_branch="main")
-> workflowId
codex_get_workflow_status(workflowId)
-> wait_review / read_review_reportOr let MCP create a service thread for a local checkout:
codex_start_review_workflow(cwd=..., target_type="uncommitted_changes")
-> workflowId
codex_get_workflow_status(workflowId)
-> reviewThreadId + reviewTurnId + finalReportReview workflows do not write files by themselves. They run inside the selected
Codex sandbox and approval policy. Use client_request_id when a caller may
retry the start request after a transport timeout.
Handle approvals and questions:
codex_list_pending_interactions
codex_answer_pending_interactionStart diagnostics with:
codex_get_runtime_capabilities
codex_health_summary
codex_collect_diagnostics
codex_analyze_issue
codex_repair_issueRepair actions default to dry_run=true.
Status and diagnostic tools also return agentGuidance and
agentGuidanceText when MCP sees a blocker, failed state, stale run, pending
interaction, duplicate prompt, auth problem, rate limit, or unsafe recovery
loop. Agents should follow agentGuidance.instructions before deciding to
retry or stop. If agentGuidance.loopGuard.allowed=false, stop automatic
recovery, collect diagnostics, and ask a human. Do not create a new
client_request_id after a timeout unless the guidance explicitly says to start
a replacement workflow.
For a broken Plan Mode workflow, use
retry_workflow_with_runtime_policy. It creates a new workflow with the selected
sandbox and approval policy, links it to the old workflow through
workflowRetryState, and does not revive the old terminal turn.
codex_health_summary is about current readiness by default. Old stale or
orphaned rows are reported in historicalDebt, but they do not make fresh
orchestration look broken when the worker, queue, and app-server are currently
healthy. Use targeted cleanup for that debt instead of blocking new work.
Status payloads now separate freshness signals:
operationRowAgeSeconds: age of the durable operation row;turnFreshness.lastProgressAgeSeconds: age of the last turn progress event;workerFreshness.heartbeatAgeSeconds: age of the worker heartbeat;stalenessMeaning="operation_row_age"for the compatibilitystalenessSecondsfield.
Public status payloads are agent-safe. Operation and workflow status return
requestSummary instead of raw request; it contains ids, runtime policy,
scheduling intent, input item state, output schema hash, resource keys, and
text hashes. It does not include the full prompt, full instructions, raw title,
raw image URL/path, exact token counts, raw command output, or private paths.
Use your own stored task text plus requestSummary.*.sha256 for correlation.
codex_get_queue_status only recommends wait_for_worker_slot when there is
actual queued work blocked by slots. If there are running turns but
queueSummary.queued == 0, the queue action is none.
Runtime capabilities
Use codex_get_runtime_capabilities before orchestration or after reconnect. It
starts the MCP-owned app-server if needed, calls short best-effort inventory
methods, and returns a cached snapshot for five minutes.
In client mode, the client process does not start its own app-server for live
inventory. It returns a passive worker-managed snapshot when one exists. With
refresh=true, it queues a worker command and returns refreshCommandId; poll
codex_get_worker_command_status to read the refreshed inventory.
The response includes:
model count, default model, hidden flags, input modalities, reasoning efforts, and service tier count;
permission profiles by
idanddescription;Windows sandbox readiness;
provider capabilities for web search, image generation, and namespace tools;
hook and skill counts without raw hook commands or absolute skill paths;
redacted account status, coarse usage bands, and operational rate-limit state;
supported app-server schema methods with a compact source, version, and hash.
Account inventory is safe to show to an orchestrator. It reports whether Codex is authenticated, the account and plan type, whether an email exists, whether usage data is available, and whether a rate limit or credits issue is visible. It does not return raw email, account identifiers, credit balances, spend limits, exact spend used, daily usage buckets, or exact token counts.
If one inventory method times out or fails, the tool still returns ok=true
with runtimeCapabilities.status="partial" and a machine-readable warning in
methodResults. Set refresh=true to bypass the cache. codex_health_summary
shows a small runtimeCapabilities subset from the last collected snapshot and
does not start app-server on its own. Pass include_account=false when a client
does not need account, usage, or rate-limit status.
Progress journal
codex_get_turn_status and codex_get_operation_status include a compact
progressEvents block by default. It captures app-server-visible progress such
as assistant text deltas, plan deltas, reasoning summary text, token usage,
model reroutes, and warnings.
The journal helps with orchestration and troubleshooting. It does not extract hidden chain-of-thought. It also does not store raw tool payloads, command output, or full unified diffs by default. Diff events are reduced to safe counts, such as changed line count and diff size.
Use progress_events=0 when a client wants the older, message-only status
shape. Use progress_max_chars to cap returned progress text.
Public status returns token usage as coarse bands, not exact token counts. Raw
audit surfaces may keep redacted event payloads for debugging, but orchestrators
should treat tokenUsage.totalTokensBand and related band fields as the public
contract.
Tool surface
Stable orchestration tools:
codex_submit_taskcodex_get_operation_statuscodex_start_plan_workflowcodex_start_review_workflowcodex_get_workflow_statuscodex_approve_plancodex_list_pending_interactionscodex_answer_pending_interactioncodex_interrupt_turncodex_archive_threadcodex_unarchive_threadcodex_start_thread_compactioncodex_get_thread_compaction_statuscodex_get_runtime_capabilitiescodex_health_summarycodex_collect_diagnosticscodex_repair_issue
Compatibility and read tools:
codex_start_chatcodex_send_messagecodex_execute_plancodex_list_projectscodex_list_project_chatscodex_list_active_chatscodex_search_chatscodex_get_chat_statuscodex_get_chatcodex_get_turn_statuscodex_restart_app_servercodex_get_app_server_statuscodex_get_diagnostic_logscodex_analyze_issue
New clients should use durable operations and workflows. Low-level write tools stay available for compatibility.
Read and diagnostic calls are bounded for agent loops. codex_list_projects
defaults to compact cached output, codex_search_chats can return
timeBudgetExhausted=true instead of blocking on a full refresh, and chat reads
prefer tracked turn plus hook history before legacy KB fallback. Diagnostics are
scoped-first: scopedFindings drive the next action, while
backgroundFindings are historical context.
See docs/API_CONTRACT.md for schemas, error shape, stable tool groups, and versioning rules.
Result contract
Every tool declares an outputSchema and returns MCP structuredContent.
Success:
{"ok": true}Domain or tool error:
{
"ok": false,
"error": {
"code": "CODEX_ERROR_CODE",
"message": "Human readable message",
"details": {},
"retryable": false
}
}Call codex_health_summary on startup and reconnect. The version block
contains serverName, serverVersion, contractVersion, toolSurfaceHash,
guideHash, guideVersion, recommended startup/write tools, and
stable/compatibility tool lists.
Agents can discover the operating contract without reading this README.
tools/list includes:
codexMcpGuide: compact machine-readable guide with capabilities, flows, global rules, and runtime limits;toolGroups: ordered groups of preferred tools;recommendedStartupTool="codex_health_summary";recommendedPrimaryWriteTool="codex_submit_task".
Every tool also has annotations.codexMcp with its role, follow-up tools,
idempotency rule, passive-read flag, and mayStartTurn flag. If a client
library hides top-level tools/list fields, call
codex_get_agent_contract(detail="compact") or
codex_get_agent_contract(detail="full", include_examples=true).
Configuration
Configuration can come from environment variables or from a JSON file referenced
by CODEX_CONTROL_PLANE_MCP_CONFIG. The old OPENCLAW_CODEX_MCP_CONFIG name is
still accepted as a fallback.
Common variables:
CODEX_HOME: Codex home directory. Defaults to%USERPROFILE%\.codex.CODEX_PROJECTS_ROOT: project root scanned by catalog and read tools.CODEX_ALLOWED_ROOTS: semicolon-separated path allowlist.CODEX_PROJECTS_REGISTRY: optional JSON project registry.CODEX_MCP_STATE_DB: local MCP state DB.CODEX_CONTROL_PLANE_MCP_LOG: log file path.CODEX_MCP_HOOK_HISTORY_ENABLED: enables SQLite hook history. Defaults totrue.CODEX_MCP_HOOK_HISTORY_MAX_TEXT_CHARS: per-message hook capture limit.CODEX_KB_HISTORY_PROJECTS_ROOT: optional legacy normalized KB history root.CODEX_BINARY_PATH: optional explicit Codex binary path.CODEX_MCP_DEFAULT_SANDBOX: default write sandbox. Defaults toread-only.CODEX_MCP_DEFAULT_APPROVAL_POLICY: default write approval policy. Defaults toon-request.CODEX_MCP_DEFAULT_MODEL: default Codex model passed to app-server.CODEX_MCP_DEFAULT_EFFORT: default effort level.CODEX_MCP_MAX_IMAGE_INPUT_ITEMS: max image attachments percodex_submit_task. Defaults to10.CODEX_MCP_MAX_IMAGE_INPUT_BYTES: max bytes for one local image input. Defaults to20000000.CODEX_MCP_TURN_STALL_TIMEOUT_SECONDS: inactivity threshold for stalled-turn reporting. Defaults to900.CODEX_MCP_STALLED_TURN_ACTION: stalled-turn policy. Defaults todiagnose_only.CODEX_MCP_APPROVAL_RESPONSE_TIMEOUT_SECONDS: pending interaction timeout.DEEPSEEK_ENV_PATH: optional.envfile for DeepSeek summary settings.DEEPSEEK_SUMMARY_ENABLED: enables or disables remote summary calls.
The write policy values are defaults, not hard limits. A client call can pass
sandbox or approval_policy explicitly when a trusted workflow needs a
different posture.
Plan Mode is the exception to pure pass-through behavior: read-only is treated
as too restrictive for Plan Mode on Windows and is raised to workspace-write.
More permissive per-call values, such as workspace-write, are passed through.
Example:
$env:CODEX_CONTROL_PLANE_MCP_CONFIG = Join-Path (Get-Location) "examples\codex-control-plane-mcp.config.json"
$env:CODEX_MCP_DEFAULT_SANDBOX = "read-only"
$env:CODEX_MCP_DEFAULT_APPROVAL_POLICY = "on-request"
py -m codex_control_plane_mcp.serverSee examples/codex-control-plane-mcp.config.json.
Reliability model
The server is built for common local orchestration failures:
MCP client timeout after task submission.
Repeated submit with the same
client_request_id.Repeated submit without an idempotency key but with the same active prompt.
MCP process restart between app-server
thread/startandturn/start.Two MCP processes sharing one SQLite state DB.
App-server exit while a turn is active.
Pending approval tied to an old app-server generation.
App-server or transcript gaps where hook history still captured the prompt, visible agent text, final answer, and completion status.
These cases are stored in durable operation, workflow, turn, hook, and pending
interaction state. Terminal statuses are explicit.
unknown_after_app_server_exit is not treated as success.
Safety
Live smoke prompts must include
MCP LIVE TEST / DO NOT MODIFY FILES.Repairs default to
dry_run=true.Forced app-server restart can mark active turns as unknown or orphaned. Prefer
restart_app_server_idle.
Checks
Fast local checks:
python -m pytest -q
python -m compileall -q openclaw_codex_mcp codex_control_plane_mcp tests scripts
git diff --checkProtocol-only MCP smoke:
python .\scripts\mcp_live_smoke.py --scenario protocolSafe live smoke with real Codex Desktop/app-server:
python .\scripts\mcp_live_smoke.py --scenario safe-operation --cwd <PROJECT_ROOT>Full live regression:
python .\scripts\mcp_live_smoke.py --scenario full --safe-restart --cwd <PROJECT_ROOT>External MCP client for development and long live tests:
python .\scripts\external_mcp_client.py daemon-start
python .\scripts\external_mcp_client.py daemon-restart-mcp --reason after_code_change
python .\scripts\external_mcp_client.py run-live-test --scenario full --archive-reportUse the external client when you need to test the current checkout as a real MCP
client without restarting Codex Desktop. It runs an independent daemon, keeps
its own MCP stdio subprocess, and can restart only that subprocess after code
changes. Live test findings are written to corrective_action_plan.md; previous
reports can be archived with --archive-report.
See docs/EXTERNAL_MCP_CLIENT.md for the daemon commands and the available live scenarios.
See docs/RELEASE_CHECKLIST.md. For public launch positioning, see docs/PUBLICATION_GUIDE.md.
Packaging
Build locally:
python -m pip install build
python -m buildThe wheel includes the MCP server, the hook installer, the admin helper, and the bundled Codex hook module.
The normal install path is:
pipx install codex-control-plane-mcpor:
uvx codex-control-plane-mcpContributing
Read CONTRIBUTING.md and SECURITY.md before opening issues that include diagnostics.
Good GitHub topics for this repo:
python, mcp, mcp-server, model-context-protocol, openai-codex,
codex, codex-desktop, agent-tools, ai-agents, developer-tools,
automation, orchestration, agentic-workflows, long-running-tasks,
openclaw, hermes, hermes-agent.
Available Tools
38 toolscodex_adopt_workflow_planB
Adopt a valid newer Plan Mode candidate already present in the workflow thread. Use this only when status or diagnostics reports an adoptable plan. Next poll codex_get_workflow_status.
Inputs: workflow_id (required), candidate_turn_id (required), candidate_plan_hash (required), client_request_id, +2 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_analyze_issueA
Analyze scoped diagnostics and recommend safe next actions. Use this after collect_diagnostics or when a human needs a compact root-cause summary. Follow agentGuidance rather than inventing retries.
Inputs: problem_text, operation_id, workflow_id, thread_id, +6 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_answer_pending_interactionB
Answer one pending Codex interaction so a turn can continue. Use this only for a listed interaction id. Next poll the owning operation, turn, or workflow.
Inputs: interaction_id (required), decision, decision_payload, answers, +6 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_approve_planA
Approve the latest ready plan and queue execution. Use this after codex_get_workflow_status reports plan_ready and a valid latestPlan. Next poll codex_get_workflow_status with the same workflowId.
Inputs: workflow_id (required), client_request_id, message, output_schema, +4 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_archive_threadB
Archive a known Codex thread through the worker or app-server command lane. Use this only when the thread has no active work. Next poll codex_get_worker_command_status when commandId is returned.
Inputs: thread_id (required), project_id, timeout_seconds, refresh_catalog. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_collect_diagnosticsB
Collect a scoped diagnostic snapshot with compact evidence and guidance. Use this before repair when status reports failed, stale, orphaned, or degraded state. It does not execute repairs.
Inputs: operation_id, workflow_id, thread_id, turn_id, +7 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_execute_planB
Compatibility write for executing an approved plan. Prefer codex_approve_plan or codex_submit_task with operation_type='execute_plan'. In client mode this delegates to durable workflow execution.
Inputs: workflow_id, chat_id, project_id, client_request_id, +8 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_agent_contractA
Read the machine-readable agent guide for this MCP server. Use this when tools/list metadata was unavailable or when a client wants the full contract examples. It is passive and the next normal startup call is codex_health_summary.
Inputs: detail, client_type, include_examples. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_app_server_statusA
Read MCP-owned app-server status without starting it. Use this with worker, queue, and concurrency status to verify active work. In client mode prefer worker-derived active turns over local guesses.
Inputs: include_recent_events. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_chatB
Read bounded chat content from hook history, transcripts, or legacy fallback. Use this for context recovery and final report inspection. It is not a write path and should not trigger retries.
Inputs: chat_id (required), project_id, range, include_tool_calls, +10 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_chat_statusA
Read lightweight chat status and safe previews. Use this to inspect a known thread without starting live work. Next call codex_get_chat for content or codex_submit_task for a new operation.
Inputs: chat_id (required), project_id, preview_max_chars. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_concurrency_statusC
Read active turn counts and scheduler resource locks. Use this with queue status when diagnosing parallel work. Active locks are not a retry instruction by themselves.
Inputs: include_locks, limit. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_diagnostic_logsA
Read redacted diagnostic log and app-server audit entries with filters. Use this only for targeted troubleshooting, not normal polling. Raw payload mode is for local audit and remains secret-redacted.
Inputs: source, workflow_id, thread_id, turn_id, +6 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_operation_statusA
Poll a durable operation from storage. Use this after codex_submit_task and follow nextRecommendedAction, pollRecommended, queueState, and agentGuidance. Never create a new retry while an existing operation is active.
Inputs: operation_id (required), last_messages, message_max_chars, progress_events, +2 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_queue_statusA
Read durable queue state, queued reasons, running operations, and worker assignment. Use this to understand slot pressure or lock waits. Do not retry when queued work already exists.
Inputs: status, limit. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_runtime_capabilitiesA
Read compact runtime capabilities, models, permissions, hooks, account state, and supported methods. Use this after health or before new work. In client mode refresh queues a worker command.
Inputs: refresh, cwd, timeout_seconds, include_models, +3 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_thread_compaction_statusA
Poll a thread compaction action. Use this with actionId from codex_start_thread_compaction. It is passive and should return a bounded status or guidance.
Inputs: action_id (required), include_events. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_turn_statusB
Read one tracked Codex turn, including safe progress and terminal evidence. Use this when you have threadId and turnId. Do not infer stalled state from row age alone.
Inputs: turn_id (required), thread_id, last_messages, message_max_chars, +2 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_worker_command_statusA
Poll a worker command created by a client-mode control action. Use this for archive, unarchive, compaction, restart, runtime refresh, and delegated lifecycle commands. Keep include_result=false unless the result is needed.
Inputs: command_id (required), include_result, max_result_chars. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_worker_statusB
Read central worker heartbeat and execution-mode state without starting app-server. Use this when health or queue guidance says inspect_worker_health. Next compare with queue and concurrency status.
Inputs: include_recent_commands, limit. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_get_workflow_statusA
Poll workflow state from storage by default. Use this for Plan Mode, execution, and review workflows. Follow nextRecommendedAction and do not create replacement work unless guidance tells you to.
Inputs: workflow_id (required), last_messages, message_max_chars, include_events, +2 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_health_summaryA
Read compact MCP readiness and contract metadata. Use this first on startup, reconnect, and after MCP restart. Next inspect runtime capabilities or follow agentGuidance if health is degraded.
Inputs: operation_id, workflow_id, thread_id, turn_id, +6 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_interrupt_turnB
Interrupt a running Codex turn by direct ids or durable operation/workflow context. Use this for explicit cancellation or stop conditions. Next poll status until terminal evidence is visible.
Inputs: thread_id, turn_id, operation_id, workflow_id, +1 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_list_active_chatsA
List chats that look active from tracked, hook, transcript, or cached evidence. Use this for operator inspection, not for creating retries. Next call codex_get_turn_status or codex_get_operation_status when ids are available.
Inputs: project_id, include_waiting_for_user, include_waiting_for_approval, include_running, +3 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_list_pending_interactionsA
List pending approvals, input requests, or elicitation requests. Use this when operation or workflow status reports pending interaction. Next answer with codex_answer_pending_interaction or ask a human.
Inputs: thread_id, turn_id, operation_id, workflow_id, +2 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_list_project_chatsA
List chats for one project from the bounded read model. Use this to find existing threads before continuation or review. Next call codex_get_chat_status, codex_get_chat, or codex_submit_task.
Inputs: project_id (required), include_archived, limit, cursor, +3 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_list_projectsA
List known Codex projects from registry, hook history, transcripts, and cached Codex state. Use this before preflight or submit when you need a project reference; later tools accept projectId, project name, or project path and return canonical projectId. Next call codex_preflight_project_run for a concrete project.
Inputs: compact, limit, refresh, include_private_details, +1 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_preflight_project_runA
Check whether a project is safe to use before a Codex run. Use this after project discovery and before write operations. Do not treat skipped worker-managed account checks as hard auth failures.
Inputs: project_id, cwd, model, sandbox, +4 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_repair_issueB
Run an allowlisted repair action with dry-run first by default. Use this only when diagnostics or agentGuidance recommends a specific action. Stop when loopGuard.allowed is false.
Inputs: action (required), diagnosis_id, thread_id, turn_id, +11 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_restart_app_serverA
Restart only the MCP-owned codex-app-server subprocess. Use this only when guidance recommends restart and active work is absent or explicitly handled. In client mode this delegates to the worker command lane.
Inputs: start_after_restart, timeout_seconds, force. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_search_chatsB
Search chat history through the MCP-owned index and safe fallback sources. Use this for discovery or recovery when ids were lost. Do not use search results as proof that a turn is still active.
Inputs: query (required), match_mode, project_id, include_archived, +7 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_send_messageA
Compatibility write for sending a message to an existing Codex thread. Prefer codex_submit_task with operation_type='send_message' for durable long work. In client mode this delegates to the durable queue.
Inputs: chat_id (required), message (required), project_id, mode, +6 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_start_chatB
Compatibility write for starting a new Codex chat. Prefer codex_submit_task with operation_type='start_chat' for durable long work. In client mode this delegates to the durable queue.
Inputs: project_id (required), message (required), title, cwd, +7 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_start_plan_workflowB
Start a durable Plan Mode workflow and return workflowId immediately. Use this when a plan must be prepared before implementation. Next poll codex_get_workflow_status, then call codex_approve_plan when latestPlan is ready.
Inputs: project_id (required), message (required), title, cwd, +11 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_start_review_workflowB
Start a durable Codex review workflow and return workflowId immediately. Use this for code review tasks. Next poll codex_get_workflow_status for progress and final report.
Inputs: target_type (required), thread_id, project_id, cwd, +11 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_start_thread_compactionA
Start context compaction for a known thread and return actionId. Use this after active work is terminal. Next poll codex_get_thread_compaction_status.
Inputs: thread_id (required), project_id, timeout_seconds. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_submit_taskA
Queue a durable Codex write operation and return operationId immediately. For project-scoped work, pass project_id from codex_list_projects.projectId; project name or project path are accepted aliases and MCP stores the canonical projectId. Always pass client_request_id and poll codex_get_operation_status.
Inputs: operation_type (required), client_request_id, agent_id, resource_keys, +25 more. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
codex_unarchive_threadA
Unarchive a known Codex thread through the worker or app-server command lane. Use this only for an existing archived thread. Next poll codex_get_worker_command_status when commandId is returned.
Inputs: thread_id (required), project_id, timeout_seconds, refresh_catalog. Returns: ok, error, agentGuidance, agentGuidanceText, +1 more
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 38 tools
Each tool has a clearly distinct purpose with detailed descriptions that specify when to use it and what to do next. Overlaps like codex_execute_plan vs codex_approve_plan are resolved by marking the former as a compatibility wrapper. No two tools perform the same action.
All tools follow the consistent pattern codex_<verb>_<noun> with lowercase and underscores. Verbs like get, list, start, submit are used uniformly, and there is no mixing of styles.
38 tools is high but each serves a distinct operation within the control plane domain, covering workflow lifecycle, diagnostics, chat, worker, and project management. A few redundancies exist for backward compatibility, but overall the count is justified by the breadth of functionality.
The tool surface covers the complete lifecycle: health checks, diagnostics, planning, execution, review, chat management, project discovery, and cleanup (archive/unarchive). Missing operations like deletion are not essential for a control plane, and the set provides no dead ends for common workflows.
Maintenance
Related MCP Connectors
Durable background job execution, async task scheduling, and state persistence for AI agents.
Reliable async execution for agent tool calls: schema gating, retries, idempotency, audit trail.
Workflow planning, recovery checkpoints, coordination, fixtures, and compatibility tools for agents.
Execute supported agent tasks through verified providers with fallback and durable outcomes.
Related MCP Servers
- FlicenseNot gradedqualityAmaintenanceEnables MCP clients to submit and manage durable, asynchronous Codex Desktop tasks, including polling, approvals, Plan Mode workflows, and final reports. It provides retry-safe operations, recovery, diagnostics, and local state for reliable long-running automation.-
- FlicenseNot gradedqualityAmaintenanceEnables MCP clients to drive Codex Desktop and codex-app-server as a durable asynchronous worker for long-running tasks, with polling, approvals, Plan Mode workflows, retry safety, diagnostics, and final reporting. It also provides recovery, queueing, and repair tools for reliable local automation.-
- FlicenseNot gradedqualityAmaintenanceEnables durable, retry-safe automation of long-running Codex Desktop tasks through MCP, with async operations, polling, Plan Mode workflows, approvals, diagnostics, and restart recovery.-
- FlicenseNot gradedqualityBmaintenanceEnables MCP clients to submit, monitor, approve, and recover long-running Codex Desktop tasks without blocking for hours. It provides retry-safe operations, Plan Mode workflows, diagnostics, and central worker coordination for durable automation.-