From e96f9edf027c8f97dc565b6e6c2fbd6f258bfa1e Mon Sep 17 00:00:00 2001 From: shadcn Date: Sun, 5 Oct 2025 14:05:14 +0400 Subject: [PATCH] feat(shadcn): add mcp support for codex (#8348) --- .changeset/smart-items-open.md | 5 +++ apps/v4/content/docs/(root)/mcp.mdx | 43 +++++++++++++++++++ apps/v4/content/docs/registry/mcp.mdx | 25 +++++++++++ packages/shadcn/src/commands/mcp.ts | 60 +++++++++++++++++++++++++-- 4 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 .changeset/smart-items-open.md diff --git a/.changeset/smart-items-open.md b/.changeset/smart-items-open.md new file mode 100644 index 000000000..8a19135fd --- /dev/null +++ b/.changeset/smart-items-open.md @@ -0,0 +1,5 @@ +--- +"shadcn": minor +--- + +add mcp support for codex diff --git a/apps/v4/content/docs/(root)/mcp.mdx b/apps/v4/content/docs/(root)/mcp.mdx index 017fc8cd7..4db642071 100644 --- a/apps/v4/content/docs/(root)/mcp.mdx +++ b/apps/v4/content/docs/(root)/mcp.mdx @@ -28,6 +28,7 @@ Select your MCP client and follow the instructions to configure the shadcn MCP s Claude Code Cursor VS Code + Codex **Run the following command** in your project: @@ -69,6 +70,31 @@ Select your MCP client and follow the instructions to configure the shadcn MCP s - Create a contact form using components from the shadcn registry + + + + **Note:** The `shadcn` CLI cannot automatically update `~/.codex/config.toml`. + You'll need to add the configuration manually for Codex. + + + **Run the following command** in your project: + ```bash + npx shadcn@latest mcp init --client codex + ``` + + **Then, add the following configuration** to `~/.codex/config.toml`: + ```toml + [mcp_servers.shadcn] + command = "npx" + args = ["shadcn@latest", "mcp"] + ``` + + **Restart Codex** and try the following prompts: + - Show me all available components in the shadcn registry + - Add the button, dialog and card components to my project + - Create a contact form using components from the shadcn registry + + --- @@ -169,6 +195,23 @@ After adding the configuration, open `.vscode/mcp.json` and click **Start** next See the [VS Code MCP documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) for more details. +### Codex + + + **Note:** The `shadcn` CLI cannot automatically update `~/.codex/config.toml`. + You'll need to add the configuration manually. + + +To configure MCP in Codex, add the shadcn server to `~/.codex/config.toml`: + +```toml title="~/.codex/config.toml" showLineNumbers +[mcp_servers.shadcn] +command = "npx" +args = ["shadcn@latest", "mcp"] +``` + +After adding the configuration, restart Codex to load the MCP server. + --- ## Configuring Registries diff --git a/apps/v4/content/docs/registry/mcp.mdx b/apps/v4/content/docs/registry/mcp.mdx index 0a3c40dee..850a6d68b 100644 --- a/apps/v4/content/docs/registry/mcp.mdx +++ b/apps/v4/content/docs/registry/mcp.mdx @@ -26,6 +26,7 @@ Ask your registry consumers to configure your registry in their `components.json Claude Code Cursor VS Code + Codex **Configure your registry** in your `components.json` file: @@ -93,6 +94,30 @@ Ask your registry consumers to configure your registry in their `components.json - Create a landing page using items from the acme registry + + + **Configure your registry** in your `components.json` file: + + ```json title="components.json" showLineNumbers + { + "registries": { + "@acme": "https://acme.com/r/{name}.json" + } + } + ``` + + **Add the following configuration** to `~/.codex/config.toml`: + ```toml + [mcp_servers.shadcn] + command = "npx" + args = ["shadcn@latest", "mcp"] + ``` + + **Restart Codex** and try the following prompts: + - Show me the components in the acme registry + - Create a landing page using items from the acme registry + + You can read more about the MCP server in the [MCP documentation](/docs/mcp). diff --git a/packages/shadcn/src/commands/mcp.ts b/packages/shadcn/src/commands/mcp.ts index 230794fc5..7c576e4e3 100644 --- a/packages/shadcn/src/commands/mcp.ts +++ b/packages/shadcn/src/commands/mcp.ts @@ -5,6 +5,7 @@ import { loadEnvFiles } from "@/src/utils/env-loader" import { getConfig } from "@/src/utils/get-config" import { getPackageManager } from "@/src/utils/get-package-manager" import { handleError } from "@/src/utils/handle-error" +import { highlighter } from "@/src/utils/highlighter" import { logger } from "@/src/utils/logger" import { spinner } from "@/src/utils/spinner" import { updateDependencies } from "@/src/utils/updaters/update-dependencies" @@ -58,6 +59,15 @@ const CLIENTS = [ }, }, }, + { + name: "codex", + label: "Codex", + configPath: ".codex/config.toml", + config: `[mcp_servers.shadcn] +command = "npx" +args = ["shadcn@${SHADCN_MCP_VERSION}", "mcp"] +`, + }, ] as const const DEPENDENCIES = [`shadcn@${SHADCN_MCP_VERSION}`] @@ -82,7 +92,7 @@ export const mcp = new Command() }) const mcpInitOptionsSchema = z.object({ - client: z.enum(["claude", "cursor", "vscode"]), + client: z.enum(["claude", "cursor", "vscode", "codex"]), cwd: z.string(), }) @@ -125,11 +135,52 @@ mcp cwd, }) + const config = await getConfig(options.cwd) + + if (options.client === "codex") { + if (config) { + await updateDependencies([], DEPENDENCIES, config, { + silent: false, + }) + } else { + const packageManager = await getPackageManager(options.cwd) + const installCommand = packageManager === "npm" ? "install" : "add" + const devFlag = packageManager === "npm" ? "--save-dev" : "-D" + + const installSpinner = spinner("Installing dependencies...").start() + await execa( + packageManager, + [installCommand, devFlag, ...DEPENDENCIES], + { + cwd: options.cwd, + } + ) + installSpinner.succeed("Installing dependencies.") + } + + logger.break() + logger.log("To configure the shadcn MCP server in Codex:") + logger.break() + logger.log( + `1. Open or create the file ${highlighter.info( + "~/.codex/config.toml" + )}` + ) + logger.log("2. Add the following configuration:") + logger.log() + logger.info(`[mcp_servers.shadcn] +command = "npx" +args = ["shadcn@${SHADCN_MCP_VERSION}", "mcp"]`) + logger.break() + logger.info("3. Restart Codex to load the MCP server") + logger.break() + process.exit(0) + } + const configSpinner = spinner("Configuring MCP server...").start() const configPath = await runMcpInit(options) configSpinner.succeed("Configuring MCP server.") - const config = await getConfig(options.cwd) if (config) { await updateDependencies([], DEPENDENCIES, config, { silent: false, @@ -173,7 +224,10 @@ async function runMcpInit(options: z.infer) { } const configPath = path.join(cwd, clientInfo.configPath) + const dir = path.dirname(configPath) + await fsExtra.ensureDir(dir) + // Handle JSON format. let existingConfig = {} try { const content = await fs.readFile(configPath, "utf-8") @@ -186,8 +240,6 @@ async function runMcpInit(options: z.infer) { { arrayMerge: overwriteMerge } ) - const dir = path.dirname(configPath) - await fsExtra.ensureDir(dir) await fs.writeFile( configPath, JSON.stringify(mergedConfig, null, 2) + "\n",