Skip to content

Commit 8b17212

Browse files
authored
feat(cli): add mcp support for codex (#1435)
* feat(cli): add mcp support for codex from shadcn * chore: update deps
1 parent 356f651 commit 8b17212

File tree

3 files changed

+299
-201
lines changed

3 files changed

+299
-201
lines changed

packages/cli/package.json

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@
6464
"test:ui": "vitest --ui"
6565
},
6666
"dependencies": {
67-
"@dotenvx/dotenvx": "^1.49.0",
68-
"@modelcontextprotocol/sdk": "^1.18.0",
67+
"@dotenvx/dotenvx": "^1.51.0",
68+
"@modelcontextprotocol/sdk": "^1.19.1",
6969
"@unovue/detypes": "^0.8.5",
7070
"@vue/compiler-sfc": "^3.5",
7171
"c12": "^3.3.0",
@@ -74,20 +74,20 @@
7474
"dedent": "^1.7.0",
7575
"deepmerge": "^4.3.1",
7676
"diff": "^8.0.2",
77-
"fs-extra": "^11.3.1",
77+
"fs-extra": "^11.3.2",
7878
"fuzzysort": "^3.1.0",
7979
"get-tsconfig": "^4.10.1",
8080
"magic-string": "^0.30.19",
81-
"nypm": "^0.6.1",
81+
"nypm": "^0.6.2",
8282
"ofetch": "^1.4.1",
83-
"ora": "^8.2.0",
83+
"ora": "^9.0.0",
8484
"pathe": "catalog:",
8585
"postcss": "^8.5.6",
8686
"prompts": "^2.4.2",
8787
"reka-ui": "catalog:",
8888
"semver": "^7.7.2",
8989
"stringify-object": "^6.0.0",
90-
"tailwindcss": "^4.1.12",
90+
"tailwindcss": "^4.1.14",
9191
"tinyexec": "^1.0.1",
9292
"tinyglobby": "catalog:",
9393
"ts-morph": "^27.0.0",
@@ -97,15 +97,14 @@
9797
"zod-to-json-schema": "^3.24.6"
9898
},
9999
"devDependencies": {
100-
"@types/diff": "^8.0.0",
101100
"@types/fs-extra": "^11.0.4",
102101
"@types/node": "^22.16.0",
103102
"@types/prompts": "^2.4.9",
104103
"@types/semver": "^7.7.1",
105104
"@types/stringify-object": "^4.0.5",
106-
"msw": "^2.11.2",
107-
"tsdown": "^0.15.1",
108-
"type-fest": "^4.41.0",
105+
"msw": "^2.11.3",
106+
"tsdown": "^0.15.6",
107+
"type-fest": "^5.0.1",
109108
"typescript": "catalog:"
110109
}
111110
}

packages/cli/src/commands/mcp.ts

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { server } from '@/src/mcp'
1212
import { loadEnvFiles } from '@/src/utils/env-loader'
1313
import { getConfig } from '@/src/utils/get-config'
1414
import { handleError } from '@/src/utils/handle-error'
15+
import { highlighter } from '@/src/utils/highlighter'
1516
import { logger } from '@/src/utils/logger'
1617
import { spinner } from '@/src/utils/spinner'
1718
import { updateDependencies } from '@/src/utils/updaters/update-dependencies'
@@ -58,6 +59,15 @@ const CLIENTS = [
5859
},
5960
},
6061
},
62+
{
63+
name: 'codex',
64+
label: 'Codex',
65+
configPath: '.codex/config.toml',
66+
config: `[mcp_servers.shadcn_vue]
67+
command = "npx"
68+
args = ["shadcn-vue@${SHADCN_MCP_VERSION}", "mcp"]
69+
`,
70+
},
6171
] as const
6272

6373
const DEPENDENCIES = [`shadcn-vue@${SHADCN_MCP_VERSION}`]
@@ -83,7 +93,7 @@ export const mcp = new Command()
8393
})
8494

8595
const mcpInitOptionsSchema = z.object({
86-
client: z.enum(['claude', 'cursor', 'vscode']),
96+
client: z.enum(['claude', 'cursor', 'vscode', 'codex']),
8797
cwd: z.string(),
8898
})
8999

@@ -126,11 +136,55 @@ mcp
126136
cwd,
127137
})
128138

139+
const config = await getConfig(options.cwd)
140+
141+
if (options.client === 'codex') {
142+
if (config) {
143+
await updateDependencies([], DEPENDENCIES, config, {
144+
silent: false,
145+
})
146+
}
147+
else {
148+
const packageManager = await detectPackageManager(options.cwd)
149+
const installCommand = packageManager?.name === 'npm' ? 'install' : 'add'
150+
const devFlag = packageManager?.name === 'npm' ? '--save-dev' : '-D'
151+
152+
const installSpinner = spinner('Installing dependencies...').start()
153+
await x(
154+
packageManager?.name || 'npm',
155+
[installCommand, devFlag, ...DEPENDENCIES],
156+
{
157+
nodeOptions: {
158+
cwd: options.cwd,
159+
},
160+
},
161+
)
162+
installSpinner.succeed('Installing dependencies.')
163+
}
164+
165+
logger.break()
166+
logger.log('To configure the shadcn-vue MCP server in Codex:')
167+
logger.break()
168+
logger.log(
169+
`1. Open or create the file ${highlighter.info(
170+
'~/.codex/config.toml',
171+
)}`,
172+
)
173+
logger.log('2. Add the following configuration:')
174+
logger.log()
175+
logger.info(`[mcp_servers.shadcn_vue]
176+
command = "npx"
177+
args = ["shadcn-vue@${SHADCN_MCP_VERSION}", "mcp"]`)
178+
logger.break()
179+
logger.info('3. Restart Codex to load the MCP server')
180+
logger.break()
181+
process.exit(0)
182+
}
183+
129184
const configSpinner = spinner('Configuring MCP server...').start()
130185
const configPath = await runMcpInit(options)
131186
configSpinner.succeed('Configuring MCP server.')
132187

133-
const config = await getConfig(options.cwd)
134188
if (config) {
135189
await updateDependencies([], DEPENDENCIES, config, {
136190
silent: false,
@@ -178,6 +232,8 @@ async function runMcpInit(options: z.infer<typeof mcpInitOptionsSchema>) {
178232
}
179233

180234
const configPath = path.join(cwd, clientInfo.configPath)
235+
const dir = path.dirname(configPath)
236+
await fsExtra.ensureDir(dir)
181237

182238
let existingConfig = {}
183239
try {
@@ -192,8 +248,6 @@ async function runMcpInit(options: z.infer<typeof mcpInitOptionsSchema>) {
192248
{ arrayMerge: overwriteMerge },
193249
)
194250

195-
const dir = path.dirname(configPath)
196-
await fsExtra.ensureDir(dir)
197251
await fs.writeFile(
198252
configPath,
199253
`${JSON.stringify(mergedConfig, null, 2)}\n`,

0 commit comments

Comments
 (0)