# PR #1591: Added mcp-server name validation - URL: https://github.com/openai/codex/pull/1591 - Author: preetDev004 - Created: 2025-07-16 16:38:38 UTC - Updated: 2025-07-16 23:00:51 UTC - Changes: +18/-2, Files changed: 1, Commits: 6 ## Description This PR implements server name validation for MCP (Model Context Protocol) servers to ensure they conform to the required pattern ^[a-zA-Z0-9_-]+$. This addresses the TODO comment in mcp_connection_manager.rs:82. + Added validation before spawning MCP client tasks + Invalid server names are added to errors map with descriptive messages I have read the CLA Document and I hereby sign the CLA ## Full Diff ```diff diff --git a/codex-rs/core/src/mcp_connection_manager.rs b/codex-rs/core/src/mcp_connection_manager.rs index 6ae1865f16..7cf6762752 100644 --- a/codex-rs/core/src/mcp_connection_manager.rs +++ b/codex-rs/core/src/mcp_connection_manager.rs @@ -79,9 +79,19 @@ impl McpConnectionManager { // Launch all configured servers concurrently. let mut join_set = JoinSet::new(); + let mut errors = ClientStartErrors::new(); for (server_name, cfg) in mcp_servers { - // TODO: Verify server name: require `^[a-zA-Z0-9_-]+$`? + // Validate server name before spawning + if !is_valid_mcp_server_name(&server_name) { + let error = anyhow::anyhow!( + "invalid server name '{}': must match pattern ^[a-zA-Z0-9_-]+$", + server_name + ); + errors.insert(server_name, error); + continue; + } + join_set.spawn(async move { let McpServerConfig { command, args, env } = cfg; let client_res = McpClient::new_stdio_client(command, args, env).await; @@ -117,7 +127,6 @@ impl McpConnectionManager { let mut clients: HashMap> = HashMap::with_capacity(join_set.len()); - let mut errors = ClientStartErrors::new(); while let Some(res) = join_set.join_next().await { let (server_name, client_res) = res?; // JoinError propagation @@ -208,3 +217,10 @@ pub async fn list_all_tools( Ok(aggregated) } + +fn is_valid_mcp_server_name(server_name: &str) -> bool { + !server_name.is_empty() + && server_name + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-') +} ``` ## Review Comments ### codex-rs/core/src/mcp_connection_manager.rs - Created: 2025-07-16 16:40:53 UTC | Link: https://github.com/openai/codex/pull/1591#discussion_r2210941410 ```diff @@ -79,9 +80,17 @@ impl McpConnectionManager { // Launch all configured servers concurrently. let mut join_set = JoinSet::new(); + let mut errors = ClientStartErrors::new(); for (server_name, cfg) in mcp_servers { - // TODO: Verify server name: require `^[a-zA-Z0-9_-]+$`? + // Validate server name before spawning + if !is_valid_server_name(&server_name) { + let error = anyhow::anyhow!("invalid server name '{}': must match pattern ^[a-zA-Z0-9_-]+$", server_name); + errors.insert(server_name, error); + continue; + } + + let server_name_cloned = server_name.clone(); ``` > Is this necessary? If we have reached this point, nothing else has taken ownership of `server_name`, correct? ### codex-rs/core/src/util.rs - Created: 2025-07-16 16:42:26 UTC | Link: https://github.com/openai/codex/pull/1591#discussion_r2210945426 ```diff @@ -64,3 +64,9 @@ pub fn is_inside_git_repo(config: &Config) -> bool { false } + +pub fn is_valid_server_name(server_name: &str) -> bool { ``` > I don't really like having generic "util" files because it's not clear what goes in there: please keep this in `mcp_connection_manager.rs` since that is the only place it is used.