Hmbown/CodeWhale · error
MCP config path cannot contain '..' components
Error message
MCP config path cannot contain '..' components
What it means
MCP config paths must not contain `..` parent-directory components; validate_mcp_config_path rejects them to prevent escaping the intended config location (path-traversal guard). This check runs on every config load, read, mutation, and workspace source switch.
Solutions
- Provide a normalized absolute path with no `..` components (e.g. via `realpath` or `canonicalize`)
- Move or point the config to a path inside the intended directory instead of traversing upward
- In scripts, use `$(realpath path)` before passing to --mcp-config
Example fix
# before codewhale --mcp-config ~/projects/../codewhale/mcp.json ... # after codewhale --mcp-config "$(realpath ~/projects/../codewhale/mcp.json)" ...
Defensive patterns
Strategy: validation
Validate before calling
const p = require("path").resolve(mcpConfigPath);
if (p.split(require("path").sep).includes("..")) {
throw new Error("MCP config path must not contain '..' components");
} Try / catch
try {
loadMcpConfig(userPath);
} catch (e) {
if (String(e).includes("'..' components")) {
// suggest canonicalizing: path.resolve(userPath), then retry
}
} Prevention
- Always canonicalize user-supplied paths (realpath/resolve) before storing them in config
- Keep MCP configs inside a single known directory
- Never construct config paths via manual string concatenation with `..`
When it happens
Trigger: Passing a path like `~/projects/../mcp.json` or `configs/../../etc/mcp.json` via --mcp-config or a config field; programmatically building an MCP config path with relative parent hops.
Common situations: Users trying to keep an MCP config outside the expected directory via relative paths; scripts joining paths with `..` instead of normalizing; symlink-adjacent traversal attempts blocked defensively.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Codewhale credentials directory has an unsupported component
- config path must not be a symlink
- Invalid MCP command
- MCP config path cannot be empty
- MCP HTTP destination blocked by network policy
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/3542e71be4719ae9.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/mcp.rs:64
const ERROR_BODY_PREVIEW_BYTES: usize = 200;
/// Newest dated MCP protocol revision Codewhale advertises at `initialize` and
/// answers as an MCP server. Matches the shared MCP crate (`crates/mcp`).
pub(crate) const MCP_PROTOCOL_VERSION: &str = "2025-06-18";
/// Dated MCP revisions accepted during negotiation, newest first. A peer
/// answering or requesting any of these continues the handshake.
pub(crate) const MCP_SUPPORTED_PROTOCOL_VERSIONS: &[&str] =
&[MCP_PROTOCOL_VERSION, "2025-03-26", "2024-11-05"];
fn validate_mcp_config_path(path: &Path) -> Result<()> {
if path.as_os_str().is_empty() {
anyhow::bail!("MCP config path cannot be empty");
}
if path
.components()
.any(|component| matches!(component, Component::ParentDir))
{
anyhow::bail!("MCP config path cannot contain '..' components");
}
Ok(())
}
/// Expand `${NAME}` placeholders in an MCP config value from the process
/// environment. This lets secrets (API keys, bearer tokens, …) be supplied
/// through environment variables instead of being written in cleartext into
/// the MCP config file on disk.
///
/// On a missing or malformed placeholder the error names only the offending
/// variable, never the surrounding value, so a secret-bearing string is never
/// echoed into logs or error output.
fn expand_env_placeholders_with(
value: &str,
environment: Option<&crate::plugins::HostEnvironment>,
) -> Result<String> {
let mut out = String::new();
let mut rest = value;View on GitHub (pinned to 73e0f67d83)