29 Commits

  • [codex] Classify nested MCP authentication startup errors (#30257)
    ## Summary
    
    - classify authentication-required RMCP startup failures, including
    errors nested inside `ClientInitializeError::TransportError`
    - let `codex-mcp` consume that classification so the existing
    `reauthenticationRequired` startup failure reason is emitted
    - add a regression test that performs real startup with an expired
    persisted OAuth token and no refresh token
    
    ## Why
    
    Follow-up to #29877.
    
    RMCP stores streamable HTTP initialization failures inside a dynamic
    transport error whose payload is not exposed through the standard Rust
    error source chain. The original `anyhow::Error::chain()` check
    therefore missed the nested `AuthError::AuthorizationRequired` seen
    during real MCP startup and emitted `failureReason: null`.
    
    The transport-specific inspection now lives in `codex-rmcp-client`,
    while `codex-mcp` consumes only the domain-level authentication-required
    result. This classifier does not distinguish first-time login from
    reauthentication; the existing auth-state logic remains responsible for
    that distinction.
    
    ## User impact
    
    When stored MCP OAuth credentials are expired and cannot be refreshed,
    app clients now receive `failureReason: "reauthenticationRequired"` on
    the failed startup update and can show the reconnect action. First-time
    login and unrelated startup failures remain unchanged.
    
    ## Validation
    
    - `just test -p codex-rmcp-client --test streamable_http_oauth_startup
    identifies_expired_unrefreshable_token_startup_error`
    - `just test -p codex-mcp
    startup_outcome_error_identifies_authentication_required`
    - `just test -p codex-mcp
    mcp_startup_failure_reason_requires_existing_oauth_and_auth_failure`
    - `cargo build -p codex-cli --bin codex`
    - local app-server probe emitted `failureReason:
    "reauthenticationRequired"`
    - manual end-to-end reconnect flow confirmed
    - `just fmt`
  • [codex] Surface MCP reauthentication-required startup failures (#29877)
    ## Summary
    
    - distinguish expired, non-refreshable stored MCP OAuth credentials from
    first-time missing credentials
    - carry a typed `failureReason: "reauthenticationRequired"` on the
    existing `mcpServer/startupStatus/updated` notification only when user
    action is required
    - keep the public MCP auth-status API unchanged and regenerate the
    app-server protocol schemas and documentation
    
    ## Why
    
    An MCP server with an expired access token and no usable refresh token
    currently fails startup without giving clients a reliable, typed
    recovery signal.
    
    The existing startup-status notification is the natural place to carry
    this state. Its nullable `failureReason` keeps the recovery reason
    attached to the failed startup transition without adding a one-off
    notification. Internally, Codex distinguishes first-time login from
    reauthentication and emits the reason only when the startup error itself
    requires authentication.
    
    ## User impact
    
    App clients can prompt an existing user to reconnect an MCP server when
    automatic recovery is impossible by handling a failed
    `mcpServer/startupStatus/updated` notification whose `failureReason` is
    `reauthenticationRequired`. Starting, ready, cancelled, unrelated
    failures, and first-time setup carry no reauthentication reason.
    
    ## Companion app PR
    
    - openai/openai#1069582
    
    ## Validation
    
    - `just test -p codex-app-server-protocol` — 248 passed; schema fixture
    tests passed
    - `cargo check -p codex-app-server -p codex-tui`
    - `just test -p codex-rmcp-client -p codex-mcp` — 184 passed, 2 skipped
    - `just test -p codex-protocol -p codex-app-server-protocol -p
    codex-mcp` — 579 passed
    - `just write-app-server-schema`
    - `just fmt`
  • mcp: accept foreign absolute cwd for remote stdio (#29493)
    ## Why
    
    Remote stdio MCP servers can run in an environment whose path convention
    differs from the Codex host. A Windows cwd such as
    `C:\Users\openai\share` is absolute for the executor but was rejected by
    a POSIX orchestrator.
    
    Built on #29501, now merged, which only clarifies the host-native
    `PathUri` constructor name.
    
    ## What changed
    
    - Deserialize MCP cwd values as `LegacyAppPathString` so config does not
    apply host path rules.
    - Interpret that spelling as host-native for local launches and convert
    it to `PathUri` at executor launch.
    - Skip host filesystem and command resolution checks for remote stdio in
    `codex doctor`.
    - Add host-independent config and executor-boundary coverage using the
    foreign path convention for each test platform.
    
    ## Validation
    
    - `just test -p codex-utils-path-uri -p codex-config -p codex-mcp -p
    codex-rmcp-client` (408 passed)
    - `just test -p codex-cli -p codex-rmcp-client` (372 passed)
    - `cargo check --workspace --tests`
    - `just test` (11,311 passed; 43 unrelated environment/timing failures)
    - `just fix -p codex-cli -p codex-config -p codex-core -p codex-mcp -p
    codex-mcp-extension -p codex-rmcp-client -p codex-tui`
  • feat: use encrypted local secrets for MCP OAuth (#27541)
    ## Summary
    
    - store MCP OAuth credentials in the configured auth credential backend
    - support encrypted-local OAuth storage, including legacy keyring
    migration
    - propagate the credential backend through MCP refresh, session, CLI,
    and app-server paths
    
    ## Stack
    
    1. #27504 — config and feature flag
    2. #27535 — auth-specific secret namespaces
    3. #27539 — encrypted CLI auth storage
    4. this PR — encrypted MCP OAuth storage
    
    This is a parallel review stack; the original #17931 remains unchanged.
    
    ## Tests
    
    - `just test -p codex-rmcp-client` (the transport round-trip test passed
    after building the required `codex` binary and retrying)
    - `just test -p codex-mcp`
    - `just test -p codex-app-server
    refresh_config_uses_latest_auth_keyring_backend`
    - `just test -p codex-core
    refresh_mcp_servers_is_deferred_until_next_turn`
    - `just test -p codex-cli mcp`
    - `just fix -p codex-rmcp-client -p codex-mcp -p codex-core -p codex-cli
    -p codex-app-server -p codex-protocol`
    - `just bazel-lock-check`
  • [codex] Retry streamable HTTP initialize failures (#25147)
    ## Summary
    - Retry transient streamable HTTP failures during RMCP startup when the
    failure happens while sending the initialize request.
    - Retry transient streamable HTTP failures for tools/list, which is
    read-only and safe to replay.
    - Cover both retryable HTTP statuses and request-layer failures where no
    HTTP status is returned.
    - Surface retryable HTTP statuses from the streamable HTTP adapter as
    typed client errors.
    - Add integration coverage for initialize retry, tools/list retry,
    no-status request failure retry, and non-retryable initialize status.
    
    ## Root cause
    The observed codex_apps failures can happen before normal tool
    execution: RMCP startup fails while sending initialize, or the first
    read-only tools/list fails after startup. Retrying hosted_apps_bridge
    tools/call would not cover initialize and would risk replaying
    side-effecting tool calls. This change retries the streamable HTTP
    handshake itself, recreates the transport between initialize attempts,
    and retries only tools/list among post-initialize service operations.
    
    ## Validation
    - cargo fmt --package codex-rmcp-client
    - cargo test -p codex-rmcp-client --test streamable_http_recovery
  • [codex] Report unusable MCP OAuth credentials as logged out (#26713)
    ## Why
    
    Persisted MCP OAuth credentials were reported as authenticated whenever
    a credential record existed. An expired token without a usable refresh
    token could therefore appear as `OAuth` even though startup could not
    authenticate with it, leaving users with a misleading status instead of
    a login prompt.
    
    ## What changed
    
    - Classify stored OAuth credentials as missing, usable, or requiring
    authorization.
    - Reuse the existing refresh window so near-expiry credentials without a
    refresh path are also treated as logged out.
    - Validate required credential fields before reporting OAuth
    authentication.
    - Add unit coverage for credential usability and integration coverage
    for expired, unexpired, and refreshable persisted credentials.
    
    ## Validation
    
    - `just test -p codex-rmcp-client`
  • fix(rmcp): refresh expired OAuth tokens before startup (#26482)
    ## Why
    
    Codex persists OAuth expiry as an absolute `expires_at`, then
    reconstructs RMCP’s relative `expires_in` when credentials are loaded.
    For an already-expired token, Codex reconstructed `expires_in` as
    missing.
    
    [RMCP 0.15 treated a missing `expires_in` as zero when a refresh token
    was
    present](https://github.com/modelcontextprotocol/rust-sdk/blob/9cfc905a9ef17c8bba6748dc0a9bdd2452681733/crates/rmcp/src/transport/auth.rs#L704-L723),
    so this still triggered a refresh. [RMCP 1.7 treats missing expiry
    information as unknown and uses the access token
    as-is](https://github.com/modelcontextprotocol/rust-sdk/blob/3529c3675ff64db805bd947ca6ece6090809e43d/crates/rmcp/src/transport/auth.rs#L1233-L1265),
    causing the stale token to be sent during `initialize`.
    
    ## What changed
    
    - Represent a known-expired persisted token as `expires_in = 0`,
    preserving `None` for genuinely unknown expiry.
    - Add Streamable HTTP coverage requiring the token to refresh before the
    startup handshake.
    
    ## Validation
    
    - The new regression test fails on RMCP 1.7 before the fix and passes
    afterward.
    - The same scenario passes on the commit immediately before the RMCP 1.7
    update, using RMCP 0.15.
    - `just test -p codex-rmcp-client` (63 passed).
  • Update rmcp to 1.7.0 (#24763)
    WIll make it easier to uprev when the new draft spec is supported.
    
    Also updates reqwest where needed for compatibility but doesn't update
    it everywhere since this is already a large diff.
    
    The new version of rmcp handles certain kinds of authentication failures
    differently, this patch includes support for identifying the failing scope
    in a WWW-Authenticate header.
  • 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`.
  • 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.
  • [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>
  • [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>
  • 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.
  • 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.
  • 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()`.
  • 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>
  • [apps] Add tool call meta. (#14647)
    - [x] Add resource_uri and other things to _meta to shortcut resource
    lookup and speed things up.
  • Stabilize RMCP pid file cleanup test (#13881)
    ## What changed
    - The pid-file cleanup test now keeps polling when the pid file exists
    but is still empty.
    - Assertions only proceed once the wrapper has actually written the
    child pid.
    
    ## Why this fixes the flake
    - File creation and pid writing are not atomic as one logical action
    from the test’s point of view.
    - The previous test sometimes won the race and read the file in the tiny
    window after creation but before the pid bytes were flushed.
    - Treating “empty file” as “not ready yet” synchronizes the test on the
    real event we need: the wrapper has finished publishing the child pid.
    
    ## Scope
    - Test-only change.
  • [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
  • [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.
  • Upgrade rmcp to 0.14 (#10718)
    - [x] Upgrade rmcp to 0.14
  • 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
  • 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
  • feat: introduce codex-utils-cargo-bin as an alternative to assert_cmd::Command (#8496)
    This PR introduces a `codex-utils-cargo-bin` utility crate that
    wraps/replaces our use of `assert_cmd::Command` and
    `escargot::CargoBuild`.
    
    As you can infer from the introduction of `buck_project_root()` in this
    PR, I am attempting to make it possible to build Codex under
    [Buck2](https://buck2.build) as well as `cargo`. With Buck2, I hope to
    achieve faster incremental local builds (largely due to Buck2's
    [dice](https://buck2.build/docs/insights_and_knowledge/modern_dice/)
    build strategy, as well as benefits from its local build daemon) as well
    as faster CI builds if we invest in remote execution and caching.
    
    See
    https://buck2.build/docs/getting_started/what_is_buck2/#why-use-buck2-key-advantages
    for more details about the performance advantages of Buck2.
    
    Buck2 enforces stronger requirements in terms of build and test
    isolation. It discourages assumptions about absolute paths (which is key
    to enabling remote execution). Because the `CARGO_BIN_EXE_*` environment
    variables that Cargo provides are absolute paths (which
    `assert_cmd::Command` reads), this is a problem for Buck2, which is why
    we need this `codex-utils-cargo-bin` utility.
    
    My WIP-Buck2 setup sets the `CARGO_BIN_EXE_*` environment variables
    passed to a `rust_test()` build rule as relative paths.
    `codex-utils-cargo-bin` will resolve these values to absolute paths,
    when necessary.
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/8496).
    * #8498
    * __->__ #8496
  • support MCP elicitations (#6947)
    No support for request schema yet, but we'll at least show the message
    and allow accept/decline.
    
    <img width="823" height="551" alt="Screenshot 2025-11-21 at 2 44 05 PM"
    src="https://github.com/user-attachments/assets/6fbb892d-ca12-4765-921e-9ac4b217534d"
    />
  • [MCP] Add support for resources (#5239)
    This PR adds support for [MCP
    resources](https://modelcontextprotocol.io/specification/2025-06-18/server/resources)
    by adding three new tools for the model:
    1. `list_resources`
    2. `list_resource_templates`
    3. `read_resource`
    
    These 3 tools correspond to the [three primary MCP resource protocol
    messages](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#protocol-messages).
    
    Example of listing and reading a GitHub resource tempalte
    <img width="2984" height="804" alt="CleanShot 2025-10-15 at 17 31 10"
    src="https://github.com/user-attachments/assets/89b7f215-2e2a-41c5-90dd-b932ac84a585"
    />
    
    `/mcp` with Figma configured
    <img width="2984" height="442" alt="CleanShot 2025-10-15 at 18 29 35"
    src="https://github.com/user-attachments/assets/a7578080-2ed2-4c59-b9b4-d8461f90d8ee"
    />
    
    Fixes #4956