{"record":{"id":"01f0a8dce4be6074","repo":"shadcn-ui/ui","slug":"unknown-client-client-available-clients-cl","errorCode":null,"errorMessage":"Unknown client: ${client}. Available clients: ${CLIENTS.map((c) => c.name).join(\", \")}","messagePattern":"Unknown client: (.+?)\\. Available clients: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/shadcn/src/commands/mcp.ts","lineNumber":234,"sourceCode":"        installSpinner.succeed(\"Installing dependencies.\")\n      }\n\n      logger.break()\n      logger.success(`Configuration saved to ${configPath}.`)\n      logger.break()\n    } catch (error) {\n      handleError(error)\n    }\n  })\n\nconst overwriteMerge = (_: any[], sourceArray: any[]) => sourceArray\n\nasync function runMcpInit(options: z.infer<typeof mcpInitOptionsSchema>) {\n  const { client, cwd } = options\n\n  const clientInfo = CLIENTS.find((c) => c.name === client)\n  if (!clientInfo) {\n    throw new Error(\n      `Unknown client: ${client}. Available clients: ${CLIENTS.map(\n        (c) => c.name\n      ).join(\", \")}`\n    )\n  }\n\n  const configPath = path.join(cwd, clientInfo.configPath)\n  const dir = path.dirname(configPath)\n  await fsExtra.ensureDir(dir)\n\n  // Handle JSON format.\n  let existingConfig = {}\n  try {\n    const content = await fs.readFile(configPath, \"utf-8\")\n    existingConfig = JSON.parse(content)\n  } catch {}\n\n  const mergedConfig = deepmerge(","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/shadcn-ui/ui/blob/efac5987074af84ece57c367c6dd83387b967022/packages/shadcn/src/commands/mcp.ts#L216-L252","documentation":"runMcpInit throws when --client doesn't match any entry in the CLIENTS array (claude, cursor, vscode, codex, opencode). The value selects both the config file path and the config format (JSON vs TOML).","triggerScenarios":"Calling `shadcn mcp init --client <name>` with <name> outside the supported list. The commander option / zod enum (mcpInitOptionsSchema) normally rejects unknown values first, so this fires on programmatic API use or a bypassed schema.","commonSituations":"Typo (e.g., 'claude-code' instead of 'claude', 'vs-code' instead of 'vscode'), a newer client this shadcn version doesn't yet support, schema bypass via direct runMcpInit call.","solutions":["Use exactly one of: claude, cursor, vscode, codex, opencode.","Omit --client to choose interactively from the prompt.","Upgrade shadcn to a version that ships support for your client."],"exampleFix":"// before\nshadcn mcp init --client claude-code\n// after\nshadcn mcp init --client claude","handlingStrategy":"validation","validationCode":"const SUPPORTED_CLIENTS = [\"claude\", \"cursor\", \"vscode\", \"codex\", \"opencode\"] as const\n\nfunction assertSupportedClient(client: string) {\n  if (!SUPPORTED_CLIENTS.includes(client as never)) {\n    throw new Error(`client must be one of: ${SUPPORTED_CLIENTS.join(\", \")}`)\n  }\n}","typeGuard":"const SUPPORTED_CLIENTS = [\"claude\", \"cursor\", \"vscode\", \"codex\", \"opencode\"] as const\ntype SupportedClient = typeof SUPPORTED_CLIENTS[number]\n\nfunction isSupportedClient(c: unknown): c is SupportedClient {\n  return typeof c === \"string\" && (SUPPORTED_CLIENTS as readonly string[]).includes(c)\n}","tryCatchPattern":null,"preventionTips":["Rely on the zod enum in mcpInitOptionsSchema to reject unknown clients at the boundary.","Upgrade shadcn before adopting a newly released MCP client."],"tags":["mcp","validation","config","cli"],"backgroundTag":null,"analyzedSha":"efac5987074af84ece57c367c6dd83387b967022","analyzedAt":"2026-08-12T05:00:50.218Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}