bytedance/deer-flow · error · HTTPException
MCP server '{server_name}' command must be a single executab
Error message
MCP server '{server_name}' command must be a single executable name; put parameters in args instead. What it means
400 raised when the stdio command field is not a single bare executable name: it contains leading/trailing whitespace, path separators ('/' or '\\'), internal whitespace, or shell metacharacters. The API executes the command directly without a shell, so only one token is accepted; parameters belong in args.
Source
Thrown at backend/app/gateway/routers/mcp.py:505
base = set(_DEFAULT_MCP_STDIO_COMMAND_ALLOWLIST)
if raw is None:
return base
extra = {item.strip() for item in raw.split(",") if item.strip()}
return base | extra
def _stdio_command_name(command: str | None, *, server_name: str) -> str:
"""Normalize and validate a stdio command field from the API boundary."""
if command is None or not command.strip():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"MCP server '{server_name}' with stdio transport requires a command.",
)
stripped = command.strip()
has_path_separator = "/" in stripped or "\\" in stripped
if stripped != command or has_path_separator or any(ch.isspace() for ch in stripped) or any(ch in stripped for ch in _SHELL_METACHARS):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=(f"MCP server '{server_name}' command must be a single executable name; put parameters in args instead."),
)
return stripped
def _launcher_option_region(args: list[str], *, grammar: _LauncherGrammar) -> list[str]:
"""Return the leading args a package launcher parses as its own options.
The region ends at a bare ``--`` or at the package name -- the first token
that is neither a flag nor the value of one. A ``--flag=value`` token
carries its own value and never consumes the next one.
Arity is looked up case-sensitively, because a launcher's short options are:
npm reads ``-c`` as ``--call`` but ``-C`` as ``--prefix``, which takes a
value.
"""View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Put only the executable name in command and move all flags into the args array
- Use a launcher (npx/uvx/uv run/etc.) from the allowlist as the command and the real package as the first arg
- If you need a specific binary path, symlink or install it on PATH and reference it by bare name, or extend the allowlist env var
Example fix
// before
{"command": "uvx --from git+https://... mcp-server"}
// after
{"command": "uvx", "args": ["--from", "git+https://...", "mcp-server"]} Defensive patterns
Strategy: validation
Validate before calling
const SHELL_METACHARS = new Set(';|&$`><\\"\'(){}[]!*?~');
function assertSingleExecutable(cmd: string) { const s = cmd.trim(); if (/[/\\]/.test(s) || /\s/.test(s) || [...s].some(c => SHELL_METACHARS.has(c)) || s !== cmd) throw new Error('command must be one bare executable name; put parameters in args'); } Type guard
function isBareExecutableName(cmd: string): boolean { return /^[A-Za-z0-9._-]+$/.test(cmd); } Try / catch
null
Prevention
- Treat command as exactly one token — tokenize the full invocation yourself and split command vs args
- Never paste a shell command line into the command field
- Avoid path-qualified binaries; put custom tools on PATH via deployment, not via the command string
When it happens
Trigger: Submitting command: 'npx -y foo' (flags inside command), command: '/usr/local/bin/npx' (absolute path), command: 'npx; rm -rf /' or 'npx && foo' (metacharacters), or command with stray whitespace.
Common situations: Copy-pasting a full CLI invocation from documentation into the command field; hardening-driven rejection of path-qualified binaries; attempts to chain commands or use shell syntax in a field that is exec'd directly.
Related errors
- MCP server '{server_name}' with stdio transport requires a c
- MCP server '{name}' uses disallowed stdio command '{command_
- MCP server '{name}' passes '{exec_flag}' to '{command_name}'
- MCP server '{name}' sets environment variable '{env_name}',
- Failed to load agents: ${res.statusText}
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/1a960babce450423.
Report an issue: GitHub.