{"record":{"id":"115eba0da355d347","repo":"bytedance/deer-flow","slug":"mcp-server-server-name-with-stdio-transport-re","errorCode":null,"errorMessage":"MCP server '{server_name}' with stdio transport requires a command.","messagePattern":"MCP server '(.+?)' with stdio transport requires a command\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"backend/app/gateway/routers/mcp.py","lineNumber":497,"sourceCode":"        return [_merge_extra_value_preserving_masked(key, nested_value, existing_value[index], existing_present=True) for index, nested_value in enumerate(incoming_value)]\n\n    return incoming_value\n\n\ndef _allowed_stdio_commands() -> set[str]:\n    \"\"\"Return executable names allowed for API-managed stdio MCP servers.\"\"\"\n    raw = os.environ.get(_MCP_STDIO_COMMAND_ALLOWLIST_ENV)\n    base = set(_DEFAULT_MCP_STDIO_COMMAND_ALLOWLIST)\n    if raw is None:\n        return base\n    extra = {item.strip() for item in raw.split(\",\") if item.strip()}\n    return base | extra\n\n\ndef _stdio_command_name(command: str | None, *, server_name: str) -> str:\n    \"\"\"Normalize and validate a stdio command field from the API boundary.\"\"\"\n    if command is None or not command.strip():\n        raise HTTPException(\n            status_code=status.HTTP_400_BAD_REQUEST,\n            detail=f\"MCP server '{server_name}' with stdio transport requires a command.\",\n        )\n\n    stripped = command.strip()\n    has_path_separator = \"/\" in stripped or \"\\\\\" in stripped\n    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):\n        raise HTTPException(\n            status_code=status.HTTP_400_BAD_REQUEST,\n            detail=(f\"MCP server '{server_name}' command must be a single executable name; put parameters in args instead.\"),\n        )\n\n    return stripped\n\n\ndef _launcher_option_region(args: list[str], *, grammar: _LauncherGrammar) -> list[str]:\n    \"\"\"Return the leading args a package launcher parses as its own options.\n","sourceCodeStart":479,"sourceCodeEnd":515,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/mcp.py#L479-L515","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n{\"my-server\": {\"type\": \"stdio\", \"args\": [\"-y\", \"some-mcp\"]}}\n// after\n{\"my-server\": {\"type\": \"stdio\", \"command\": \"npx\", \"args\": [\"-y\", \"some-mcp\"]}}","handlingStrategy":"validation","validationCode":"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`); }","typeGuard":"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; }","tryCatchPattern":"null","preventionTips":["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"],"tags":["mcp","stdio","config","validation","http-400"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}