@leo000001/codex-mcp 2.1.4 → 2.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - **Disk persistence** — session metadata (`meta.json`), event logs (`events.jsonl`), and results (`result.json`) are now persisted to `~/.codex-mcp/state/` (configurable via `CODEX_MCP_STATE_DIR`). Surviving sessions are recovered on server restart with status `error` (reason: `server_restart`); completed results remain queryable.
13
+ - **Graceful shutdown with stdin drain** — when the MCP client disconnects (stdin closes), the server now waits up to 15 s (Windows) / 10 s (Unix) for active sessions to complete before forcing shutdown, matching claude-code-mcp behavior.
14
+ - **Orphan process reaper** — on startup, detects and terminates leaked `codex app-server` child processes from previous crashed server runs using PID + spawn-timestamp identity verification (cross-platform: `wmic` on Windows, `ps`/`/proc` on Linux).
15
+ - **Long-polling** — `codex_check(action="poll")` now accepts `pollOptions.waitMs` (max 120 s). When set, the server waits for new events/actions/status changes before returning, eliminating the approval-auto-decline race caused by sparse polling. Max 4 concurrent waiters per session.
16
+ - **TTL warning events** — sessions approaching idle/running TTL expiry receive a `codex-mcp/ttl_warning` progress event 60 s before cleanup (emitted once per session).
17
+ - **STATE_DIR lockfile** — prevents multiple server instances from corrupting the same state directory.
18
+ - **Tiered flush strategy** — critical events (approvals, results, errors) are flushed to disk immediately; progress/output events are batched every 100 ms.
19
+ - **Three-dimensional retention policy** — old sessions are pruned by age (7 days), count (200), and disk size (500 MB).
20
+
10
21
  ### Breaking Changes
11
22
 
12
23
  - `approvalPolicy`, `sandbox`, and `effort` are now **required** parameters in the `codex` tool — callers must explicitly set based on their own permission level and task complexity
