{"record":{"id":"a03a5c4056604d4b","repo":"BerriAI/litellm","slug":"stdio-config-is-required-for-stdio-transport","errorCode":null,"errorMessage":"stdio_config is required for stdio transport","messagePattern":"stdio_config is required for stdio transport","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/experimental_mcp_client/client.py","lineNumber":269,"sourceCode":"        self._elicitation_callback: Callable | None = elicitation_callback\n        self._logging_callback: Callable | None = logging_callback\n        # handle the basic auth value if provided\n        if auth_value:\n            self.update_auth_value(auth_value)\n\n    def _create_transport_context(\n        self,\n    ) -> tuple[Any, httpx.AsyncClient | None]:\n        \"\"\"\n        Create the appropriate transport context based on transport type.\n        Returns:\n            Tuple of (transport_context, http_client).\n            http_client is only set for HTTP transport and needs cleanup.\n        \"\"\"\n        http_client: httpx.AsyncClient | None = None\n        if self.transport_type == MCPTransport.stdio:\n            if not self.stdio_config:\n                raise ValueError(\"stdio_config is required for stdio transport\")\n            server_params: Final = StdioServerParameters(\n                command=self.stdio_config.get(\"command\", \"\"),\n                args=self.stdio_config.get(\"args\", []),\n                env=self._get_safe_stdio_env(self.stdio_config.get(\"env\")),\n            )\n            return stdio_client(server_params), None\n        if self.transport_type == MCPTransport.sse:\n            headers = self._get_auth_headers()\n            httpx_client_factory = self._create_httpx_client_factory()\n            return (\n                sse_client(\n                    url=self.server_url,\n                    timeout=self.timeout,\n                    headers=headers,\n                    httpx_client_factory=httpx_client_factory,\n                ),\n                None,\n            )","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/experimental_mcp_client/client.py#L251-L287","documentation":"The MCP client picks a transport by transport_type. When transport_type is stdio, it must build StdioServerParameters from a stdio_config dict (command, args, env); if stdio_config is missing or empty the client cannot spawn the server process and raises ValueError immediately.","triggerScenarios":"Registering an MCP server with transport_type='stdio' (or omitting transport_type so it defaults to stdio) but only supplying url/ without any stdio_config block; typoing the key as stdio or stdin_config; passing stdio_config: {} which is falsy.","commonSituations":"Converting an HTTP MCP server entry to stdio and forgetting to add the command block; YAML config indentation putting stdio_config under the wrong key; assuming url alone works for every transport type.","solutions":["Add a stdio_config block with at least command (and usually args): stdio_config: {command: 'npx', args: ['-y', '@modelcontextprotocol/server-everything']}","Verify transport_type matches the config: use transport_type='http'/'sse' with url for remote servers, 'stdio' with stdio_config for local processes","Check YAML indentation so stdio_config is a sibling of transport_type under the server entry, not nested elsewhere","Confirm stdio_config is non-empty after litellm's config loading (os.environ/ prefixed values must resolve to real strings)"],"exampleFix":"# before\nmcp_servers:\n  my_server:\n    transport_type: stdio\n    url: http://localhost:8000/mcp\n\n# after\nmcp_servers:\n  my_server:\n    transport_type: stdio\n    stdio_config:\n      command: npx\n      args: [\"-y\", \"@modelcontextprotocol/server-everything\"]","handlingStrategy":"validation","validationCode":"def validate_mcp_server_entry(server: dict) -> None:\n    if server.get(\"transport_type\", \"stdio\") == \"stdio\":\n        sc = server.get(\"stdio_config\")\n        if not sc or not sc.get(\"command\"):\n            raise ValueError(\"stdio servers need stdio_config.command\")\n    else:\n        if not server.get(\"url\"):\n            raise ValueError(\"http/sse servers need url\")","typeGuard":"def is_valid_stdio_config(cfg: object) -> bool:\n    return (\n        isinstance(cfg, dict)\n        and isinstance(cfg.get(\"command\"), str)\n        and cfg[\"command\"].strip() != \"\"\n        and isinstance(cfg.get(\"args\", []), list)\n    )","tryCatchPattern":null,"preventionTips":["Schema-validate litellm config (pydantic) before proxy start","Integration-test MCP server entries at deploy time"],"tags":["mcp","stdio","configuration","validation"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}