feat(shadcn): add mcp support for codex (#8348)

This commit is contained in:
shadcn
2025-10-05 14:05:14 +04:00
committed by GitHub
parent b19e9cadb2
commit e96f9edf02
4 changed files with 129 additions and 4 deletions

View File

@@ -0,0 +1,5 @@
---
"shadcn": minor
---
add mcp support for codex

View File

@@ -28,6 +28,7 @@ Select your MCP client and follow the instructions to configure the shadcn MCP s
<TabsTrigger value="claude">Claude Code</TabsTrigger>
<TabsTrigger value="cursor">Cursor</TabsTrigger>
<TabsTrigger value="vscode">VS Code</TabsTrigger>
<TabsTrigger value="codex">Codex</TabsTrigger>
</TabsList>
<TabsContent value="claude" className="mt-4">
**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
</TabsContent>
<TabsContent value="codex" className="mt-4">
<Callout className="mt-0">
**Note:** The `shadcn` CLI cannot automatically update `~/.codex/config.toml`.
You'll need to add the configuration manually for Codex.
</Callout>
**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
</TabsContent>
</Tabs>
---
@@ -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
<Callout>
**Note:** The `shadcn` CLI cannot automatically update `~/.codex/config.toml`.
You'll need to add the configuration manually.
</Callout>
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

View File

@@ -26,6 +26,7 @@ Ask your registry consumers to configure your registry in their `components.json
<TabsTrigger value="claude">Claude Code</TabsTrigger>
<TabsTrigger value="cursor">Cursor</TabsTrigger>
<TabsTrigger value="vscode">VS Code</TabsTrigger>
<TabsTrigger value="codex">Codex</TabsTrigger>
</TabsList>
<TabsContent value="claude" className="mt-4">
**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
</TabsContent>
<TabsContent value="codex" className="mt-4">
**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
</TabsContent>
</Tabs>
You can read more about the MCP server in the [MCP documentation](/docs/mcp).

View File

@@ -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<typeof mcpInitOptionsSchema>) {
}
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<typeof mcpInitOptionsSchema>) {
{ arrayMerge: overwriteMerge }
)
const dir = path.dirname(configPath)
await fsExtra.ensureDir(dir)
await fs.writeFile(
configPath,
JSON.stringify(mergedConfig, null, 2) + "\n",