mirror of
https://github.com/openai/codex.git
synced 2026-11-05 20:10:33 +00:00
Move connector auth repair to server metadata
This commit is contained in:
@@ -109,7 +109,6 @@ pub struct McpConnectionManager {
|
||||
server_metadata: HashMap<String, McpServerMetadata>,
|
||||
required_servers: Vec<String>,
|
||||
tool_plugin_provenance: Arc<ToolPluginProvenance>,
|
||||
host_owned_codex_apps_enabled: bool,
|
||||
prefix_mcp_tool_names: bool,
|
||||
elicitation_requests: ElicitationRequestManager,
|
||||
startup_cancellation_token: CancellationToken,
|
||||
@@ -130,7 +129,6 @@ impl McpConnectionManager {
|
||||
runtime_context: McpRuntimeContext,
|
||||
codex_home: PathBuf,
|
||||
codex_apps_tools_cache_key: CodexAppsToolsCacheKey,
|
||||
host_owned_codex_apps_enabled: bool,
|
||||
prefix_mcp_tool_names: bool,
|
||||
client_elicitation_capability: ElicitationCapability,
|
||||
supports_openai_form_elicitation: bool,
|
||||
@@ -252,7 +250,6 @@ impl McpConnectionManager {
|
||||
server_metadata,
|
||||
required_servers,
|
||||
tool_plugin_provenance,
|
||||
host_owned_codex_apps_enabled,
|
||||
prefix_mcp_tool_names,
|
||||
elicitation_requests: elicitation_requests.clone(),
|
||||
startup_cancellation_token: startup_cancellation_token.clone(),
|
||||
@@ -338,7 +335,6 @@ impl McpConnectionManager {
|
||||
server_metadata: HashMap::new(),
|
||||
required_servers: Vec::new(),
|
||||
tool_plugin_provenance: Arc::new(ToolPluginProvenance::default()),
|
||||
host_owned_codex_apps_enabled: false,
|
||||
prefix_mcp_tool_names,
|
||||
elicitation_requests: ElicitationRequestManager::new(
|
||||
approval_policy.value(),
|
||||
@@ -405,8 +401,10 @@ impl McpConnectionManager {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn is_host_owned_codex_apps_server(&self, server_name: &str) -> bool {
|
||||
self.host_owned_codex_apps_enabled && server_name == CODEX_APPS_MCP_SERVER_NAME
|
||||
pub fn server_supports_connector_auth_repair(&self, server_name: &str) -> bool {
|
||||
self.server_metadata
|
||||
.get(server_name)
|
||||
.is_some_and(McpServerMetadata::supports_connector_auth_repair)
|
||||
}
|
||||
|
||||
pub fn set_approval_policy(&self, approval_policy: &Constrained<AskForApproval>) {
|
||||
|
||||
@@ -1147,6 +1147,7 @@ async fn list_all_tools_adds_server_metadata_to_cached_tools() {
|
||||
"https://docs.example".to_string(),
|
||||
)),
|
||||
supports_parallel_tool_calls: true,
|
||||
supports_connector_auth_repair: false,
|
||||
default_tools_approval_mode: None,
|
||||
tool_approval_modes: HashMap::new(),
|
||||
},
|
||||
@@ -1276,7 +1277,6 @@ async fn no_local_runtime_fails_local_stdio_but_keeps_local_http_server() {
|
||||
chatgpt_user_id: None,
|
||||
is_workspace_account: false,
|
||||
},
|
||||
/*host_owned_codex_apps_enabled*/ false,
|
||||
/*prefix_mcp_tool_names*/ true,
|
||||
ElicitationCapability::default(),
|
||||
/*supports_openai_form_elicitation*/ false,
|
||||
|
||||
@@ -41,7 +41,6 @@ pub use mcp::codex_apps_mcp_server_config;
|
||||
pub use mcp::configured_mcp_servers;
|
||||
pub use mcp::effective_mcp_servers;
|
||||
pub use mcp::effective_mcp_servers_from_configured;
|
||||
pub use mcp::host_owned_codex_apps_enabled;
|
||||
pub use mcp::hosted_plugin_runtime_mcp_server_config;
|
||||
pub use mcp::tool_plugin_provenance;
|
||||
pub use plugin_config::PluginMcpConfigParseOutcome;
|
||||
|
||||
@@ -231,10 +231,6 @@ impl ToolPluginProvenance {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn host_owned_codex_apps_enabled(config: &McpConfig, auth: Option<&CodexAuth>) -> bool {
|
||||
config.apps_enabled && auth.is_some_and(CodexAuth::uses_codex_backend)
|
||||
}
|
||||
|
||||
pub fn configured_mcp_servers(config: &McpConfig) -> HashMap<String, McpServerConfig> {
|
||||
config.mcp_server_catalog.configured_servers()
|
||||
}
|
||||
@@ -255,14 +251,24 @@ pub fn effective_mcp_servers_from_configured(
|
||||
config: &McpConfig,
|
||||
auth: Option<&CodexAuth>,
|
||||
) -> HashMap<String, EffectiveMcpServer> {
|
||||
let mut servers = configured_servers
|
||||
let codex_apps_available =
|
||||
config.apps_enabled && auth.is_some_and(CodexAuth::uses_codex_backend);
|
||||
configured_servers
|
||||
.into_iter()
|
||||
.map(|(name, server)| (name, EffectiveMcpServer::configured(server)))
|
||||
.collect::<HashMap<_, _>>();
|
||||
if !host_owned_codex_apps_enabled(config, auth) {
|
||||
servers.remove(CODEX_APPS_MCP_SERVER_NAME);
|
||||
}
|
||||
servers
|
||||
.filter_map(|(name, server)| {
|
||||
if name == CODEX_APPS_MCP_SERVER_NAME && !codex_apps_available {
|
||||
return None;
|
||||
}
|
||||
|
||||
let server = EffectiveMcpServer::configured(server);
|
||||
let server = if name == CODEX_APPS_MCP_SERVER_NAME {
|
||||
server.with_connector_auth_repair()
|
||||
} else {
|
||||
server
|
||||
};
|
||||
Some((name, server))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn tool_plugin_provenance(config: &McpConfig) -> ToolPluginProvenance {
|
||||
@@ -277,7 +283,6 @@ pub async fn read_mcp_resource(
|
||||
uri: &str,
|
||||
) -> anyhow::Result<ReadResourceResult> {
|
||||
let mut mcp_servers = effective_mcp_servers(config, auth);
|
||||
let host_owned_codex_apps_enabled = host_owned_codex_apps_enabled(config, auth);
|
||||
mcp_servers.retain(|name, _| name == server);
|
||||
let auth_statuses = compute_auth_statuses(
|
||||
mcp_servers.iter(),
|
||||
@@ -302,7 +307,6 @@ pub async fn read_mcp_resource(
|
||||
runtime_context,
|
||||
config.codex_home.clone(),
|
||||
codex_apps_tools_cache_key(auth),
|
||||
host_owned_codex_apps_enabled,
|
||||
config.prefix_mcp_tool_names,
|
||||
config.client_elicitation_capability.clone(),
|
||||
/*supports_openai_form_elicitation*/ false,
|
||||
@@ -337,7 +341,6 @@ pub async fn collect_mcp_server_status_snapshot_with_detail(
|
||||
detail: McpSnapshotDetail,
|
||||
) -> McpServerStatusSnapshot {
|
||||
let mcp_servers = effective_mcp_servers(config, auth);
|
||||
let host_owned_codex_apps_enabled = host_owned_codex_apps_enabled(config, auth);
|
||||
let tool_plugin_provenance = tool_plugin_provenance(config);
|
||||
if mcp_servers.is_empty() {
|
||||
return McpServerStatusSnapshot {
|
||||
@@ -377,7 +380,6 @@ pub async fn collect_mcp_server_status_snapshot_with_detail(
|
||||
runtime_context,
|
||||
config.codex_home.clone(),
|
||||
codex_apps_tools_cache_key(auth),
|
||||
host_owned_codex_apps_enabled,
|
||||
config.prefix_mcp_tool_names,
|
||||
config.client_elicitation_capability.clone(),
|
||||
/*supports_openai_form_elicitation*/ false,
|
||||
|
||||
@@ -14,15 +14,22 @@ pub(crate) enum McpServerLaunch {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EffectiveMcpServer {
|
||||
launch: McpServerLaunch,
|
||||
connector_auth_repair: bool,
|
||||
}
|
||||
|
||||
impl EffectiveMcpServer {
|
||||
pub fn configured(config: McpServerConfig) -> Self {
|
||||
Self {
|
||||
launch: McpServerLaunch::Configured(Box::new(config)),
|
||||
connector_auth_repair: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_connector_auth_repair(mut self) -> Self {
|
||||
self.connector_auth_repair = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn launch(&self) -> &McpServerLaunch {
|
||||
&self.launch
|
||||
}
|
||||
@@ -44,6 +51,10 @@ impl EffectiveMcpServer {
|
||||
McpServerLaunch::Configured(config) => config.required,
|
||||
}
|
||||
}
|
||||
|
||||
fn supports_connector_auth_repair(&self) -> bool {
|
||||
self.connector_auth_repair
|
||||
}
|
||||
}
|
||||
|
||||
/// Transport origin retained for metrics and diagnostics after server launch.
|
||||
@@ -79,11 +90,16 @@ pub(crate) struct McpServerMetadata {
|
||||
pub pollutes_memory: bool,
|
||||
pub origin: Option<McpServerOrigin>,
|
||||
pub supports_parallel_tool_calls: bool,
|
||||
pub supports_connector_auth_repair: bool,
|
||||
pub default_tools_approval_mode: Option<AppToolApproval>,
|
||||
pub tool_approval_modes: HashMap<String, AppToolApproval>,
|
||||
}
|
||||
|
||||
impl McpServerMetadata {
|
||||
pub fn supports_connector_auth_repair(&self) -> bool {
|
||||
self.supports_connector_auth_repair
|
||||
}
|
||||
|
||||
pub fn tool_approval_mode(&self, tool_name: &str) -> AppToolApproval {
|
||||
self.tool_approval_modes
|
||||
.get(tool_name)
|
||||
@@ -101,6 +117,7 @@ impl From<&EffectiveMcpServer> for McpServerMetadata {
|
||||
pollutes_memory: true,
|
||||
origin: McpServerOrigin::from_transport(&config.transport),
|
||||
supports_parallel_tool_calls: config.supports_parallel_tool_calls,
|
||||
supports_connector_auth_repair: server.supports_connector_auth_repair(),
|
||||
default_tools_approval_mode: config.default_tools_approval_mode,
|
||||
tool_approval_modes: config
|
||||
.tools
|
||||
|
||||
@@ -40,7 +40,6 @@ use codex_mcp::ToolPluginProvenance;
|
||||
use codex_mcp::codex_apps_tools_cache_key;
|
||||
use codex_mcp::compute_auth_statuses;
|
||||
use codex_mcp::effective_mcp_servers;
|
||||
use codex_mcp::host_owned_codex_apps_enabled;
|
||||
use codex_mcp::tool_plugin_provenance;
|
||||
|
||||
const CONNECTORS_READY_TIMEOUT_ON_EMPTY_TOOLS: Duration = Duration::from_secs(30);
|
||||
@@ -240,7 +239,6 @@ pub async fn list_accessible_connectors_from_mcp_tools_with_mcp_manager(
|
||||
|
||||
let mut mcp_servers = effective_mcp_servers(&mcp_config, auth.as_ref());
|
||||
mcp_servers.retain(|name, _| name == CODEX_APPS_MCP_SERVER_NAME);
|
||||
let host_owned_codex_apps_enabled = host_owned_codex_apps_enabled(&mcp_config, auth.as_ref());
|
||||
if mcp_servers.is_empty() {
|
||||
return Ok(AccessibleConnectorsStatus {
|
||||
connectors: Vec::new(),
|
||||
@@ -275,7 +273,6 @@ pub async fn list_accessible_connectors_from_mcp_tools_with_mcp_manager(
|
||||
McpRuntimeContext::new(environment_manager, config.cwd.to_path_buf()),
|
||||
config.codex_home.to_path_buf(),
|
||||
codex_apps_tools_cache_key(auth.as_ref()),
|
||||
host_owned_codex_apps_enabled,
|
||||
mcp_config.prefix_mcp_tool_names,
|
||||
mcp_config.client_elicitation_capability,
|
||||
/*supports_openai_form_elicitation*/ false,
|
||||
|
||||
@@ -635,7 +635,7 @@ async fn maybe_request_codex_apps_auth_elicitation(
|
||||
.services
|
||||
.mcp_connection_manager
|
||||
.load_full()
|
||||
.is_host_owned_codex_apps_server(server)
|
||||
.server_supports_connector_auth_repair(server)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::state::ActiveTurn;
|
||||
use crate::test_support::models_manager_with_provider;
|
||||
use crate::tools::hook_names::HookToolName;
|
||||
use crate::turn_metadata::McpTurnMetadataContext;
|
||||
use async_channel::unbounded;
|
||||
use codex_config::CONFIG_TOML_FILE;
|
||||
use codex_config::config_toml::ConfigToml;
|
||||
use codex_config::types::AppConfig;
|
||||
@@ -20,6 +21,9 @@ use codex_config::types::McpServerToolConfig;
|
||||
use codex_features::Features;
|
||||
use codex_hooks::Hooks;
|
||||
use codex_hooks::HooksConfig;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_mcp::codex_apps_mcp_server_config;
|
||||
use codex_mcp::effective_mcp_servers_from_configured;
|
||||
use codex_model_provider::create_model_provider;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
@@ -1333,17 +1337,37 @@ fn codex_apps_auth_failure_metadata() -> McpToolApprovalMetadata {
|
||||
)
|
||||
}
|
||||
|
||||
async fn install_host_owned_codex_apps_manager(session: &Session, turn_context: &TurnContext) {
|
||||
let auth = session.services.auth_manager.auth().await;
|
||||
async fn install_connector_auth_repair_manager(session: &Session, turn_context: &TurnContext) {
|
||||
let auth = CodexAuth::create_dummy_chatgpt_auth_for_testing();
|
||||
let mut mcp_config = turn_context
|
||||
.config
|
||||
.to_mcp_config(session.services.plugins_manager.as_ref())
|
||||
.await;
|
||||
mcp_config.apps_enabled = true;
|
||||
let mcp_servers = effective_mcp_servers_from_configured(
|
||||
HashMap::from([(
|
||||
CODEX_APPS_MCP_SERVER_NAME.to_string(),
|
||||
codex_apps_mcp_server_config(
|
||||
&turn_context.config.chatgpt_base_url,
|
||||
/*apps_mcp_product_sku*/ None,
|
||||
),
|
||||
)]),
|
||||
&mcp_config,
|
||||
Some(&auth),
|
||||
);
|
||||
let (tx_event, rx_event) = unbounded();
|
||||
drop(rx_event);
|
||||
let startup_cancellation_token = CancellationToken::new();
|
||||
startup_cancellation_token.cancel();
|
||||
let manager = codex_mcp::McpConnectionManager::new(
|
||||
&HashMap::new(),
|
||||
&mcp_servers,
|
||||
turn_context.config.mcp_oauth_credentials_store_mode,
|
||||
turn_context.config.auth_keyring_backend_kind(),
|
||||
HashMap::new(),
|
||||
&turn_context.approval_policy,
|
||||
turn_context.sub_id.clone(),
|
||||
session.get_tx_event(),
|
||||
CancellationToken::new(),
|
||||
tx_event,
|
||||
startup_cancellation_token,
|
||||
turn_context.permission_profile(),
|
||||
codex_mcp::McpRuntimeContext::new(
|
||||
session.services.turn_environments.environment_manager(),
|
||||
@@ -1353,13 +1377,12 @@ async fn install_host_owned_codex_apps_manager(session: &Session, turn_context:
|
||||
},
|
||||
),
|
||||
turn_context.config.codex_home.to_path_buf(),
|
||||
codex_mcp::codex_apps_tools_cache_key(auth.as_ref()),
|
||||
/*host_owned_codex_apps_enabled*/ true,
|
||||
codex_mcp::codex_apps_tools_cache_key(Some(&auth)),
|
||||
turn_context.config.prefix_mcp_tool_names(),
|
||||
rmcp::model::ElicitationCapability::default(),
|
||||
/*supports_openai_form_elicitation*/ false,
|
||||
codex_mcp::ToolPluginProvenance::default(),
|
||||
auth.as_ref(),
|
||||
Some(&auth),
|
||||
/*elicitation_reviewer*/ None,
|
||||
)
|
||||
.await;
|
||||
@@ -1372,7 +1395,7 @@ async fn install_host_owned_codex_apps_manager(session: &Session, turn_context:
|
||||
#[tokio::test]
|
||||
async fn codex_apps_auth_elicitation_feature_disabled_returns_original_result() {
|
||||
let (session, turn_context, rx_event) = make_session_and_context_with_rx().await;
|
||||
install_host_owned_codex_apps_manager(&session, &turn_context).await;
|
||||
install_connector_auth_repair_manager(&session, &turn_context).await;
|
||||
let result = codex_apps_auth_failure_result();
|
||||
let metadata = codex_apps_auth_failure_metadata();
|
||||
|
||||
@@ -1391,7 +1414,7 @@ async fn codex_apps_auth_elicitation_feature_disabled_returns_original_result()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn codex_apps_auth_elicitation_non_host_owned_server_returns_original_result() {
|
||||
async fn codex_apps_auth_elicitation_server_without_repair_capability_returns_original_result() {
|
||||
let (session, mut turn_context, rx_event) = make_session_and_context_with_rx().await;
|
||||
let mut features = Features::with_defaults();
|
||||
features.enable(Feature::AuthElicitation);
|
||||
@@ -1417,7 +1440,7 @@ async fn codex_apps_auth_elicitation_non_host_owned_server_returns_original_resu
|
||||
#[tokio::test]
|
||||
async fn codex_apps_auth_elicitation_disallowed_by_policy_returns_original_result() {
|
||||
let (session, mut turn_context, rx_event) = make_session_and_context_with_rx().await;
|
||||
install_host_owned_codex_apps_manager(&session, &turn_context).await;
|
||||
install_connector_auth_repair_manager(&session, &turn_context).await;
|
||||
let mut features = Features::with_defaults();
|
||||
features.enable(Feature::AuthElicitation);
|
||||
let turn_context = Arc::get_mut(&mut turn_context).expect("single turn context ref");
|
||||
@@ -1446,7 +1469,7 @@ async fn codex_apps_auth_elicitation_disallowed_by_policy_returns_original_resul
|
||||
#[tokio::test]
|
||||
async fn codex_apps_auth_elicitation_granular_mcp_disabled_returns_original_result() {
|
||||
let (session, mut turn_context, rx_event) = make_session_and_context_with_rx().await;
|
||||
install_host_owned_codex_apps_manager(&session, &turn_context).await;
|
||||
install_connector_auth_repair_manager(&session, &turn_context).await;
|
||||
let mut features = Features::with_defaults();
|
||||
features.enable(Feature::AuthElicitation);
|
||||
let turn_context = Arc::get_mut(&mut turn_context).expect("single turn context ref");
|
||||
@@ -1481,7 +1504,7 @@ async fn codex_apps_auth_elicitation_granular_mcp_disabled_returns_original_resu
|
||||
#[tokio::test]
|
||||
async fn codex_apps_auth_elicitation_feature_enabled_requests_elicitation() {
|
||||
let (session, mut turn_context, rx_event) = make_session_and_context_with_rx().await;
|
||||
install_host_owned_codex_apps_manager(&session, &turn_context).await;
|
||||
install_connector_auth_repair_manager(&session, &turn_context).await;
|
||||
*session.active_turn.lock().await = Some(ActiveTurn::default());
|
||||
let mut features = Features::with_defaults();
|
||||
features.enable(Feature::AuthElicitation);
|
||||
|
||||
@@ -317,8 +317,6 @@ impl Session {
|
||||
let tool_plugin_provenance = codex_mcp::tool_plugin_provenance(&mcp_config);
|
||||
let mcp_servers =
|
||||
effective_mcp_servers_from_configured(mcp_servers, &mcp_config, auth.as_ref());
|
||||
let host_owned_codex_apps_enabled =
|
||||
host_owned_codex_apps_enabled(&mcp_config, auth.as_ref());
|
||||
let auth_statuses = compute_auth_statuses(
|
||||
mcp_servers.iter(),
|
||||
store_mode,
|
||||
@@ -359,7 +357,6 @@ impl Session {
|
||||
mcp_runtime_context,
|
||||
config.codex_home.to_path_buf(),
|
||||
codex_apps_tools_cache_key(auth.as_ref()),
|
||||
host_owned_codex_apps_enabled,
|
||||
mcp_config.prefix_mcp_tool_names,
|
||||
mcp_config.client_elicitation_capability,
|
||||
self.services
|
||||
|
||||
@@ -343,7 +343,6 @@ use codex_git_utils::get_git_repo_root;
|
||||
use codex_mcp::McpConfig;
|
||||
use codex_mcp::compute_auth_statuses;
|
||||
use codex_mcp::effective_mcp_servers_from_configured;
|
||||
use codex_mcp::host_owned_codex_apps_enabled;
|
||||
use codex_otel::SessionTelemetry;
|
||||
use codex_otel::THREAD_STARTED_METRIC;
|
||||
use codex_otel::TelemetryAuthMode;
|
||||
|
||||
@@ -1138,9 +1138,6 @@ impl Session {
|
||||
sess.send_event_raw(event).await;
|
||||
}
|
||||
|
||||
let host_owned_codex_apps_enabled = config
|
||||
.features
|
||||
.apps_enabled_for_auth(auth.as_ref().is_some_and(|auth| auth.uses_codex_backend()));
|
||||
let client_elicitation_capability = if config.features.enabled(Feature::AuthElicitation) {
|
||||
ElicitationCapability {
|
||||
form: Some(FormElicitationCapability::default()),
|
||||
@@ -1183,7 +1180,6 @@ impl Session {
|
||||
mcp_runtime_context,
|
||||
config.codex_home.to_path_buf(),
|
||||
codex_apps_tools_cache_key(auth),
|
||||
host_owned_codex_apps_enabled,
|
||||
config.prefix_mcp_tool_names(),
|
||||
client_elicitation_capability,
|
||||
sess.services
|
||||
|
||||
Reference in New Issue
Block a user