## What changed
- Allow MCP server names to contain `:`, `@`, `/`, and `.`, enabling names such as `npm:@modelcontextprotocol/server-sequential.thinking`.
- Preserve these names across `mcp add`, `get`, `list`, and `remove`, runtime tool namespaces, and OAuth credential lookup.
- Quote non-bare server names in generated `config.toml` recovery hints and keep similarly escaped OAuth credential names isolated.
## Testing
- Add CLI and runtime round-trip coverage for npm-style names.
- Add snapshot coverage for quoted recovery hints and a regression test for OAuth credential-name collisions.
GitOrigin-RevId: 97e9353cdbc544db4eb2377ddbfa1d2d539b1e04
## Why
An MCP binding can wait for one server while another connection updates a
shared tool catalog. Preferring the catalog captured before that wait can omit
newly available tools from the first model request.
## What changed
- Recheck the current MCP tool catalog before using the captured fallback.
- Keep the captured catalog when it expires during the wait, while honoring a
server that disables catalog caching.
## Testing
- Cover a shared Apps cache populated by a peer while binding capture waits.
- Cover cache opt-out while capture waits for another server.
GitOrigin-RevId: e4389c7ba23e4d8397dbae0930c9e36ba0a172fb
## Why
Binding capture can wait for multiple MCP servers concurrently. During that wait, a tool catalog may be published by another connection or expire after it has already allowed a server to remain dormant. Re-reading only the current cache could omit those tools or trigger unnecessary startup.
## What changed
- Retain the cached catalog that permits lazy startup for the duration of binding capture.
- Recheck the cache after the optional startup grace so catalogs published while waiting are included.
- Add regression coverage for catalogs published during startup and catalogs that expire while another server is resolving.
GitOrigin-RevId: b5c66831db8f9ebecc79ff25c5b4b0182ad68a2f
## What changed
- Add `mcp_optional_startup_grace_ms` with a default of 1,000 ms to control how long tool catalog capture waits for optional MCP servers.
- Treat a value of `0` as disabling the shared grace, so optional servers use their configured `startup_timeout_sec` instead.
- Apply updated grace values during runtime and MCP configuration refreshes, and reset cached startup deadlines when the configured duration changes.
## Testing
- Cover custom, disabled, refreshed, and shared startup grace behavior in MCP connection and core integration tests.
GitOrigin-RevId: 936196215ed6e0a29c9ec72cfee17663978df8ef
## Why
MCP servers attached to executor environments must retain their owner's
permission profile instead of inheriting the thread-wide sandbox authority.
## What changed
- Resolve and capture a permission profile for each enabled MCP server when
publishing the runtime, and reject calls or elicitations when that authority
is unavailable.
- Use the captured server profile for tool approval decisions, elicitation, and
sandbox metadata, including after runtime refreshes.
- Materialize `:workspace_roots` from `PathUri` values so permissions preserve
the path convention of remote executor environments.
- Give threadless app discovery and resource reads an explicit default
permission profile.
## Testing
Added coverage for per-server elicitation authority, unresolved attachments,
runtime refreshes, restricted tool calls, and foreign-platform workspace roots.
GitOrigin-RevId: 6b188d4b08b29e9971ff7aa68a7785a0cdf9e394
## Why
MCP inventory can be cached or collected separately from a thread's live
connections, so tool availability alone does not describe the current runtime
state.
## What changed
- Add a nullable `runtimeStatus` to `mcpServerStatus/list` for thread-scoped
requests, covering not-started, starting, connected, authentication-required,
failed, cancelled, and disabled connections.
- Observe published connection state without starting or reconnecting servers,
and return an unknown status when no thread is supplied or the active
configuration no longer matches the published registration.
- Show connection state and tool counts in the compact `/mcp` view while
retaining the detailed inventory in `/mcp verbose` and compatibility with
servers that omit `runtimeStatus`.
## Testing
- Cover runtime status transitions, deferred and disabled servers, closed
transports, configuration changes, protocol compatibility, and TUI rendering.
GitOrigin-RevId: e3bb6efe652f0fa8b3c97d5c53e4729b3a87cd91
## What changed
- Add experimental `mcpServer/event/stream/start` and `mcpServer/event/stream/stop` requests for hosted apps, plus `mcpServer/event/stream/notification` forwarding.
- Scope subscriptions to the owning app-server connection and subscribed thread, enforce unique IDs and a per-connection limit, and clean them up when the thread is unsubscribed or the connection closes.
- Wait for the MCP active notification before completing startup, retry streams that close immediately, and terminate them when authentication or hosted runtime ownership changes.
## Testing
- Add an app-server integration test covering activation, event forwarding, duplicate subscription rejection, and explicit cancellation.
GitOrigin-RevId: 8a6fc1615adfc5af7e67def3b824fa5909ab3e7b
## What changed
- Execute hook-triggered MCP calls through the runtime's latest connection set instead of preparing a separate catalog-bound call.
- Keep hook calls from waiting for server startup or reconnecting, and reject disconnected servers immediately.
- Apply the shorter of the hook-requested timeout and the server's configured tool timeout.
## Testing
- Update connection manager tests to cover non-waiting calls and disabled tool filters.
GitOrigin-RevId: 3166b2d1e26d9ae2b8b3a648b4d0897cc260eb93
## What changed
- Execute `mcp_tool` hook handlers through the session's shared MCP runtime, including managed hook configurations.
- Restrict hook calls to already-connected, cataloged, and policy-allowed tools. Unavailable servers fail immediately without starting or reconnecting them.
- Pass session metadata to hook tools, cap hook timeouts by the server timeout, and invoke hooks without model-tool approval or recursive hook dispatch.
- Record handler type and execution mode in hook telemetry, and mark memory as externally influenced after successful or blocking MCP hooks when configured.
## Testing
- Added end-to-end coverage for prompt interpolation, hidden tools, blocking decisions, unavailable servers, thread metadata, approval bypass, and memory-mode handling.
- Added MCP runtime coverage for startup readiness, tool filters, catalog revisions, and managed connector policy.
GitOrigin-RevId: 1647cb801ebc5fa385c7bda9d9c266a389c611b8
## Why
App widgets need to read resources using the app and account context of the
tool call that produced them, including after a thread is restored.
## What changed
- Add an optional `originCallId` to `mcpServer/resource/read` requests and
return it on successful scoped reads.
- Track bounded provenance for successful app tool calls in thread history and
use the current tool binding, account link, and app policy when reading the
associated widget resource.
- Reject missing, mismatched, failed, or ambiguous origins, while keeping
app-only tools available for widget reads without exposing them to the model.
## Testing
Add app-server coverage for scoped widget reads across both history modes,
ephemeral and persistent threads, server restarts, app-only visibility, and
invalid origin cases.
GitOrigin-RevId: 11eaefc066b2a3b639599e4cbdef680233d150a2
## Why
When an MCP server rejects existing OAuth credentials, reporting that the server
is merely not logged in obscures that the user needs to authenticate again.
## What changed
Pass the MCP startup failure reason into error formatting and report that the
server requires OAuth reauthentication when appropriate. Preserve the existing
recovery hint for either `codex mcp login` or the client's OAuth sign-in flow.
## Testing
Cover the reauthentication message for both login flows and verify it in the
streamable HTTP OAuth round-trip test.
GitOrigin-RevId: 6f6d5fe7519b1a476f8b70d976223b2ea1ec938e
## Why
Subagents can reuse cached MCP tool definitions without opening another server
connection immediately, but marking a server as required previously forced eager
startup even when its cached tools were available.
## What changed
- Allow required MCP servers with usable cached tools to remain dormant under
the lazy startup policy.
- Treat those cached tools as satisfying required-server validation and tool
catalog capture until the server is needed.
- Preserve eager startup for required servers without cached tools and start a
dormant server when one of its tools is called.
## Testing
Extend the cached HTTP MCP subagent test to cover both optional and required
servers, verifying that the required server stays dormant until its cached tool
is called.
GitOrigin-RevId: 48ea20b9ae447eef27461caee2320ea78465bb6a
## What changed
- Expose hosted Plugin Runtime event definitions through `McpResourceClient::list_events`.
- Add cancellable `events/stream` subscriptions that route lifecycle notifications to the matching request and cancel when the stream is dropped.
- Bound event notification and queue sizes, time out stalled response headers, and close streamable HTTP responses locally on cancellation.
## Testing
- Add streamable HTTP integration coverage for isolated concurrent subscriptions, local cancellation, and stalled response-header timeouts.
GitOrigin-RevId: 98c6fffa8f004eb2638c1b0705f659222cbbdfdb
## Why
An OAuth-backed Streamable HTTP MCP server can fail startup when its stored credentials are rejected. If a client then completes OAuth sign-in and replaces those credentials, the failed server needs to become available without restarting the Codex session.
## What changed
- Track the credential store and OAuth tokens used for each MCP connection, and detect replacements after authentication failures.
- Refresh affected MCP servers before the next turn and include their recovered tools in the model request.
- Classify HTTP authentication challenges and rejected refresh tokens as requiring reauthentication, with sign-in guidance appropriate to local and client-managed environments.
## Testing
- Cover recovery from expired credentials through an externally written replacement token.
- Cover authentication-error classification, startup messaging, and `Auto` store migration from file credentials to the keyring.
GitOrigin-RevId: 9b090089d4e7a44ffc182f4e25da20a18e97b70f
## Why
Subagents can reuse cached MCP tool definitions without starting every optional
server before any of its tools are used.
## What changed
- Defer startup for subagent-owned, optional MCP servers when their cache has at
least one visible, allowed tool, and trigger startup on the first operation
that needs the live client.
- Keep root sessions, required servers, selected plugin servers, and explicit
reconnects eager.
- Exclude empty catalogs from cache eligibility and keep dormant servers out of
the initial startup summary.
## Testing
- Extend MCP tool-cache coverage for eager root startup, unused and filtered
subagent servers, deferred startup status events, and startup that survives an
interrupted first tool call.
GitOrigin-RevId: e7528ff08312583a6747cbc6550ea5b6eabda9a6
## What changed
- Cache an `McpBinding` on each published MCP runtime once server startup has
settled and the tool catalog revision is stable.
- Reuse the cached binding while the catalog revision remains unchanged, and
rebuild it after a runtime publish or catalog change.
- Treat terminal failures from optional servers as stable, while continuing to
wait for required servers and reconnecting Codex Apps servers.
## Testing
- Cover binding reuse within one published runtime and invalidation after a
republish.
- Cover stability checks for pending, failed optional, required, and
reconnected servers.
GitOrigin-RevId: 783a6b04897f6c484a6d56fd9cee542814041759
## Why
Codex Apps tool catalogs can exceed the standard MCP limit of 2,048 items and
still need to remain available through tool search.
## What changed
- Allow up to 8,192 catalog items for host-owned `codex_apps` registrations.
- Keep the 2,048-item limit for other MCP servers, including extensions that
register the `codex_apps` name.
- Restrict the shared Codex Apps tool cache to host-owned registrations.
## Testing
- Cover large catalogs for built-in and hosted-plugin registrations while
verifying that another extension retains the standard limit.
- Verify that a same-named extension cannot read the host-owned Apps cache.
GitOrigin-RevId: 2265693a460e9be63c4c849169cba7324def4f49
## Why
Executor-owned MCP servers must not receive hosted ChatGPT actor credentials or credentials from the host's OAuth store.
## What changed
- Provide the ChatGPT auth provider and consult stored OAuth credentials only for MCP servers in the local environment.
- Require non-local servers configured with `auth = "chatgpt"` to supply a non-empty, valid static `Authorization` header. Reject environment-backed authorization so host secrets are not resolved for an executor-owned server.
- Report unsupported authentication and fail startup before connecting when an executor-owned server has no acceptable explicit authorization.
## Testing
Add coverage for local credential forwarding, non-local credential isolation, static header validation, auth status, OAuth lookup avoidance, and startup rejection.
GitOrigin-RevId: e18f1878f260c93d9babd390a5a7eac86172299b
## Why
OAuth discovery failures do not establish that an MCP server lacks OAuth
support. Reporting those failures as `unsupported` conflates an inconclusive
check with a confirmed result.
## What changed
- Add an `unknown` MCP authentication status across the protocol, app server,
CLI, and TUI.
- Preserve OAuth discovery errors so callers can report `unknown`, while
retaining `unsupported` for servers known not to support OAuth.
- Document the distinction in the app server API.
## Testing
- Verify transient HTTP discovery errors are preserved.
- Verify `codex mcp list --json` reports `unknown` when discovery is rate
limited.
GitOrigin-RevId: e4562985971606740538e542ec7eeee502111964
## Why
MCP catalog discovery must not allow a server to keep pagination running or
growing without bounds.
## What changed
- Apply the shared pagination collector to tool, resource, and resource-template
discovery.
- Limit each catalog to 100 pages and 1,024 items, and reject pagination cursors
larger than 64 KiB or any repeated cursor.
- Bound the entire pagination operation by the configured tool timeout, falling
back to 30 seconds when no timeout is configured.
## Testing
Add unit coverage for every limit and an end-to-end MCP test that preserves
valid multi-page tools while excluding a server that returns an oversized
cursor.
GitOrigin-RevId: 961a1bfa5fe8a265daf56e342a919c980cd720fa
## Why
Each connection set could restart the one-second startup grace for the same
cacheable optional MCP server, repeatedly delaying catalog capture while that
server was still pending.
## What changed
- Store the optional startup deadline in the shared tool catalog cache entry.
- Reuse that deadline until a catalog is published, and allow a fresh grace
period after the cached catalog expires.
- Preserve per-connection-set startup grace for servers that disable catalog
caching.
## Testing
Added a paused-time test covering shared deadlines, immediate cached-tool reuse,
cache expiration, and disabled caching.
GitOrigin-RevId: 3494969ee7002c70ce9e4ffd370e46a22d38cc11
## What changed
- Resolve per-server tool catalogs concurrently in `list_all_tools` and binding capture.
- After the shared startup wait, recheck servers that previously exposed cached tools so a newly ready client contributes its current catalog and callable client.
## Testing
- Add gated-client tests that verify multiple server catalogs start before any one server is released.
- Verify binding capture replaces cached Codex Apps tools with the ready client's tools when startup completes during capture.
GitOrigin-RevId: a30d1a535ed1588f2bba21f2741e8bbd9342e339
## Why
A pending optional MCP server can delay the first model request even when the
turn does not need that server.
## What changed
- Give optional MCP servers a shared one-second startup grace, then omit servers
that are still pending from the captured tool catalog.
- Continue waiting when the turn explicitly requires a server through a plugin,
skill dependency, or `mcp://` mention, and preserve this behavior for input
received between sampling steps.
- Route direct resource requests to the live connection set when a pending
server was omitted from the binding, while keeping all-server resource
discovery non-blocking.
## Testing
- Cover the shared grace period and resource behavior for pending optional
servers.
- Verify plugin, plugin-skill, and direct MCP mentions wait for startup.
- Verify an Apps-enabled turn proceeds without tools from an unrelated pending
optional server.
GitOrigin-RevId: b5f895c5a5362fe73f7d33250367662d4a217e4d
## Why
Cached MCP definitions can be supplied to inference without waiting for the
server to finish initializing.
## What changed
- Publish cached tools while startup is still in progress, clearing their
potentially stale read-only hint.
- Wait for the selected server to start before executing a tool call, then
prepare the call against the refreshed live binding.
- Keep cached tools visible in a binding even when no live client is available,
while rejecting attempts to prepare those calls.
## Testing
- Cover cached-tool visibility before startup and replacement with live tool
metadata afterward.
- Verify cached definitions reach inference before MCP initialization and that
calls unavailable in the live catalog return the expected model-visible
error.
GitOrigin-RevId: 3aae8f474c344ccdc5e08fe321bbad21d85bffd1
## What changed
- Accept a table form of `features.non_prefixed_mcp_tool_names` with an
optional `server_names` list while preserving the existing boolean form.
- Omit the legacy `mcp__` namespace prefix only for tools from selected MCP
servers. When no server list is provided, the enabled feature continues to
omit the prefix for every server.
- Cover configuration resolution, tool normalization, and an MCP stdio
round trip with selected servers.
GitOrigin-RevId: bdfb7ac54226de5051f06610e2c6b78b23912ef0
## Why
Refreshing MCP runtime state should not restart an unchanged, ready server or
relist its tools.
## What changed
- Reconcile refreshed MCP configuration against the published connection set
and reuse connections whose transport, environment, authentication, OAuth
credentials, and client capabilities are unchanged.
- Keep tool filters, timeouts, metadata, and plugin provenance in the published
server view so those settings can change without reconnecting.
- Update elicitation authority in place for reused connections, and reconnect
when connection-defining inputs or live OAuth credentials change.
## Testing
Added coverage for unchanged-server reuse, view-only and elicitation-policy
updates, connection identity changes, OAuth credential changes, and avoiding
redundant tool listing.
GitOrigin-RevId: f04f5db5fbdde127b6a14f6aa9673112c0b557e7
## What changed
- Make `McpRuntime` own the published MCP configuration, connections, elicitation routing, and selected capability roots for a thread.
- Capture immutable MCP bindings for model steps and tool calls so in-flight work keeps a consistent connection set and approval authority while refreshed state is published atomically.
- Mark MCP state dirty when relevant configuration, plugins, environments, authentication, or elicitation capabilities change, then rebuild it before the next sampling request or out-of-band MCP operation.
- Separate config reloads from server invalidation: `ReloadMcpConfig` applies resolved MCP inputs, while `RefreshMcpServers` requests reinitialization from the thread's latest state.
## Testing
- Cover refreshed state visibility for existing turns, stable step bindings, current approval authority, cancelled refresh retries, resource-client reconciliation, and Apps recovery between sampling requests.
GitOrigin-RevId: 59eabb1aa8dc083426bd18ef4d3630508f376401
## What changed
- Use `McpConnectionSet` as the primary name for the collection of active MCP
server connections throughout `codex-mcp` and its callers.
- Keep `McpConnectionManager` as a backward-compatible type alias.
GitOrigin-RevId: 9753838b4fd0a0b6429a9c4af0c077137616f388
## Why
An MCP connection or tool catalog can change after a model step captures its
available tools. Calls from that step must not be rerouted to a replacement
client or run against a catalog revision the model did not see.
## What changed
- Add `McpBinding` to capture the ready clients, visible tools, resources, and
server metadata for one sampling request.
- Prepare calls against the captured client and reject them if the tool catalog
changes before call preparation and execution finish.
- Keep resource access and cache identity tied to the binding's exact connection
set, and omit servers that do not have a ready client.
- Preserve each client's unfiltered tool catalog so bindings can apply the
current filter consistently.
## Testing
Add coverage for connection replacement, stale catalog rejection, serialized
call preparation and refresh, ready-client capture, and binding-scoped resource
identity.
GitOrigin-RevId: a25da4d2c7f5ed06c41caa0c6d15c464c1698314
## What changed
- Move required-server startup validation into `connection_manager/required.rs`.
- Move tool listing, lookup, metadata attachment, and Codex Apps cache refresh into `connection_manager/tool_catalog.rs`.
- Keep the existing connection-manager API and behavior unchanged.
GitOrigin-RevId: 7249896699f756bdbb6e00bc2bbc4a98098741a9