{"record":{"id":"fd2ab831c7d3cdc7","repo":"HKUDS/Vibe-Trading","slug":"stdio-mcp-servers-require-a-command","errorCode":null,"errorMessage":"stdio MCP servers require a command","messagePattern":"stdio MCP servers require a command","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/config/schema.py","lineNumber":388,"sourceCode":"            raise ValueError(\"HTTP MCP servers require an explicit type of 'sse' or 'streamableHttp'\")\n        return \"stdio\"\n\n    @model_validator(mode=\"after\")\n    def validate_transport_config(self) -> \"MCPServerConfig\":\n        \"\"\"Validate transport-specific MCP server configuration.\n\n        Returns:\n            The validated MCP server config instance.\n\n        Raises:\n            ValueError: If required fields are missing for the resolved\n                transport or conflicting fields are provided.\n        \"\"\"\n        transport = self.resolved_transport()\n\n        if transport == \"stdio\":\n            if not self.command.strip():\n                raise ValueError(\"stdio MCP servers require a command\")\n            if self.url.strip() or self.headers:\n                raise ValueError(\"stdio MCP servers do not accept url/headers\")\n            if self.auth is not None:\n                raise ValueError(\"stdio MCP servers do not accept auth (OAuth is HTTP-only)\")\n            return self\n\n        if not self.url.strip():\n            raise ValueError(f\"{transport} MCP servers require a url\")\n        if self.command.strip() or self.args or self.env:\n            raise ValueError(f\"{transport} MCP servers do not accept command/args/env\")\n\n        if self.auth is not None:\n            # The OAuth provider owns the runtime Authorization header; a\n            # hand-set static header alongside it is always a config error.\n            if self.headers:\n                raise ValueError(\n                    \"MCP servers using auth must not also set static headers \"\n                    \"(the OAuth provider owns the Authorization header)\"","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/config/schema.py#L370-L406","documentation":"Raised by validate_transport_config when the resolved transport is stdio but the command field is empty or whitespace. stdio MCP servers launch a local process, so a command is mandatory.","triggerScenarios":"An MCP server entry with type: stdio (or implied stdio) and a missing/blank command; entries that only set args or env hoping the command is inherited.","commonSituations":"Copy-paste template missing the command line; environment-variable substitution producing an empty string; overriding a stdio server definition at runtime and dropping command.","solutions":["Set command to the executable to run, e.g. command: npx with args for the package.","If a URL server was intended, set url plus explicit type: sse/streamableHttp instead of leaving type as stdio.","Check that env-var interpolation in the config actually resolves to a value."],"exampleFix":"# before\nmcp_servers:\n  fs:\n    type: stdio\n    args: [\"-y\", \"@modelcontextprotocol/server-filesystem\"]\n\n# after\nmcp_servers:\n  fs:\n    type: stdio\n    command: npx\n    args: [\"-y\", \"@modelcontextprotocol/server-filesystem\"]","handlingStrategy":"validation","validationCode":"def stdio_entry_valid(entry: dict) -> bool:\n    transport = entry.get('type') or ('stdio' if entry.get('command') else None)\n    if transport == 'stdio':\n        return bool(str(entry.get('command', '')).strip())\n    return True","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Template stdio entries with command pre-filled (e.g. command: npx)","Fail fast on empty env-var interpolation in command fields"],"tags":["mcp","config","stdio","validation"],"backgroundTag":"config-validation-failed","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}