Refine partial MCP layer validation

This commit is contained in:
Felix Xia
2026-06-24 20:42:05 +01:00
parent 70135cc051
commit b009f83994
3 changed files with 12 additions and 37 deletions
@@ -20,7 +20,6 @@ use codex_config::ConfigLayerStackOrdering;
use codex_config::ConfigRequirementsToml;
use codex_config::config_toml::ConfigToml;
use codex_config::merge_toml_values;
use codex_config::validate_config_toml_layer;
use codex_core::config::deserialize_config_toml_with_base;
use codex_core::config::edit::ConfigEdit;
use codex_core::config::edit::ConfigEditsBuilder;
@@ -294,25 +293,23 @@ impl ConfigManager {
parsed_segments.push(segments);
}
validate_config_toml_layer(user_config.clone(), self.codex_home()).map_err(|err| {
// MCP server entries may be completed by lower-precedence config layers,
// while feature requirements must still be checked against the user's
// explicit settings before the write is persisted.
let mut user_config_for_feature_validation = user_config.clone();
if let Some(table) = user_config_for_feature_validation.as_table_mut() {
table.remove("mcp_servers");
}
let user_config_toml = deserialize_config_toml_with_base(
user_config_for_feature_validation,
self.codex_home(),
)
.map_err(|err| {
ConfigManagerError::write(
ConfigWriteErrorCode::ConfigValidationError,
format!("Invalid configuration: {err}"),
)
})?;
let mut user_config_without_mcp_servers = user_config.clone();
if let Some(table) = user_config_without_mcp_servers.as_table_mut() {
table.remove("mcp_servers");
}
let user_config_toml =
deserialize_config_toml_with_base(user_config_without_mcp_servers, self.codex_home())
.map_err(|err| {
ConfigManagerError::write(
ConfigWriteErrorCode::ConfigValidationError,
format!("Invalid configuration: {err}"),
)
})?;
validate_feature_requirements_for_config_toml(
&user_config_toml,
layers.requirements().feature_requirements.as_ref(),
-1
View File
@@ -147,7 +147,6 @@ pub use state::ConfigLayerStackOrdering;
pub use state::ConfigLoadOptions;
pub use state::LoaderOverrides;
pub use strict_config::config_error_from_ignored_toml_fields;
pub use strict_config::validate_config_toml_layer;
pub use thread_config::NoopThreadConfigLoader;
pub use thread_config::RemoteThreadConfigLoader;
pub use thread_config::SessionThreadConfig;
-21
View File
@@ -10,7 +10,6 @@ use crate::diagnostics::span_for_config_path;
use crate::diagnostics::span_for_toml_key_path;
use crate::diagnostics::text_range_from_span;
use codex_features::is_known_feature_key;
use codex_utils_absolute_path::AbsolutePathBufGuard;
use serde::Deserialize;
use serde::de::DeserializeOwned;
use std::collections::HashMap;
@@ -60,26 +59,6 @@ pub(crate) fn config_error_from_config_toml_layer_for_source_name(
)
}
/// Validate one config layer without requiring an MCP server fragment to
/// contain a transport. MCP server definitions are merged recursively across
/// config layers, so transport completeness is validated on the effective
/// config after composition.
pub fn validate_config_toml_layer(
mut value: TomlValue,
base_dir: &Path,
) -> Result<(), toml::de::Error> {
let _guard = AbsolutePathBufGuard::new(base_dir);
let mcp_servers = value
.as_table_mut()
.and_then(|table| table.remove("mcp_servers"));
let _: ConfigToml = value.try_into()?;
if let Some(mcp_servers) = mcp_servers {
let _: ConfigTomlMcpServersLayer = mcp_servers_layer(mcp_servers).try_into()?;
}
Ok(())
}
/// Strictly validate one config layer while allowing MCP server fragments to
/// receive their transport from a lower-precedence layer.
fn config_error_from_config_toml_layer_for_source(