package/README.md CHANGED
@@ -8,12 +8,16 @@ MCP server that wraps [OpenAI Codex](https://github.com/openai/codex) — start
8
8
 
9
9
  ## Features
10
10
 
11
- - **4 tools, full capability** — `codex`, `codex_reply`, `codex_session`, `codex_check`
11
+ - **5 tools, full capability** — `codex_setup`, `codex`, `codex_reply`, `codex_session`, `codex_check`
12
12
  - **Async non-blocking** — sessions run in background, poll for results
13
13
  - **Complete permission management** — three-layer model: approval policy, sandbox isolation, async approval arbitration
14
14
  - **Zero config** — inherits your local `~/.codex/config.toml` automatically
15
15
  - **Session management** — list, inspect, cancel, interrupt, fork sessions
16
16
  - **Event streaming** — cursor-based pagination with pin-protected event buffer
17
+ - **Disk persistence** — session state, event logs, and results survive server restarts (`~/.codex-mcp/state/`)
18
+ - **Long-polling** — `codex_check` supports `pollOptions.waitMs` to wait for new events instead of busy-polling
19
+ - **Graceful shutdown** — stdin drain logic waits for active sessions before exiting
20
+ - **Orphan reaping** — leaked child processes from crashed runs are automatically cleaned up on startup
17
21
  - **Static read-only resources** — `codex-mcp:///server-info`, `codex-mcp:///compat-report`, `codex-mcp:///config`, `codex-mcp:///gotchas`, `codex-mcp:///quickstart`, `codex-mcp:///errors`
18
22
 
19
23
  ## Prerequisites
@@ -163,9 +167,13 @@ $env:CODEX_MCP_STDIO_MODE = "strict"; npx -y @leo000001/codex-mcp
163
167
 
164
168
  ## Tools
165
169
 
170
+ ### `codex_setup` — Check local readiness
171
+
172
+ Run a local readiness check before starting work. It verifies Codex executable resolution, login status, detected backend mode (`app-server` vs `exec`), and whether user/project `config.toml` files are visible from the target cwd.
173
+
166
174
  ### `codex` — Start a new session
167
175
 
168
- Start a Codex agent session asynchronously. Returns immediately with `sessionId`.
176
+ Start a Codex agent session asynchronously. Returns immediately with `sessionId` and `threadId`.
169
177
 
170
178
  | Parameter | Type | Required | Description |
171
179
  | ---------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
@@ -179,23 +187,24 @@ Start a Codex agent session asynchronously. Returns immediately with `sessionId`
179
187
  | `advanced` | object | No | Low-frequency options (see below) |
180
188
 
181
189
  <details>
182
- <summary><code>advanced</code> object parameters (9 low-frequency parameters)</summary>
183
-
184
- | Parameter | Type | Description |
185
- | -------------------------------- | -------- | ----------------------------------------------------------------------------------------------- |
186
- | `advanced.baseInstructions` | string | Replace default instructions (thread-level) |
187
- | `advanced.developerInstructions` | string | Developer instructions (thread-level) |
188
- | `advanced.personality` | string | Personality: `none`, `friendly`, `pragmatic` (default: from `~/.codex/config.toml`) |
189
- | `advanced.summary` | string | Reasoning summary: `auto`, `concise`, `detailed`, `none` (default: from `~/.codex/config.toml`) |
190
- | `advanced.config` | object | Override `config.toml` values (passed as `codex app-server -c key=value`) |
191
- | `advanced.ephemeral` | boolean | Don't persist thread. Default: `false` |
192
- | `advanced.outputSchema` | object | JSON Schema for structured output |
193
- | `advanced.images` | string[] | Local image paths (adds `localImage` inputs) |
194
- | `advanced.approvalTimeoutMs` | number | Auto-decline timeout (ms) for pending approvals. Default: `60000` |
190
+ <summary><code>advanced</code> object parameters (10 low-frequency parameters)</summary>
191
+
192
+ | Parameter | Type | Description |
193
+ | -------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
194
+ | `advanced.baseInstructions` | string | Replace default instructions (thread-level) |
195
+ | `advanced.developerInstructions` | string | Developer instructions (thread-level) |
196
+ | `advanced.personality` | string | Personality: `none`, `friendly`, `pragmatic` (default: from `~/.codex/config.toml`) |
197
+ | `advanced.summary` | string | Reasoning summary: `auto`, `concise`, `detailed`, `none` (default: from `~/.codex/config.toml`) |
198
+ | `advanced.config` | object | Override `config.toml` values (passed as `codex app-server -c key=value`) |
199
+ | `advanced.ephemeral` | boolean | Don't persist thread. Default: `false` |
200
+ | `advanced.outputSchema` | object | JSON Schema for structured output |
201
+ | `advanced.images` | string[] | Local image paths (adds `localImage` inputs) |
202
+ | `advanced.approvalTimeoutMs` | number | Auto-decline timeout (ms) for pending approvals. Default: `60000` |
203
+ | `advanced.waitForResult` | number | Wait up to this many ms for the session to complete and return the result directly. Max `300000` (5 min). Falls back to polling when the run does not finish in time or enters interactive approval/user-input flow. |
195
204
 
196
205
  </details>
197
206
 
198
- **Returns:** `{ sessionId, threadId, status: "running" | "idle", pollInterval }`
207
+ **Returns:** `{ sessionId, threadId, status, pollInterval?, execution?, interactionState?, recommendedNextAction? }`
199
208
 
200
209
  ```json
201
210
  {
@@ -223,20 +232,27 @@ If your MCP client supports resources, this server exposes a few **read-only** r
223
232
 
224
233
  Send a follow-up message to an existing session.
225
234
 
226
- | Parameter | Type | Required | Description |
227
- | ---------------- | ------ | -------- | ------------------------------------------------------------------------------- |
228
- | `sessionId` | string | Yes | Session ID from `codex` |
229
- | `prompt` | string | Yes | Follow-up message |
230
- | `model` | string | No | Override model for this turn |
231
- | `approvalPolicy` | string | No | Override approval policy |
232
- | `effort` | string | No | Override reasoning effort (`none`, `minimal`, `low`, `medium`, `high`, `xhigh`) |
233
- | `summary` | string | No | Override reasoning summary (`auto`, `concise`, `detailed`, `none`) |
234
- | `personality` | string | No | Override personality (`none`, `friendly`, `pragmatic`) |
235
- | `sandbox` | string | No | Override sandbox (`read-only`, `workspace-write`, `danger-full-access`) |
236
- | `cwd` | string | No | Override working directory |
237
- | `outputSchema` | object | No | JSON Schema for structured output |
238
-
239
- **Returns:** `{ sessionId, threadId, status: "running" | "idle", pollInterval }`
235
+ | Parameter | Type | Required | Description |
236
+ | ---------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
237
+ | `sessionId` | string | Yes | Session ID from `codex` |
238
+ | `prompt` | string | Yes | Follow-up message |
239
+ | `model` | string | No | Override model for this turn |
240
+ | `approvalPolicy` | string | No | Override approval policy |
241
+ | `effort` | string | No | Override reasoning effort (`none`, `minimal`, `low`, `medium`, `high`, `xhigh`) |
242
+ | `summary` | string | No | Override reasoning summary (`auto`, `concise`, `detailed`, `none`) |
243
+ | `personality` | string | No | Override personality (`none`, `friendly`, `pragmatic`) |
244
+ | `sandbox` | string | No | Override sandbox (`read-only`, `workspace-write`, `danger-full-access`) |
245
+ | `cwd` | string | No | Override working directory |
246
+ | `outputSchema` | object | No | JSON Schema for structured output |
247
+ | `waitForResult` | number | No | Wait up to this many ms for the reply turn to complete and return the result directly. Max `300000` (5 min). Falls back to polling when the turn does not finish in time or needs interactive approval. |
248
+
249
+ **Returns:** `{ sessionId, threadId, status, pollInterval?, result?, completedAt?, execution?, interactionState?, recommendedNextAction? }`
250
+
251
+ Additional orchestration hints may be present in `codex`, `codex_reply`, and `codex_check` responses:
252
+
253
+ - `execution`: whether foreground waiting was requested/effective, and whether it fell back to background polling
254
+ - `interactionState`: `working`, `waiting_input`, or `finished`
255
+ - `recommendedNextAction`: `poll`, `respond_permission`, `respond_user_input`, or `none`
240
256
 
241
257
  ```json
242
258
  {
@@ -276,21 +292,22 @@ List, inspect, cancel, interrupt, fork sessions, or clean background terminals.
276
292
 
277
293
  Query a running session for events, respond to approval requests, or answer user input.
278
294
 
279
- | Parameter | Type | Required | Description |
280
- | ---------------------- | -------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
281
- | `action` | string | Yes | `"poll"`, `"respond_permission"`, or `"respond_user_input"` |
282
- | `sessionId` | string | Yes | Target session ID |
283
- | `cursor` | number | No | Event cursor for incremental polling (`action="poll"`). For `respond_*`, codex-mcp applies monotonic cursor progression: `max(cursor, sessionLastCursor)`. |
284
- | `maxEvents` | number | No | Keep this small. `poll` default: `1` (minimum `1`; increase only for catch-up). `respond_*` default: `0` (recommended; compact ACK, no event replay). |
285
- | `responseMode` | string | No | Response shaping mode: `minimal` (default), `delta_compact`, `full` |
286
- | `pollOptions` | object | No | Optional controls: `includeEvents` (default `true`), `includeActions` (default `true`), `includeResult` (default `true`), `maxBytes` (default unlimited) |
287
- | `requestId` | string | For respond_permission/user_input | Request ID from `actions[]` |
288
- | `decision` | string | For respond_permission | For command approvals: `"accept"`, `"acceptForSession"`, `"acceptWithExecpolicyAmendment"`, `"decline"`, `"cancel"`; for file changes: `"accept"`, `"acceptForSession"`, `"decline"`, `"cancel"` |
289
- | `execpolicy_amendment` | string[] | For acceptWithExecpolicyAmendment | Exec policy amendment list (required when `decision="acceptWithExecpolicyAmendment"`) |
290
- | `denyMessage` | string | No | Internal note on deny (not sent to app-server) |
291
- | `answers` | object | For respond_user_input | For `respond_user_input`: `question-id -> { answers: string[] }` |
292
-
293
- **Returns (poll and respond\_\*):** `{ sessionId, status, pollInterval?, cursorResetTo?, events, nextCursor, actions?, result? }`
295
+ | Parameter | Type | Required | Description |
296
+ | -------------------------- | -------- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
297
+ | `action` | string | Yes | `"poll"`, `"respond_permission"`, or `"respond_user_input"` |
298
+ | `sessionId` | string | Yes | Target session ID |
299
+ | `cursor` | number | No | Event cursor for incremental polling (`action="poll"`). For `respond_*`, codex-mcp applies monotonic cursor progression: `max(cursor, sessionLastCursor)`. |
300
+ | `maxEvents` | number | No | Keep this small. `poll` default: `1` (minimum `1`; increase only for catch-up). `respond_*` default: `0` (recommended; compact ACK, no event replay). |
301
+ | `responseMode` | string | No | Response shaping mode: `minimal` (default), `delta_compact`, `full` |
302
+ | `pollOptions` | object | No | Optional controls: `includeEvents` (default `true`), `includeActions` (default `true`), `includeResult` (default `true`), `maxBytes` (default unlimited) |
303
+ | `requestId` | string | For respond_permission/user_input | Request ID from `actions[]` |
304
+ | `decision` | string | For respond_permission | For command approvals: `"accept"`, `"acceptForSession"`, `"acceptWithExecpolicyAmendment"`, `"applyNetworkPolicyAmendment"`, `"decline"`, `"cancel"`; for file changes: `"accept"`, `"acceptForSession"`, `"decline"`, `"cancel"` |
305
+ | `execpolicy_amendment` | string[] | For acceptWithExecpolicyAmendment | Exec policy amendment list (required when `decision="acceptWithExecpolicyAmendment"`) |
306
+ | `network_policy_amendment` | object | For applyNetworkPolicyAmendment | Network policy amendment object `{ action: "allow" | "deny", host: string }`(required when`decision="applyNetworkPolicyAmendment"`) |
307
+ | `denyMessage` | string | No | Internal note on deny (not sent to app-server) |
308
+ | `answers` | object | For respond_user_input | For `respond_user_input`: `question-id -> { answers: string[] }` |
309
+
310
+ **Returns (poll and respond\_\*):** `{ sessionId, status, pollInterval?, interactionState?, recommendedNextAction?, cursorResetTo?, events, nextCursor, actions?, result? }`
294
311
 
295
312
  ```json
296
313
  { "action": "poll", "sessionId": "sess_abc123", "cursor": 0 }
@@ -335,6 +352,7 @@ When the agent requests approval or user input, `poll` includes an `actions[]` l
335
352
 
336
353
  - `respond_permission`: `decision` is one of `accept`, `acceptForSession`, `decline`, `cancel`.
337
354
  - For command approvals, `acceptWithExecpolicyAmendment` is supported and requires `execpolicy_amendment`.
355
+ - For command approvals, `applyNetworkPolicyAmendment` is supported and requires `network_policy_amendment`.
338
356
  - `respond_user_input`: send `answers` keyed by the question `id`.
339
357
  - For command approvals, `actions[]` may include `commandActions` and `proposedExecpolicyAmendment` for richer review UI.
340
358
 
@@ -404,6 +422,17 @@ MCP Client ←stdio→ codex-mcp server ←stdio→ codex exec --json ←→ Cod
404
422
 
405
423
  Each session spawns an independent child process. In app-server mode, it uses the JSON-RPC protocol over stdio. In exec fallback mode, it uses `codex exec --json` JSONL output with `codex exec resume` for multi-turn context.
406
424
 
425
+ Session metadata, event logs, and results are persisted to disk (`~/.codex-mcp/state/` by default). On restart, the server recovers queryable sessions and reaps any orphaned child processes from the previous run.
426
+
427
+ ### Environment Variables
428
+
429
+ | Variable | Description | Default |
430
+ | -------------------------------- | ------------------------------------------------ | -------------------- |
431
+ | `CODEX_MCP_STATE_DIR` | Directory for persistent session state | `~/.codex-mcp/state` |
432
+ | `CODEX_MCP_PATH` | Explicit filesystem path to the codex binary | _(unset)_ |
433
+ | `CODEX_MCP_COMMAND` | Command name to resolve from PATH | _(unset)_ |
434
+ | `CODEX_MCP_DISABLE_NOISE_FILTER` | Set to `1` to disable PowerShell noise filtering | `0` |
435
+
407
436
  ## Development
408
437
 
409
438
  ```bash