{"record":{"id":"f48d333fb6d70311","repo":"langflow-ai/langflow","slug":"unsupported-client","errorCode":null,"errorMessage":"Unsupported client","messagePattern":"Unsupported client","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/backend/base/langflow/api/v1/mcp_projects.py","lineNumber":1291,"sourceCode":"\n                    if not Path(\"/mnt/c\").exists():\n                        msg = \"Windows C: drive not mounted at /mnt/c in WSL\"\n                        raise ValueError(msg)\n\n                    msg = \"Could not find valid Windows user directory in WSL\"\n                    raise ValueError(msg)\n                except (OSError, CalledProcessError) as e:\n                    await logger.awarning(\"Failed to determine Windows user path in WSL: %s\", str(e))\n                    msg = f\"Could not determine Windows Claude config path in WSL: {e!s}\"\n                    raise ValueError(msg) from e\n            # Regular Windows\n            return Path(os.environ[\"APPDATA\"]) / \"Claude\" / \"claude_desktop_config.json\"\n\n        msg = \"Unsupported operating system for Claude configuration\"\n        raise ValueError(msg)\n\n    msg = \"Unsupported client\"\n    raise ValueError(msg)\n\n\ndef remove_server_by_urls(config_data: dict, urls: Sequence[str] | str) -> tuple[dict, list[str]]:\n    \"\"\"Remove any MCP servers that use one of the specified URLs from config data.\n\n    Returns:\n        tuple: (updated_config, list_of_removed_server_names)\n    \"\"\"\n    normalized_urls = _normalize_url_list(urls)\n    if not normalized_urls:\n        return config_data, []\n\n    if \"mcpServers\" not in config_data:\n        return config_data, []\n\n    removed_servers: list[str] = []\n    servers_to_remove: list[str] = []\n","sourceCodeStart":1273,"sourceCodeEnd":1309,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/mcp_projects.py#L1273-L1309","documentation":"Raised by get_config_path() in Langflow's MCP projects API when the client argument does not match one of the three supported names. The function only handles client.lower() == 'cursor', 'windsurf', or 'claude'; any other string (including typos, new clients, or different casing/whitespace) falls through to the terminal 'Unsupported client' ValueError at mcp_projects.py:1291.","triggerScenarios":"Calling get_config_path('Claude Code'), 'vscode', 'cline', 'codex', or any client name other than exactly cursor/windsurf/claude (case-insensitive). Also triggered by strings with leading/trailing whitespace (' claude') or trailing newlines, since the comparison uses client.lower() without stripping.","commonSituations":"Frontend or API consumers passing a display name ('Claude Desktop') instead of the machine name 'claude'; adding support for a new MCP client in a fork without extending this function; user-supplied client strings from a form or config file that include whitespace or different casing.","solutions":["Pass one of the supported machine names exactly: 'cursor', 'windsurf', or 'claude' (any casing, but no extra whitespace).","Normalize user input before calling: client.strip().lower() and reject values outside {'cursor','windsurf','claude'} with a clear validation message.","To support a new client, extend get_config_path with a new branch returning its config path and update the client list used by the availability-check endpoints so it stays consistent."],"exampleFix":"# before\nclient = request_client_name  # e.g. 'Claude Desktop ' -> raises\npath = await get_config_path(client)\n\n# after\nSUPPORTED_CLIENTS = {\"cursor\", \"windsurf\", \"claude\"}\nclient = request_client_name.strip().lower()\nif client not in SUPPORTED_CLIENTS:\n    msg = f\"Unsupported client {request_client_name!r}; expected one of {sorted(SUPPORTED_CLIENTS)}\"\n    raise ValueError(msg)\npath = await get_config_path(client)","handlingStrategy":"type-guard","validationCode":"SUPPORTED_MCP_CLIENTS = {\"cursor\", \"windsurf\", \"claude\"}\n\ndef is_supported_client(client: str) -> bool:\n    return isinstance(client, str) and client.strip().lower() in SUPPORTED_MCP_CLIENTS\n\n# before calling:\nif not is_supported_client(client):\n    raise HTTPException(400, f\"Unsupported client; choose from {sorted(SUPPORTED_MCP_CLIENTS)}\")","typeGuard":"from typing import Literal\n\nClientName = Literal[\"cursor\", \"windsurf\", \"claude\"]\n\ndef is_client_name(value: str) -> bool:\n    \"\"\"Narrow an arbitrary string to the supported client union.\"\"\"\n    return isinstance(value, str) and value.strip().lower() in {\"cursor\", \"windsurf\", \"claude\"}","tryCatchPattern":"try:\n    path = await get_config_path(client)\nexcept ValueError as e:\n    if \"Unsupported client\" in str(e):\n        raise HTTPException(status_code=400, detail=str(e)) from e\n    raise","preventionTips":["Normalize client strings (strip + lower) at the API boundary before they reach get_config_path","Use a Literal/enum type for the client parameter in typed callers so invalid names fail at type-check time","Return the supported client list from your validation error so callers can self-correct"],"tags":["mcp","input-validation","client-config","api"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}