Support threadless MCP connections without event channels (#34408)

## What changed

- Make the MCP connection manager's event sender optional.
- Skip startup notifications when a caller has no session event stream.
- Decline interactive MCP elicitations in that mode while allowing the
  underlying operation to continue.
- Update threadless resource reads, status snapshots, and connector discovery
  to use the channel-free path.

## Testing

- Extend the app-server MCP resource test to verify that a threadless resource
  read declines an elicitation and still returns the resource contents.

GitOrigin-RevId: 65fea152adbc02a78e09a40cae4134b6dccffd34
This commit is contained in:
stevenlee-oai authored and copyberry committed 2026-07-20 20:43:36 +00:00
1 parent b7e39aa316
commit 19940967bd
14 files changed
+185 -124

No files matched your search

+1 -5
View File
@@ -5,7 +5,6 @@ use std::sync::Mutex as StdMutex;
use std::time::Duration;
use std::time::Instant;
use async_channel::unbounded;
pub use codex_connectors::AppBranding;
pub use codex_connectors::AppInfo;
pub use codex_connectors::AppMetadata;
@@ -235,9 +234,6 @@ pub async fn list_accessible_connectors_from_mcp_tools_with_mcp_manager(
let runtime_context =
McpRuntimeContext::new(Arc::clone(&environment_manager), config.cwd.to_path_buf());
let (tx_event, rx_event) = unbounded();
drop(rx_event);
let cancel_token = CancellationToken::new();
let codex_apps_auth_manager =
codex_mcp::host_owned_codex_apps_enabled(&mcp_config, auth.as_ref())
@@ -248,7 +244,7 @@ pub async fn list_accessible_connectors_from_mcp_tools_with_mcp_manager(
config.auth_keyring_backend_kind(),
&config.permissions.approval_policy,
INITIAL_SUBMIT_ID.to_owned(),
tx_event,
/*tx_event*/ None,
cancel_token.clone(),
PermissionProfile::default(),
// Connector discovery is threadless. Use an actually configured env if
+1 -2
View File
@@ -1449,7 +1449,6 @@ async fn host_owned_codex_apps_manager(
let auth = session.services.auth_manager.auth().await;
let startup_cancellation_token = CancellationToken::new();
startup_cancellation_token.cancel();
let (tx_event, _rx_event) = async_channel::unbounded();
let mcp_servers = HashMap::from([(
CODEX_APPS_MCP_SERVER_NAME.to_string(),
codex_mcp::EffectiveMcpServer::configured(codex_mcp::codex_apps_mcp_server_config(
@@ -1464,7 +1463,7 @@ async fn host_owned_codex_apps_manager(
turn_context.config.auth_keyring_backend_kind(),
&turn_context.approval_policy,
turn_context.sub_id.clone(),
tx_event,
/*tx_event*/ None,
startup_cancellation_token,
turn_context.permission_profile(),
codex_mcp::McpRuntimeContext::new(
+1 -1
View File
@@ -451,7 +451,7 @@ impl Session {
mcp_config.auth_keyring_backend_kind,
&turn_context.approval_policy,
turn_context.sub_id.clone(),
self.get_tx_event(),
Some(self.get_tx_event()),
mcp_startup_cancellation_token,
turn_context.permission_profile(),
mcp_runtime_context.clone(),
+1 -1
View File
@@ -1218,7 +1218,7 @@ impl Session {
config.auth_keyring_backend_kind(),
&session_configuration.approval_policy,
INITIAL_SUBMIT_ID.to_owned(),
tx_event.clone(),
Some(tx_event.clone()),
mcp_startup_cancellation_token,
session_configuration.permission_profile(),
mcp_runtime_context.clone(),