bytedance/deer-flow · error · HTTPException
MCP server '{server_name}' with stdio transport requires a c
Error message
MCP server '{server_name}' with stdio transport requires a command. What it means
400 raised by _stdio_command_name when an API-managed stdio MCP server definition has a command field that is None, empty, or whitespace-only. stdio servers spawn a local process, so a command is mandatory — the API boundary rejects the definition before anything is persisted or executed.
Source
Thrown at backend/app/gateway/routers/mcp.py:497
return [_merge_extra_value_preserving_masked(key, nested_value, existing_value[index], existing_present=True) for index, nested_value in enumerate(incoming_value)]
return incoming_value
def _allowed_stdio_commands() -> set[str]:
"""Return executable names allowed for API-managed stdio MCP servers."""
raw = os.environ.get(_MCP_STDIO_COMMAND_ALLOWLIST_ENV)
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.
View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Add the executable name to the command field (e.g. command: 'npx') and move any flags into args
- If the server is remote, set type to 'sse' or 'http' and provide url instead of command
- Validate the payload locally against McpServerConfigResponse before submitting
Example fix
// before
{"my-server": {"type": "stdio", "args": ["-y", "some-mcp"]}}
// after
{"my-server": {"type": "stdio", "command": "npx", "args": ["-y", "some-mcp"]}} Defensive patterns
Strategy: validation
Validate before calling
function assertStdioServer(name: string, cfg: {type?: string; command?: string; url?: string}) { const t = (cfg.type ?? 'stdio').toLowerCase(); if (t === 'stdio' && !(cfg.command && cfg.command.trim())) throw new Error(`server ${name}: stdio transport requires command`); if (t !== 'stdio' && !cfg.url) throw new Error(`server ${name}: ${t} transport requires url`); } Type guard
function isStdioServerConfig(cfg: {type?: string; command?: string; url?: string}): cfg is {type: 'stdio'; command: string; args?: string[]} { return (cfg.type ?? 'stdio').toLowerCase() === 'stdio' && typeof cfg.command === 'string' && cfg.command.trim().length > 0; } Try / catch
null
Prevention
- Remember type defaults to stdio when omitted — then command is required
- Keep flags in args, never inside command
- Lint config-as-code with the same rules the API enforces before submitting
When it happens
Trigger: POST/PUT to /api/mcp/config with a server entry of type stdio (the default when type is omitted) whose command is missing; a payload where the command ended up in args and command was left null; enabling a stored server whose raw JSON lacks a command field.
Common situations: Hand-written extensions_config.json or API payloads modeled after SSE/HTTP servers (which need url, not command); copy-paste config snippets that omit the command key; frontend forms defaulting transport to stdio without requiring the command input.
Related errors
- MCP server '{server_name}' command must be a single executab
- Failed to update MCP configuration
- Cannot set extra config key '{key}' to masked value '***'; p
- MCP server '{name}' uses disallowed stdio command '{command_
- MCP server '{name}' passes '{exec_flag}' to '{command_name}'
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/115eba0da355d347.
Report an issue: GitHub.