mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
be1d3cff9300c7d72d4adab2b31c19e8a8bb27ca
75 Commits
-
Use MCP server instructions in deferred namespace descriptions (#21053)
## Why MCP servers can provide `instructions` that explain what their tools are for. Directly exposed MCP namespaces already use those instructions when a connector description is not available, but deferred `tool_search` results did not preserve that fallback. The direct path falls back from connector metadata to server instructions, while the deferred path only carried `connector_description` and otherwise fell back to generic namespace text. That meant a plain MCP server could provide useful model-facing guidance and still appear as `Tools in the X namespace.` whenever it was discovered lazily through `tool_search`. ## What changed - Store one model-facing `namespace_description` on `ToolInfo`, using connector descriptions for connector-backed tools and server instructions for plain MCP servers. - Thread that namespace description through the `tool_search` source list, search indexing, and returned namespace metadata. - Add an end-to-end regression test for deferred non-app MCP search results exposing server instructions as the namespace description. ## Verification - `cargo test -p codex-tools search_tool_description_lists_each_mcp_source_once --lib` - `cargo test -p codex-core --test all tool_search_uses_non_app_mcp_server_instructions_as_namespace_description`
sayan-oai ·
2026-05-04 19:36:07 +00:00 -
expand the set of core shell env vars for Windows. (#20089)
https://github.com/openai/codex/issues/13917 and https://github.com/openai/codex/issues/18248 correctly identify that ``` [shell_environment_policy] inherit = "core" ``` is not functional on Windows because it carries an insufficient set of env vars. This PR expands that to match the more functional set from the MCP client
iceweasel-oai ·
2026-04-29 19:23:46 +00:00 -
Terminate stdio MCP servers on shutdown to avoid process leaks (#19753)
## Why Several bug reports describe thread shutdown (including subagent threads) leaving stdio MCP server processes behind. These reports all point at the same lifecycle gap: Codex launches stdio MCP servers, but the session-level shutdown path does not explicitly close MCP clients or terminate the server process tree. Fixes #12491 Fixes #12976 Fixes #18881 Fixes #19469 ## History This is best understood as a regression/coverage gap in MCP session lifecycle management, not as stdio MCP cleanup being absent all along. #10710 added process-group cleanup for stdio MCP servers, but that cleanup only runs when the `RmcpClient`/transport is dropped. The older reports (#12491 and #12976) came after that cleanup existed, which suggests the remaining problem was that some higher-level shutdown paths kept the MCP manager alive or replaced it without explicitly draining clients. The newer reports (#18881 and #19469) exposed the same family around manager replacement and shutdown. ## What changed - Added an explicit stdio MCP process handle in `codex-rmcp-client` so local MCP servers terminate their process group and executor-backed MCP servers call the executor process terminator. - Added `RmcpClient::shutdown()` and manager-level MCP shutdown draining so session shutdown, channel-close fallback, MCP refresh, and connector probing stop owned MCP clients. - Added regression coverage that starts a stdio MCP server, begins an in-flight blocking tool call, shuts down the client, and asserts the server process exits. ## Verification - `cargo test -p codex-rmcp-client` - `cargo test -p codex-mcp` - `just fix -p codex-rmcp-client` - `just fix -p codex-mcp` - `just fix -p codex-core` - Manual before/after validation with a temporary repro script: - Pre-fix binary from `HEAD^` (`fed0a8f4fa`): reproduced the leak with surviving MCP server and child PIDs, `survivors=[77583, 77592]`, `leaked=true`. - Post-fix binary from this branch (`67e318148b`): verified both MCP processes were gone after interrupting `codex exec`, `survivors=[]`, `leaked=false`.
Eric Traut ·
2026-04-28 09:29:57 -07:00 -
[codex] Move config loading into codex-config (#19487)
## Why Config loading had become split across crates: `codex-config` owned the config types and merge logic, while `codex-core` still owned the loader that assembled the layer stack. This change consolidates that responsibility in `codex-config`, so the crate that defines config behavior also owns how configs are discovered and loaded. To make that move possible without reintroducing the old dependency cycle, the shell-environment policy types and helpers that `codex-exec-server` needs now live in `codex-protocol` instead of flowing through `codex-config`. This also makes the migrated loader tests more deterministic on machines that already have managed or system Codex config installed by letting tests override the system config and requirements paths instead of reading the host's `/etc/codex`. ## What Changed - moved the config loader implementation from `codex-core` into `codex-config::loader` and deleted the old `core::config_loader` module instead of leaving a compatibility shim - moved shell-environment policy types and helpers into `codex-protocol`, then updated `codex-exec-server` and other downstream crates to import them from their new home - updated downstream callers to use loader/config APIs from `codex-config` - added test-only loader overrides for system config and requirements paths so loader-focused tests do not depend on host-managed config state - cleaned up now-unused dependency entries and platform-specific cfgs that were surfaced by post-push CI ## Testing - `cargo test -p codex-config` - `cargo test -p codex-core config_loader_tests::` - `cargo test -p codex-protocol -p codex-exec-server -p codex-cloud-requirements -p codex-rmcp-client --lib` - `cargo test --lib -p codex-app-server-client -p codex-exec` - `cargo test --no-run --lib -p codex-app-server` - `cargo test -p codex-linux-sandbox --lib` - `cargo shear` - `just bazel-lock-check` ## Notes - I did not chase unrelated full-suite failures outside the migrated loader surface. - `cargo test -p codex-core --lib` still hits unrelated proxy-sensitive failures on this machine, and Windows CI still shows unrelated long-running/timeouting test noise outside the loader migration itself.
pakrym-oai ·
2026-04-26 15:10:53 -07:00 -
test: harden app-server integration tests (#19683)
## Why Windows Bazel runs in the permissions stack exposed that app-server integration tests were launching normal plugin startup warmups in every subprocess. Those warmups can call `https://chatgpt.com/backend-api/plugins/featured` when a test is not specifically exercising plugin startup, which adds slow background work, noisy stderr, and dependence on external network state. The relevant startup/featured-plugin behavior was introduced across #15042 and #15264. A few app-server tests also had long optional waits or unbounded cleanup paths, making failures expensive to diagnose and contributing to slow Windows shards. One external-agent config test from #18246 used a GitHub-style marketplace source, which was enough to exercise the pending remote-import path but also meant the background completion task could attempt a real clone. ## What Changed - Adds explicit `AppServerRuntimeOptions` / `PluginStartupTasks` plumbing and a hidden debug-only `--disable-plugin-startup-tasks-for-tests` app-server flag, so integration tests can suppress startup plugin warmups without adding a production env-var gate. - Has the app-server test harness pass that hidden flag by default, while opting plugin-startup coverage back in for tests that intentionally exercise startup sync and featured-plugin warmup behavior. - Lowers normal app-server subprocess logging from `info`/`debug` to `warn` to avoid multi-megabyte stderr output in Bazel logs. - Prevents the external-agent config test from attempting a real marketplace clone by using an invalid non-local source while still exercising the pending-import completion path. - Bounds optional filesystem/realtime waits and fake WebSocket test-server shutdown so failures produce targeted timeouts instead of hanging a shard. - Fixes the Unix script-resolution test in `rmcp-client` to exercise PATH resolution directly and include the actual spawn error in failures. ## Verification - `cargo check -p codex-app-server` - `cargo clippy -p codex-app-server --tests -- -D warnings` - `cargo test -p codex-rmcp-client program_resolver::tests::test_unix_executes_script_without_extension` - `cargo test -p codex-app-server --test all external_agent_config_import_sends_completion_notification_after_pending_plugins_finish -- --nocapture` - `cargo test -p codex-app-server --test all plugin_list_uses_warmed_featured_plugin_ids_cache_on_first_request -- --nocapture` - Windows Local Bazel passed with this test-hardening bundle before it was extracted from #19606. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19683). * #19395 * #19394 * #19393 * #19392 * #19606 * __->__ #19683
Michael Bolin ·
2026-04-26 12:43:16 -07:00 -
Ahmed Ibrahim ·
2026-04-24 15:03:55 -07:00 -
refactor: route Codex auth through AuthProvider (#18811)
## Summary This PR moves Codex backend request authentication from direct bearer-token handling to `AuthProvider`. The new `codex-auth-provider` crate defines the shared request-auth trait. `CodexAuth::provider()` returns a provider that can apply all headers needed for the selected auth mode. This lets ChatGPT token auth and AgentIdentity auth share the same callsite path: - ChatGPT token auth applies bearer auth plus account/FedRAMP headers where needed. - AgentIdentity auth applies AgentAssertion plus account/FedRAMP headers where needed. Reference old stack: https://github.com/openai/codex/pull/17387/changes ## Callsite Migration | Area | Change | | --- | --- | | backend-client | accepts an `AuthProvider` instead of a raw token/header | | chatgpt client/connectors | applies auth through `CodexAuth::provider()` | | cloud tasks | keeps Codex-backend gating, applies auth through provider | | cloud requirements | uses Codex-backend auth checks and provider headers | | app-server remote control | applies provider headers for backend calls | | MCP Apps/connectors | gates on `uses_codex_backend()` and keys caches from generic account getters | | model refresh | treats AgentIdentity as Codex-backend auth | | OpenAI file upload path | rejects non-Codex-backend auth before applying headers | | core client setup | keeps model-provider auth flow and allows AgentIdentity through provider-backed OpenAI auth | ## Stack 1. https://github.com/openai/codex/pull/18757: full revert 2. https://github.com/openai/codex/pull/18871: isolated Agent Identity crate 3. https://github.com/openai/codex/pull/18785: explicit AgentIdentity auth mode and startup task allocation 4. This PR: migrate Codex backend auth callsites through AuthProvider 5. https://github.com/openai/codex/pull/18904: accept AgentIdentity JWTs and load `CODEX_AGENT_IDENTITY` ## Testing Tests: targeted Rust checks, cargo-shear, Bazel lock check, and CI.
efrazer-oai ·
2026-04-23 17:14:02 -07:00 -
Matthew Zeng ·
2026-04-22 17:52:17 -07:00 -
[3/4] Add executor-backed RMCP HTTP client (#18583)
### Why The RMCP layer needs a Streamable HTTP client that can talk either directly over `reqwest` or through the executor HTTP runner without duplicating MCP session logic higher in the stack. This PR adds that client-side transport boundary so remote Streamable HTTP MCP can reuse the same RMCP flow as the local path. ### What - Add a shared `rmcp-client/src/streamable_http/` module with: - `transport_client.rs` for the local-or-remote transport enum - `local_client.rs` for the direct `reqwest` implementation - `remote_client.rs` for the executor-backed implementation - `common.rs` for the small shared Streamable HTTP helpers - Teach `RmcpClient` to build Streamable HTTP transports in either local or remote mode while keeping the existing OAuth ownership in RMCP. - Translate remote POST, GET, and DELETE session operations into executor `http/request` calls. - Preserve RMCP session expiry handling and reconnect behavior for the remote transport. - Add remote transport coverage in `rmcp-client/tests/streamable_http_remote.rs` and keep the shared test support in `rmcp-client/tests/streamable_http_test_support.rs`. ### Verification - `cargo check -p codex-rmcp-client` - online CI ### Stack 1. #18581 protocol 2. #18582 runner 3. #18583 RMCP client 4. #18584 manager wiring and local/remote coverage --------- Co-authored-by: Codex <noreply@openai.com>
Ahmed Ibrahim ·
2026-04-22 17:38:04 -07:00 -
Add turn-scoped environment selections (#18416)
## Summary - add experimental turn/start.environments params for per-turn environment id + cwd selections - pass selections through core protocol ops and resolve them with EnvironmentManager before TurnContext creation - treat omitted selections as default behavior, empty selections as no environment, and non-empty selections as first environment/cwd as the turn primary ## Testing - ran `just fmt` - ran `just write-app-server-schema` - not run: unit tests for this stacked PR --------- Co-authored-by: Codex <noreply@openai.com>
starr-openai ·
2026-04-21 17:48:33 -07:00 -
chore: document intentional await-holding cases (#18423)
## Why This PR prepares the stack to enable Clippy await-holding lints that were left disabled in #18178. The mechanical lock-scope cleanup is handled separately; this PR is the documentation/configuration layer for the remaining await-across-guard sites. Without explicit annotations, reviewers and future maintainers cannot tell whether an await-holding warning is a real concurrency smell or an intentional serialization boundary. ## What changed - Configures `clippy.toml` so `await_holding_invalid_type` also covers `tokio::sync::{MutexGuard,RwLockReadGuard,RwLockWriteGuard}`. - Adds targeted `#[expect(clippy::await_holding_invalid_type, reason = ...)]` annotations for intentional async guard lifetimes. - Documents the main categories of intentional cases: active-turn state transitions that must remain atomic, session-owned MCP manager accesses, remote-control websocket serialization, JS REPL kernel/process serialization, OAuth persistence, external bearer token refresh serialization, and tests that intentionally serialize shared global or session-owned state. - For external bearer token refresh, documents the existing serialization boundary: holding `cached_token` across the provider command prevents concurrent cache misses from starting duplicate refresh commands, and the current behavior is small enough that an explicit expectation is easier to maintain than adding another synchronization primitive. ## Verification - `cargo clippy -p codex-login --all-targets` - `cargo clippy -p codex-connectors --all-targets` - `cargo clippy -p codex-core --all-targets` - The follow-up PR #18698 enables `await_holding_invalid_type` and `await_holding_lock` as workspace `deny` lints, so any undocumented remaining offender will fail Clippy. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/18423). * #18698 * __->__ #18423
Michael Bolin ·
2026-04-20 22:41:54 -07:00 -
refactor: use semaphores for async serialization gates (#18403)
This is the second cleanup in the await-holding lint stack. The higher-level goal, following https://github.com/openai/codex/pull/18178 and https://github.com/openai/codex/pull/18398, is to enable Clippy coverage for guards held across `.await` points without carrying broad suppressions. The stack is working toward enabling Clippy's [`await_holding_lock`](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock) lint and the configurable [`await_holding_invalid_type`](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type) lint for Tokio guard types. Several existing fields used `tokio::sync::Mutex<()>` only as one-at-a-time async gates. Those guards intentionally lived across `.await` while an operation was serialized. A mutex over `()` suggests protected data and trips the await-holding lint shape; a single-permit `tokio::sync::Semaphore` expresses the intended serialization directly. ## What changed - Replace `Mutex<()>` serialization gates with `Semaphore::new(1)` for agent identity ensure, exec policy updates, guardian review session reuse, plugin remote sync, managed network proxy refresh, auth token refresh, and RMCP session recovery. - Update call sites from `lock().await` / `try_lock()` to `acquire().await` / `try_acquire()`. - Map closed-semaphore errors into the existing local error types, even though these semaphores are owned for the lifetime of their managers. - Update session test builders for the new `managed_network_proxy_refresh_lock` type. ## Verification - The split stack was verified at the final lint-enabling head with `just clippy`. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/18403). * #18698 * #18423 * #18418 * __->__ #18403
Michael Bolin ·
2026-04-20 17:21:29 +00:00 -
[5/6] Wire executor-backed MCP stdio (#18212)
## Summary - Add the executor-backed RMCP stdio transport. - Wire MCP stdio placement through the executor environment config. - Cover local and executor-backed stdio paths with the existing MCP test helpers. ## Stack ```text o #18027 [6/6] Fail exec client operations after disconnect │ @ #18212 [5/6] Wire executor-backed MCP stdio │ o #18087 [4/6] Abstract MCP stdio server launching │ o #18020 [3/6] Add pushed exec process events │ o #18086 [2/6] Support piped stdin in exec process API │ o #18085 [1/6] Add MCP server environment config │ o main ``` --------- Co-authored-by: Codex <noreply@openai.com>
Ahmed Ibrahim ·
2026-04-18 21:47:43 -07:00 -
refactor: narrow async lock guard lifetimes (#18211)
Follow-up to https://github.com/openai/codex/pull/18178, where we called out enabling the await-holding lint as a follow-up. The long-term goal is to enable Clippy coverage for async guards held across awaits. This PR is intentionally only the first, low-risk cleanup pass: it narrows obvious lock guard lifetimes and leaves `codex-rs/Cargo.toml` unchanged so the lint is not enabled until the remaining cases are fixed or explicitly justified. It intentionally leaves the active-turn/turn-state locking pattern alone because those checks and mutations need to stay atomic. ## Common fixes used here These are the main patterns reviewers should expect in this PR, and they are also the patterns to reach for when fixing future `await_holding_*` findings: - **Scope the guard to the synchronous work.** If the code only needs data from a locked value, move the lock into a small block, clone or compute the needed values, and do the later `.await` after the block. - **Use direct one-line mutations when there is no later await.** Cases like `map.lock().await.remove(&id)` are acceptable when the guard is only needed for that single mutation and the statement ends before any async work. - **Drain or clone work out of the lock before notifying or awaiting.** For example, the JS REPL drains pending exec senders into a local vector and the websocket writer clones buffered envelopes before it serializes or sends them. - **Use a `Semaphore` only when serialization is intentional across async work.** The test serialization guards intentionally span awaited setup or execution, so using a semaphore communicates "one at a time" without holding a mutex guard. - **Remove the mutex when there is only one owner.** The PTY stdin writer task owns `stdin` directly; the old `Arc<Mutex<_>>` did not protect shared access because nothing else had access to the writer. - **Do not split locks that protect an atomic invariant.** This PR deliberately leaves active-turn/turn-state paths alone because those checks and mutations need to stay atomic. Those cases should be fixed separately with a design change or documented with `#[expect]`. ## What changed - Narrow scoped async mutex guards in app-server, JS REPL, network approval, remote-control websocket, and the RMCP test server. - Replace test-only async mutex serialization guards with semaphores where the guard intentionally lives across async work. - Let the PTY pipe writer task own stdin directly instead of wrapping it in an async mutex. ## Verification - `just fix -p codex-core -p codex-app-server -p codex-rmcp-client -p codex-shell-escalation -p codex-utils-pty -p codex-utils-readiness` - `just clippy -p codex-core` - `cargo test -p codex-core -p codex-app-server -p codex-rmcp-client -p codex-shell-escalation -p codex-utils-pty -p codex-utils-readiness` was run; the app-server suite passed, and `codex-core` failed in the local sandbox on six otel approval tests plus `suite::user_shell_cmd::user_shell_command_does_not_set_network_sandbox_env_var`, which appear to depend on local command approval/default rules and `CODEX_SANDBOX_NETWORK_DISABLED=1` in this environment.
Michael Bolin ·
2026-04-17 14:06:50 -07:00 -
[4/6] Abstract MCP stdio server launching (#18087)
## Summary - Move local MCP stdio process startup behind a launcher trait. - Preserve existing local stdio behavior while making transport creation explicit. ## Stack ```text o #18027 [6/6] Fail exec client operations after disconnect │ o #18212 [5/6] Wire executor-backed MCP stdio │ @ #18087 [4/6] Abstract MCP stdio server launching │ o #18020 [3/6] Add pushed exec process events │ o #18086 [2/6] Support piped stdin in exec process API │ o #18085 [1/6] Add MCP server environment config │ o main ``` --------- Co-authored-by: Codex <noreply@openai.com>
Ahmed Ibrahim ·
2026-04-17 12:34:48 -07:00 -
Support original-detail metadata on MCP image outputs (#17714)
## Summary - honor `_meta["codex/imageDetail"] == "original"` on MCP image content and map it to `detail: "original"` where supported - strip that detail back out when the active model does not support original-detail image inputs - update code-mode `image(...)` to accept individual MCP image blocks - teach `js_repl` / `codex.emitImage(...)` to preserve the same hint from raw MCP image outputs - document the new `_meta` contract and add generic RMCP-backed coverage across protocol, core, code-mode, and js_repl paths
Curtis 'Fjord' Hawthorne ·
2026-04-15 14:43:33 -07:00 -
Send sandbox state through MCP tool metadata (#17763)
## Changes Allows MCPs to opt in to receiving sandbox config info through `_meta` on model-initiated tool calls. This lets MCPs adhere to the thread's sandbox if they choose to. ## Details - Adds the `codex/sandbox-state-meta` experimental MCP capability. - Tracks whether each MCP server advertises that capability. - When a server opts in, `codex-core` injects the current `SandboxState` into model-initiated MCP tool-call request `_meta`. ## Verification - added an integration test for the capability
aaronl-openai ·
2026-04-15 00:49:15 -07:00 -
Add
supports_parallel_tool_callsflag to included mcps (#17667)## Why For more advanced MCP usage, we want the model to be able to emit parallel MCP tool calls and have Codex execute eligible ones concurrently, instead of forcing all MCP calls through the serial block. The main design choice was where to thread the config. I made this server-level because parallel safety depends on the MCP server implementation. Codex reads the flag from `mcp_servers`, threads the opted-in server names into `ToolRouter`, and checks the parsed `ToolPayload::Mcp { server, .. }` at execution time. That avoids relying on model-visible tool names, which can be incomplete in deferred/search-tool paths or ambiguous for similarly named servers/tools. ## What was added Added `supports_parallel_tool_calls` for MCP servers. Before: ```toml [mcp_servers.docs] command = "docs-server" ``` After: ```toml [mcp_servers.docs] command = "docs-server" supports_parallel_tool_calls = true ``` MCP calls remain serial by default. Only tools from opted-in servers are eligible to run in parallel. Docs also now warn to enable this only when the server’s tools are safe to run concurrently, especially around shared state or read/write races. ## Testing Tested with a local stdio MCP server exposing real delay tools. The model/Responses side was mocked only to deterministically emit two MCP calls in the same turn. Each test called `query_with_delay` and `query_with_delay_2` with `{ "seconds": 25 }`. | Build/config | Observed | Wall time | | --- | --- | --- | | main with flag enabled | serial | `58.79s` | | PR with flag enabled | parallel | `31.73s` | | PR without flag | serial | `56.70s` | PR with flag enabled showed both tools start before either completed; main and PR-without-flag completed the first delay before starting the second. Also added an integration test. Additional checks: - `cargo test -p codex-tools` passed - `cargo test -p codex-core mcp_parallel_support_uses_exact_payload_server` passed - `git diff --check` passedjosiah-openai ·
2026-04-13 15:16:34 -07:00 -
Use AbsolutePathBuf in skill loading and codex_home (#17407)
Helps with FS migration later
pakrym-oai ·
2026-04-13 10:26:51 -07:00 -
fix(mcp) pause timer for elicitations (#17566)
## Summary Stop counting elicitation time towards mcp tool call time. There are some tradeoffs here, but in general I don't think time spent waiting for elicitations should count towards tool call time, or at least not directly towards timeouts. Elicitations are not exactly like exec_command escalation requests, but I would argue it's ~roughly equivalent. ## Testing - [x] Added unit tests - [x] Tested locally
Dylan Hurd ·
2026-04-12 16:06:17 -07:00 -
Add output_schema to code mode render (#17210)
This updates code-mode tool rendering so MCP tools can surface structured output types from their `outputSchema`. What changed: - Detect MCP tool-call result wrappers from the output schema shape instead of relying on tool-name parsing or provenance flags. - Render shared TypeScript aliases once for MCP tool results (`CallToolResult`, `ContentBlock`, etc.) so multiple MCP tool declarations stay compact. - Type `structuredContent` from the tool definition's `outputSchema` instead of rendering it as `unknown`. - Update the shared MCP aliases to match the MCP draft `CallToolResult` schema more closely. Example: - Before: `declare const tools: { mcp__rmcp__echo(args: { env_var?: string; message: string; }): Promise<{ _meta?: unknown; content: Array<unknown>; isError?: boolean; structuredContent?: unknown; }>; };` - After: `declare const tools: { mcp__rmcp__echo(args: { env_var?: string; message: string; }): Promise<CallToolResult<{ echo: string; env: string | null; }>>; };`Vivian Fang ·
2026-04-10 11:41:44 +00:00 -
[mcp] Support server-driven elicitations (#17043)
- [x] Enables MCP elicitation for custom servers, not just Codex Apps - [x] Adds an RMCP service wrapper to preserve elicitation _meta - [x] Round-trips response _meta for persist/approval choices - [x] Updates TUI empty-schema elicitations into message-only approval prompts
Matthew Zeng ·
2026-04-08 10:18:58 -07:00 -
Refactor config types into a separate crate (#16962)
Move config types into a separate crate because their macros expand into a lot of new code.
pakrym-oai ·
2026-04-07 00:32:41 +00:00 -
chore: clean up argument-comment lint and roll out all-target CI on macOS (#16054)
## Why `argument-comment-lint` was green in CI even though the repo still had many uncommented literal arguments. The main gap was target coverage: the repo wrapper did not force Cargo to inspect test-only call sites, so examples like the `latest_session_lookup_params(true, ...)` tests in `codex-rs/tui_app_server/src/lib.rs` never entered the blocking CI path. This change cleans up the existing backlog, makes the default repo lint path cover all Cargo targets, and starts rolling that stricter CI enforcement out on the platform where it is currently validated. ## What changed - mechanically fixed existing `argument-comment-lint` violations across the `codex-rs` workspace, including tests, examples, and benches - updated `tools/argument-comment-lint/run-prebuilt-linter.sh` and `tools/argument-comment-lint/run.sh` so non-`--fix` runs default to `--all-targets` unless the caller explicitly narrows the target set - fixed both wrappers so forwarded cargo arguments after `--` are preserved with a single separator - documented the new default behavior in `tools/argument-comment-lint/README.md` - updated `rust-ci` so the macOS lint lane keeps the plain wrapper invocation and therefore enforces `--all-targets`, while Linux and Windows temporarily pass `-- --lib --bins` That temporary CI split keeps the stricter all-targets check where it is already cleaned up, while leaving room to finish the remaining Linux- and Windows-specific target-gated cleanup before enabling `--all-targets` on those runners. The Linux and Windows failures on the intermediate revision were caused by the wrapper forwarding bug, not by additional lint findings in those lanes. ## Validation - `bash -n tools/argument-comment-lint/run.sh` - `bash -n tools/argument-comment-lint/run-prebuilt-linter.sh` - shell-level wrapper forwarding check for `-- --lib --bins` - shell-level wrapper forwarding check for `-- --tests` - `just argument-comment-lint` - `cargo test` in `tools/argument-comment-lint` - `cargo test -p codex-terminal-detection` ## Follow-up - Clean up remaining Linux-only target-gated callsites, then switch the Linux lint lane back to the plain wrapper invocation. - Clean up remaining Windows-only target-gated callsites, then switch the Windows lint lane back to the plain wrapper invocation.
Michael Bolin ·
2026-03-27 19:00:44 -07:00 -
fix(core): default approval behavior for mcp missing annotations (#15519)
- Changed `requires_mcp_tool_approval` to apply MCP spec defaults when annotations are missing. - Unannotated tools now default to: - `readOnlyHint = false` - `destructiveHint = true` - `openWorldHint = true` - This means unannotated MCP tools now go through approval/ARC monitoring instead of silently bypassing it. - Explicitly read-only tools still skip approval unless they are also explicitly marked destructive. **Previous behavior** Failed open for missing annotations, which was unsafe for custom MCP tools that omitted or forgot annotations. --------- Co-authored-by: colby-oai <228809017+colby-oai@users.noreply.github.com>
Fouad Matin ·
2026-03-25 07:55:41 -07:00 -
fix: keep rmcp-client env vars as OsString (#15363)
## Why This is a follow-up to #15360. That change fixed the `arg0` helper setup, but `rmcp-client` still coerced stdio transport environment values into UTF-8 `String`s before program resolution and process spawn. If `PATH` or another inherited environment value contains non-UTF-8 bytes, that loses fidelity before it reaches `which` and `Command`. ## What changed - change `create_env_for_mcp_server()` to return `HashMap<OsString, OsString>` and read inherited values with `std::env::var_os()` - change `TransportRecipe::Stdio.env`, `RmcpClient::new_stdio_client()`, and `program_resolver::resolve()` to keep stdio transport env values in `OsString` form within `rmcp-client` - keep the `codex-core` config boundary stringly, but convert configured stdio env values to `OsString` once when constructing the transport - update the rmcp-client stdio test fixtures and callers to use `OsString` env maps - add a Unix regression test that verifies `create_env_for_mcp_server()` preserves a non-UTF-8 `PATH` ## How to verify - `cargo test -p codex-rmcp-client` - `cargo test -p codex-core mcp_connection_manager` - `just argument-comment-lint` Targeted coverage in this change includes `utils::tests::create_env_preserves_path_when_it_is_not_utf8`, while the updated stdio transport path is exercised by the existing rmcp-client tests that construct `RmcpClient::new_stdio_client()`.
Michael Bolin ·
2026-03-24 23:32:31 +00:00 -
Suppress plugin-install MCP OAuth URL console spam (#15666)
Switch plugin-install background MCP OAuth to a silent login path so the raw authorization URL is no longer printed in normal success cases. OAuth behavior is otherwise unchanged, with fallback URL output via stderr still shown only if browser launch fails. Before: https://github.com/user-attachments/assets/4bf387af-afa8-4b83-bcd6-4ca6b55da8db
canvrno-oai ·
2026-03-24 14:46:21 -07:00 -
Plumb MCP turn metadata through _meta (#15190)
## Summary Some background. We're looking to instrument GA turns end to end. Right now a big gap is grouping mcp tool calls with their codex sessions. We send session id and turn id headers to the responses call but not the mcp/wham calls. Ideally we could pass the args as headers like with responses, but given the setup of the rmcp client, we can't send as headers without either changing the rmcp package upstream to allow per request headers or introducing a mutex which break concurrency. An earlier attempt made the assumption that we had 1 client per thread, which allowed us to set headers at the start of a turn. @pakrym mentioned that this assumption might break in the near future. So the solution now is to package the turn metadata/session id into the _meta field in the post body and pull out in codex-backend. - send turn metadata to MCP servers via `tools/call` `_meta` instead of assuming per-thread request headers on shared clients - preserve the existing `_codex_apps` metadata while adding `x-codex-turn-metadata` for all MCP tool calls - extend tests to cover both custom MCP servers and the codex apps search flow --------- Co-authored-by: Codex <noreply@openai.com>
nicholasclark-openai ·
2026-03-19 22:05:13 +00:00 -
Revert "Forward session and turn headers to MCP HTTP requests" (#15185)
Reverts openai/codex#15011 Codex merged by mistake before feedback applied
nicholasclark-openai ·
2026-03-19 10:38:53 -07:00 -
Forward session and turn headers to MCP HTTP requests (#15011)
## Summary - forward request-scoped task headers through MCP tool metadata lookups and tool calls - apply those headers to streamable HTTP initialize, tools/list, and tools/call requests - update affected rmcp/core tests for the new request_headers plumbing ## Testing - cargo test -p codex-rmcp-client - cargo test -p codex-core (fails on pre-existing unrelated error in core/src/auth_env_telemetry.rs: missing websocket_connect_timeout_ms in ModelProviderInfo initializer) - just fix -p codex-rmcp-client - just fix -p codex-core (hits the same unrelated auth_env_telemetry.rs error) - just fmt --------- Co-authored-by: Codex <noreply@openai.com>
nicholasclark-openai ·
2026-03-18 21:29:37 -07:00 -
Apply argument comment lint across codex-rs (#14652)
## Why Once the repo-local lint exists, `codex-rs` needs to follow the checked-in convention and CI needs to keep it from drifting. This commit applies the fallback `/*param*/` style consistently across existing positional literal call sites without changing those APIs. The longer-term preference is still to avoid APIs that require comments by choosing clearer parameter types and call shapes. This PR is intentionally the mechanical follow-through for the places where the existing signatures stay in place. After rebasing onto newer `main`, the rollout also had to cover newly introduced `tui_app_server` call sites. That made it clear the first cut of the CI job was too expensive for the common path: it was spending almost as much time installing `cargo-dylint` and re-testing the lint crate as a representative test job spends running product tests. The CI update keeps the full workspace enforcement but trims that extra overhead from ordinary `codex-rs` PRs. ## What changed - keep a dedicated `argument_comment_lint` job in `rust-ci` - mechanically annotate remaining opaque positional literals across `codex-rs` with exact `/*param*/` comments, including the rebased `tui_app_server` call sites that now fall under the lint - keep the checked-in style aligned with the lint policy by using `/*param*/` and leaving string and char literals uncommented - cache `cargo-dylint`, `dylint-link`, and the relevant Cargo registry/git metadata in the lint job - split changed-path detection so the lint crate's own `cargo test` step runs only when `tools/argument-comment-lint/*` or `rust-ci.yml` changes - continue to run the repo wrapper over the `codex-rs` workspace, so product-code enforcement is unchanged Most of the code changes in this commit are intentionally mechanical comment rewrites or insertions driven by the lint itself. ## Verification - `./tools/argument-comment-lint/run.sh --workspace` - `cargo test -p codex-tui-app-server -p codex-tui` - parsed `.github/workflows/rust-ci.yml` locally with PyYAML --- * -> #14652 * #14651
Michael Bolin ·
2026-03-16 16:48:15 -07:00 -
[apps] Add tool call meta. (#14647)
- [x] Add resource_uri and other things to _meta to shortcut resource lookup and speed things up.
Matthew Zeng ·
2026-03-14 22:24:13 -07:00 -
client: extend custom CA handling across HTTPS and websocket clients (#14239)
## Stacked PRs This work is now effectively split across two steps: - #14178: add custom CA support for browser and device-code login flows, docs, and hermetic subprocess tests - #14239: extend that shared custom CA handling across Codex HTTPS clients and secure websocket TLS Note: #14240 was merged into this branch while it was stacked on top of this PR. This PR now subsumes that websocket follow-up and should be treated as the combined change. Builds on top of #14178. ## Problem Custom CA support landed first in the login path, but the real requirement is broader. Codex constructs outbound TLS clients in multiple places, and both HTTPS and secure websocket paths can fail behind enterprise TLS interception if they do not honor `CODEX_CA_CERTIFICATE` or `SSL_CERT_FILE` consistently. This PR broadens the shared custom-CA logic beyond login and applies the same policy to websocket TLS, so the enterprise-proxy story is no longer split between “HTTPS works” and “websockets still fail”. ## What This Delivers Custom CA support is no longer limited to login. Codex outbound HTTPS clients and secure websocket connections can now honor the same `CODEX_CA_CERTIFICATE` / `SSL_CERT_FILE` configuration, so enterprise proxy/intercept setups work more consistently end-to-end. For users and operators, nothing new needs to be configured beyond the same CA env vars introduced in #14178. The change is that more of Codex now respects them, including websocket-backed flows that were previously still using default trust roots. I also manually validated the proxy path locally with mitmproxy using: `CODEX_CA_CERTIFICATE=~/.mitmproxy/mitmproxy-ca-cert.pem HTTPS_PROXY=http://127.0.0.1:8080 just codex` with mitmproxy installed via `brew install mitmproxy` and configured as the macOS system proxy. ## Mental model `codex-client` is now the owner of shared custom-CA policy for outbound TLS client construction. Reqwest callers start from the builder configuration they already need, then pass that builder through `build_reqwest_client_with_custom_ca(...)`. Websocket callers ask the same module for a rustls client config when a custom CA bundle is configured. The env precedence is the same everywhere: - `CODEX_CA_CERTIFICATE` wins - otherwise fall back to `SSL_CERT_FILE` - otherwise use system roots The helper is intentionally narrow. It loads every usable certificate from the configured PEM bundle into the appropriate root store and returns either a configured transport or a typed error that explains what went wrong. ## Non-goals This does not add handshake-level integration tests against a live TLS endpoint. It does not validate that the configured bundle forms a meaningful certificate chain. It also does not try to force every transport in the repo through one abstraction; it extends the shared CA policy across the reqwest and websocket paths that actually needed it. ## Tradeoffs The main tradeoff is centralizing CA behavior in `codex-client` while still leaving adoption up to call sites. That keeps the implementation additive and reviewable, but it means the rule "outbound Codex TLS that should honor enterprise roots must use the shared helper" is still partly enforced socially rather than by types. For websockets, the shared helper only builds an explicit rustls config when a custom CA bundle is configured. When no override env var is set, websocket callers still use their ordinary default connector path. ## Architecture `codex-client::custom_ca` now owns CA bundle selection, PEM normalization, mixed-section parsing, certificate extraction, typed CA-loading errors, and optional rustls client-config construction for websocket TLS. The affected consumers now call into that shared helper directly rather than carrying login-local CA behavior: - backend-client - cloud-tasks - RMCP client paths that use `reqwest` - TUI voice HTTP paths - `codex-core` default reqwest client construction - `codex-api` websocket clients for both responses and realtime websocket connections The subprocess CA probe, env-sensitive integration tests, and shared PEM fixtures also live in `codex-client`, which is now the actual owner of the behavior they exercise. ## Observability The shared CA path logs: - which environment variable selected the bundle - which path was loaded - how many certificates were accepted - when `TRUSTED CERTIFICATE` labels were normalized - when CRLs were ignored - where client construction failed Returned errors remain user-facing and include the relevant env var, path, and remediation hint. That same error model now applies whether the failure surfaced while building a reqwest client or websocket TLS configuration. ## Tests Pure unit tests in `codex-client` cover env precedence and PEM normalization behavior. Real client construction remains in subprocess tests so the suite can control process env and avoid the macOS seatbelt panic path that motivated the hermetic test split. The subprocess coverage verifies: - `CODEX_CA_CERTIFICATE` precedence over `SSL_CERT_FILE` - fallback to `SSL_CERT_FILE` - single-cert and multi-cert bundles - malformed and empty-file errors - OpenSSL `TRUSTED CERTIFICATE` handling - CRL tolerance for well-formed CRL sections The websocket side is covered by the existing `codex-api` / `codex-core` websocket test suites plus the manual mitmproxy validation above. --------- Co-authored-by: Ivan Zakharchanka <3axap4eHko@gmail.com> Co-authored-by: Codex <noreply@openai.com>
Josh McKinney ·
2026-03-13 00:59:26 +00:00 -
Fix MCP tool calling (#14491)
Properly escape mcp tool names and make tools only available via imports.
pakrym-oai ·
2026-03-12 13:38:52 -07:00 -
use scopes_supported for OAuth when present on MCP servers (#14419)
Fixes [#8889](https://github.com/openai/codex/issues/8889). ## Summary - Discover and use advertised MCP OAuth `scopes_supported` when no explicit or configured scopes are present. - Apply the same scope precedence across `mcp add`, `mcp login`, skill dependency auto-login, and app-server MCP OAuth login. - Keep discovered scopes ephemeral and non-persistent. - Retry once without scopes for CLI and skill auto-login flows if the OAuth provider rejects discovered scopes. ## Motivation Some MCP servers advertise the scopes they expect clients to request during OAuth, but Codex was ignoring that metadata and typically starting OAuth with no scopes unless the user manually passed `--scopes` or configured `server.scopes`. That made compliant MCP servers harder to use out of the box and is the behavior described in [#8889](https://github.com/openai/codex/issues/8889). This change also brings our behavior in line with the MCP authorization spec's scope selection guidance: https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#scope-selection-strategy ## Behavior Scope selection now follows this order everywhere: 1. Explicit request scopes / CLI `--scopes` 2. Configured `server.scopes` 3. Discovered `scopes_supported` 4. Legacy empty-scope behavior Compatibility notes: - Existing working setups keep the same behavior because explicit and configured scopes still win. - Discovered scopes are never written back into config or token storage. - If discovery is missing, malformed, or empty, behavior falls back to the previous empty-scope path. - App-server login gets the same precedence rules, but does not add a transparent retry path in this change. ## Implementation - Extend streamable HTTP OAuth discovery to parse and normalize `scopes_supported`. - Add a shared MCP scope resolver in `core` so all login entrypoints use the same precedence rules. - Preserve provider callback errors from the OAuth flow so CLI/skill flows can safely distinguish provider rejections from other failures. - Reuse discovered scopes from the existing OAuth support check where possible instead of persisting new config.
jgershen-oai ·
2026-03-12 11:57:06 -07:00 -
feat: search_tool migrate to bring you own tool of Responses API (#14274)
## Why to support a new bring your own search tool in Responses API(https://developers.openai.com/api/docs/guides/tools-tool-search#client-executed-tool-search) we migrating our bm25 search tool to use official way to execute search on client and communicate additional tools to the model. ## What - replace the legacy `search_tool_bm25` flow with client-executed `tool_search` - add protocol, SSE, history, and normalization support for `tool_search_call` and `tool_search_output` - return namespaced Codex Apps search results and wire namespaced follow-up tool calls back into MCP dispatch
Anton Panasenko ·
2026-03-11 17:51:51 -07:00 -
Stabilize RMCP streamable HTTP readiness tests (#13880)
## What changed - The RMCP streamable HTTP tests now wait for metadata and tool readiness before issuing tool calls. - OAuth state is isolated per test home. - The helper server startup path now uses bounded bind retries so transient `AddrInUse` collisions do not fail the test immediately. ## Why this fixes the flake - The old tests could begin issuing tool requests before the helper server had finished advertising its metadata and tools, so the first request sometimes raced the server startup sequence. - On top of that, shared OAuth state and occasional bind collisions on CI runners introduced cross-test environmental noise unrelated to the functionality under test. - Readiness polling makes the client wait for an observable “server is ready” signal, while isolated state and bounded bind retries remove external contention that was causing intermittent failures. ## Scope - Test-only change.
Ahmed Ibrahim ·
2026-03-09 19:52:55 +00:00 -
[rmcp-client] Recover from streamable HTTP 404 sessions (#13514)
## Summary - add one-time session recovery in `RmcpClient` for streamable HTTP MCP `404` session expiry - rebuild the transport and retry the failed operation once after reinitializing the client state - extend the test server and integration coverage for `404`, `401`, single-retry, and non-session failure scenarios ## Testing - just fmt - cargo test -p codex-rmcp-client (the post-rebase run lost its final summary in the terminal; the suite had passed earlier before the rebase) - just fix -p codex-rmcp-client
Casey Chow ·
2026-03-06 10:02:42 -05:00 -
[elicitations] Switch to use MCP style elicitation payload for mcp tool approvals. (#13621)
- [x] Switch to use MCP style elicitation payload for mcp tool approvals. - [ ] TODO: Update the UI to support the full spec.
Matthew Zeng ·
2026-03-06 01:50:26 -08:00 -
Add oauth_resource handling for MCP login flows (#12866)
Addresses bug https://github.com/openai/codex/issues/12589 Builds on community PR #12763. This adds `oauth_resource` support for MCP `streamable_http` servers and wires it through the relevant config and login paths. It fixes the bug where the configured OAuth resource was not reliably included in the authorization request, causing MCP login to omit the expected `resource` parameter.
Eric Traut ·
2026-02-26 20:10:12 -08:00 -
Add configurable MCP OAuth callback URL for MCP login (#11382)
## Summary Implements a configurable MCP OAuth callback URL override for `codex mcp login` and app-server OAuth login flows, including support for non-local callback endpoints (for example, devbox ingress URLs). ## What changed - Added new config key: `mcp_oauth_callback_url` in `~/.codex/config.toml`. - OAuth authorization now uses `mcp_oauth_callback_url` as `redirect_uri` when set. - Callback handling validates the callback path against the configured redirect URI path. - Listener bind behavior is now host-aware: - local callback URL hosts (`localhost`, `127.0.0.1`, `::1`) bind to `127.0.0.1` - non-local callback URL hosts bind to `0.0.0.0` - `mcp_oauth_callback_port` remains supported and is used for the listener port. - Wired through: - CLI MCP login flow - App-server MCP OAuth login flow - Skill dependency OAuth login flow - Updated config schema and config tests. ## Why Some environments need OAuth callbacks to land on a specific reachable URL (for example ingress in remote devboxes), not loopback. This change allows that while preserving local defaults for existing users. ## Backward compatibility - No behavior change when `mcp_oauth_callback_url` is unset. - Existing `mcp_oauth_callback_port` behavior remains intact. - Local callback flows continue binding to loopback by default. ## Testing - `cargo test -p codex-rmcp-client callback -- --nocapture` - `cargo test -p codex-core --lib mcp_oauth_callback -- --nocapture` - `cargo check -p codex-cli -p codex-app-server -p codex-rmcp-client` ## Example config ```toml mcp_oauth_callback_port = 5555 mcp_oauth_callback_url = "https://<devbox>-<namespace>.gateway.<cluster>.internal.api.openai.org/callback"
dkumar-oai ·
2026-02-19 13:32:10 -08:00 -
rmcp-client: fix auth crash (#11692)
Don't load auth tokens if bearer token is present. This fixes a crash I was getting on Linux: ``` 2026-02-12T23:26:24.999408Z DEBUG session_init: codex_core::codex: Configuring session: model=gpt-5.3-codex-spark; provider=ModelProviderInfo { name: "OpenAI", base_url: None, env_key: None, env_key_instructions: No ne, experimental_bearer_token: None, wire_api: Responses, query_params: None, http_headers: Some({"version": "0.0.0"}), env_http_headers: Some({"OpenAI-Project": "OPENAI_PROJECT", "OpenAI-Organization": "OPENAI_ORGA NIZATION"}), request_max_retries: None, stream_max_retries: None, stream_idle_timeout_ms: None, requires_openai_auth: true, supports_websockets: true } 2026-02-12T23:26:24.999799Z TRACE session_init: codex_keyring_store: keyring.load start, service=Codex MCP Credentials, account=codex_apps|20398391ad12d90b thread 'tokio-runtime-worker' (96190) has overflowed its stack fatal runtime error: stack overflow, aborting Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.35s ```Max Johnson ·
2026-02-13 14:32:01 -08:00 -
Upgrade rmcp to 0.14 (#10718)
- [x] Upgrade rmcp to 0.14
Matthew Zeng ·
2026-02-08 15:07:53 -08:00 -
Process-group cleanup for stdio MCP servers to prevent orphan process storms (#10710)
This PR changes stdio MCP child processes to run in their own process group * Add guarded teardown in codex-rmcp-client: send SIGTERM to the group first, then SIGKILL after a short grace period. * Add terminate_process_group helper in process_group.rs. * Add Unix regression test in process_group_cleanup.rs to verify wrapper + grandchild are reaped on client drop. Addresses reported MCP process/thread storm: #10581
Eric Traut ·
2026-02-06 21:26:36 -08:00 -
feat: replace custom mcp-types crate with equivalents from rmcp (#10349)
We started working with MCP in Codex before https://crates.io/crates/rmcp was mature, so we had our own crate for MCP types that was generated from the MCP schema: https://github.com/openai/codex/blob/8b95d3e082376f4cb23e92641705a22afb28a9da/codex-rs/mcp-types/README.md Now that `rmcp` is more mature, it makes more sense to use their MCP types in Rust, as they handle details (like the `_meta` field) that our custom version ignored. Though one advantage that our custom types had is that our generated types implemented `JsonSchema` and `ts_rs::TS`, whereas the types in `rmcp` do not. As such, part of the work of this PR is leveraging the adapters between `rmcp` types and the serializable types that are API for us (app server and MCP) introduced in #10356. Note this PR results in a number of changes to `codex-rs/app-server-protocol/schema`, which merit special attention during review. We must ensure that these changes are still backwards-compatible, which is possible because we have: ```diff - export type CallToolResult = { content: Array<ContentBlock>, isError?: boolean, structuredContent?: JsonValue, }; + export type CallToolResult = { content: Array<JsonValue>, structuredContent?: JsonValue, isError?: boolean, _meta?: JsonValue, }; ``` so `ContentBlock` has been replaced with the more general `JsonValue`. Note that `ContentBlock` was defined as: ```typescript export type ContentBlock = TextContent | ImageContent | AudioContent | ResourceLink | EmbeddedResource; ``` so the deletion of those individual variants should not be a cause of great concern. Similarly, we have the following change in `codex-rs/app-server-protocol/schema/typescript/Tool.ts`: ``` - export type Tool = { annotations?: ToolAnnotations, description?: string, inputSchema: ToolInputSchema, name: string, outputSchema?: ToolOutputSchema, title?: string, }; + export type Tool = { name: string, title?: string, description?: string, inputSchema: JsonValue, outputSchema?: JsonValue, annotations?: JsonValue, icons?: Array<JsonValue>, _meta?: JsonValue, }; ``` so: - `annotations?: ToolAnnotations` ➡️ `JsonValue` - `inputSchema: ToolInputSchema` ➡️ `JsonValue` - `outputSchema?: ToolOutputSchema` ➡️ `JsonValue` and two new fields: `icons?: Array<JsonValue>, _meta?: JsonValue` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/10349). * #10357 * __->__ #10349 * #10356
Michael Bolin ·
2026-02-02 17:41:55 -08:00 -
Validate CODEX_HOME before resolving (#10249)
Summary - require `CODEX_HOME` to point to an existing directory before canonicalizing and surface clear errors otherwise - share the same helper logic in both `core` and `rmcp-client` and add unit tests that cover missing, non-directory, valid, and default paths This addresses #9222
Eric Traut ·
2026-01-30 15:46:33 -08:00 -
Show OAuth error descriptions in callback responses (#9654)
### Motivation - The local OAuth callback server returned a generic "Invalid OAuth callback" on failures even when the query contained an `error_description`, making it hard to debug OAuth failures. ### Description - Update `codex-rs/rmcp-client/src/perform_oauth_login.rs` to surface `error_description` values from the callback query in the HTTP response. - Introduce a `CallbackOutcome` enum and change `parse_oauth_callback` to return it, parsing `code`, `state`, and `error_description` from the query string. - Change `spawn_callback_server` to match on `CallbackOutcome` and return `OAuth error: <description>` with a 400 status when `error_description` is present, while preserving the existing success and invalid flows. - Use inline formatting for the error response string. ### Testing - Ran `just fmt` in the `codex-rs` workspace to format changes successfully. - Ran `cargo test -p codex-rmcp-client` and all tests passed. ------ [Codex Task](https://chatgpt.com/codex/tasks/task_i_6971aadc68d0832e93159efea8cd48a9)
blevy-oai ·
2026-01-27 13:22:54 -08:00 -
Fix: Render MCP image outputs regardless of ordering (#9815)
## What? - Render an MCP image output cell whenever a decodable image block exists in `CallToolResult.content` (including text-before-image or malformed image before valid image). ## Why? - Tool results that include caption text before the image currently drop the image output cell. - A malformed image block can also suppress later valid image output. ## How? - Iterate `content` and return the first successfully decoded image instead of only checking the first block. - Add unit tests that cover text-before-image ordering and invalid-image-before-valid. ## Before ```rust let image = match result { Ok(mcp_types::CallToolResult { content, .. }) => { if let Some(mcp_types::ContentBlock::ImageContent(image)) = content.first() { // decode image (fails -> None) } else { None } } _ => None, }?; ``` ## After ```rust let image = result .as_ref() .ok()? .content .iter() .find_map(decode_mcp_image)?; ``` ## Risk / Impact - Low: only affects image cell creation for MCP tool results; no change for non-image outputs. ## Tests - [x] `just fmt` - [x] `cargo test -p codex-tui` - [x] Rerun after branch update (2026-01-27): `just fmt`, `cargo test -p codex-tui` Manual testing # Manual testing: MCP image tool result rendering (Codex TUI) # Build the rmcp stdio test server binary: cd codex-rs cargo build -p codex-rmcp-client --bin test_stdio_server # Register the server as an MCP server (absolute path to the built binary): codex mcp add mcpimg -- /Users/joshka/code/codex-pr-review/codex-rs/target/debug/test_stdio_server # Then in Codex TUI, ask it to call: - mcpimg.image_scenario({"scenario":"image_only"}) - mcpimg.image_scenario({"scenario":"text_then_image","caption":"Here is the image:"}) - mcpimg.image_scenario({"scenario":"invalid_base64_then_image"}) - mcpimg.image_scenario({"scenario":"invalid_image_bytes_then_image"}) - mcpimg.image_scenario({"scenario":"multiple_valid_images"}) - mcpimg.image_scenario({"scenario":"image_then_text","caption":"Here is the image:"}) - mcpimg.image_scenario({"scenario":"text_only","caption":"Here is the image:"}) # Expected: # - You should see an extra history cell: "tool result (image output)" when the # tool result contains at least one decodable image block (even if earlier # blocks are text or invalid images). Fixes #9814 --------- Co-authored-by: Josh McKinney <joshka@openai.com>K Bediako ·
2026-01-27 21:14:08 +00:00 -
[connectors] Support connectors part 1 - App server & MCP (#9667)
In order to make Codex work with connectors, we add a built-in gateway MCP that acts as a transparent proxy between the client and the connectors. The gateway MCP collects actions that are accessible to the user and sends them down to the user, when a connector action is chosen to be called, the client invokes the action through the gateway MCP as well. - [x] Add the system built-in gateway MCP to list and run connectors. - [x] Add the app server methods and protocol
Matthew Zeng ·
2026-01-22 16:48:43 -08:00 -
add generated jsonschema for config.toml (#8956)
### What Add JSON Schema generation for `config.toml`, with checked‑in `docs/config.schema.json`. We can move the schema elsewhere if preferred (and host it if there's demand). Add fixture test to prevent drift and `just write-config-schema` to regenerate on schema changes. Generate MCP config schema from `RawMcpServerConfig` instead of `McpServerConfig` because that is the runtime type used for deserialization. Populate feature flag values into generated schema so they can be autocompleted. ### Tests Added tests + regenerate script to prevent drift. Tested autocompletions using generated jsonschema locally with Even Better TOML. https://github.com/user-attachments/assets/5aa7cd39-520c-4a63-96fb-63798183d0bc
sayan-oai ·
2026-01-13 10:22:51 -08:00