pub fn validate_server_config(config: &ServerConfig) -> Result<()>Expand description
Validates a ServerConfig for safe execution, dispatching on transport type.
This function performs comprehensive security validation before a config is used to connect to a server. It validates:
- Stdio transport: command (absolute path or binary name), arguments, and environment variables.
- Http/Sse transport: URL presence and scheme, and HTTP header names/values.
- Timeouts:
connect_timeout/discover_timeoutchecked against bounds, for all transports.
§Security Rules
- Forbidden chars in command/args:
;,|,&,>,<,`,$,(,),\n,\r - Env name charset: must match
[A-Za-z_][A-Za-z0-9_]*(POSIX/Windows environment variable identifier convention); rejects non-ASCII Unicode confusables (e.g. U+0131ı, U+017Fſ) that could otherwise dodge the ASCII-only case-insensitive comparison below while still resolving as the forbidden name on Windows - Forbidden env names: dynamic-linker (
LD_PRELOAD,LD_LIBRARY_PATH,LD_AUDIT,DYLD_*),PATH, and interpreter hijack vectors (NODE_OPTIONS,BASH_ENV,PYTHONPATH,PYTHONSTARTUP,RUBYOPT,PERL5OPT,JAVA_TOOL_OPTIONS), matched case-insensitively — see theFORBIDDEN_ENV_NAMESconstant’s doc comment in this module’s source for the full threat-model note - Absolute paths: Must exist and be executable
- Binary names: Allowed (resolved via PATH at runtime)
- URL scheme: Must be
http://orhttps:// - Header names/values: Must not contain control characters
- Timeout bounds:
connect_timeout/discover_timeoutmust be greater than zero and at mostMAX_TIMEOUT(600s) - Element counts/lengths (denial-of-service protection, CWE-400) — see this module’s
validate_stdio_size_bounds/validate_network_size_bounds: at mostMAX_ARG_COUNTargs,MAX_ENV_COUNTenv vars, andMAX_HEADER_COUNTheaders; at mostMAX_ARG_LENbytes per command/argument/env-name/header-name,MAX_ENV_VALUE_LENbytes per env value,MAX_HEADER_VALUE_LENbytes per header value, andMAX_URL_LENbytes for theurlfield
§Errors
Returns Error::SecurityViolation if:
- Command is empty or whitespace
- Command/args contain shell metacharacters
- Absolute path does not exist or is not executable
- Environment variable name is forbidden, or outside the
[A-Za-z_][A-Za-z0-9_]*charset - URL scheme is not
http:///https://, or a header name/value contains control characters
Returns Error::ValidationError if:
- URL is missing for Http/Sse transport
connect_timeoutordiscover_timeoutis zeroconnect_timeoutordiscover_timeoutexceedsMAX_TIMEOUT(600s)
§Examples
use mcp_execution_core::{ServerConfig, validate_server_config};
// Valid: binary name
let config = ServerConfig::builder()
.command("docker".to_string())
.build()
.unwrap();
assert!(validate_server_config(&config).is_ok());
// Invalid: forbidden env var — `ServerConfigBuilder::build()` already
// rejects this, so no unvalidated `ServerConfig` reaches this function.
let err = ServerConfig::builder()
.command("docker".to_string())
.env("LD_PRELOAD".to_string(), "/evil.so".to_string())
.build()
.unwrap_err();
assert!(err.is_security_error());
// Valid: HTTP transport
let config = ServerConfig::builder()
.http_transport("https://api.example.com/mcp".to_string())
.build()
.unwrap();
assert!(validate_server_config(&config).is_ok());§Security Considerations
- Binary names are allowed and resolved via PATH at runtime
- Absolute paths undergo strict validation (existence, permissions)
- All arguments are validated separately to prevent injection
- Environment variables are checked against forbidden names
- Header values are never echoed into error messages, since they routinely carry secrets such as bearer tokens
- Header names are never echoed either, once rejected: a
Name=ValueorName: ValueCLI argument can be mis-split on the wrong separator, leaving a full secret value in the “name” position — the token-charset error, the duplicate-header-name error, and the header-value control-character error all omit the name for this reason - There is no infinite-timeout option:
0is always rejected, since an unbounded wait would let a hung server block this non-interactive tool forever (see thevalidate_timeoutdesign note in this module)