Skip to content

Commit 0f98457

Browse files
authored
Merge pull request #27 from Jpisnice/fixes
Fixes
2 parents 3f4c44b + eef5a06 commit 0f98457

File tree

13 files changed

+458
-492
lines changed

13 files changed

+458
-492
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"claude",
3434
"copilot"
3535
],
36-
"author": "Janardhan Pollle <[email protected]>",
36+
"author": "Janardhan Pollle",
3737
"license": "MIT",
3838
"repository": {
3939
"type": "git",

src/cli/args.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export type CliOptions = {
2+
githubApiKey: string | null
3+
}
4+
5+
export function parseArgs(argv = process.argv.slice(2)): CliOptions {
6+
const githubApiKeyIndex = argv.findIndex(
7+
(arg) => arg === "--github-api-key" || arg === "-g"
8+
)
9+
let githubApiKey: string | null = null
10+
11+
if (githubApiKeyIndex !== -1 && argv[githubApiKeyIndex + 1]) {
12+
githubApiKey = argv[githubApiKeyIndex + 1]
13+
} else if (process.env.GITHUB_PERSONAL_ACCESS_TOKEN) {
14+
githubApiKey = process.env.GITHUB_PERSONAL_ACCESS_TOKEN
15+
}
16+
17+
return { githubApiKey }
18+
}

src/index.ts

Lines changed: 4 additions & 338 deletions
Original file line numberDiff line numberDiff line change
@@ -1,342 +1,8 @@
11
#!/usr/bin/env node
2-
/**
3-
* Shadcn UI v4 MCP Server
4-
*
5-
* A Model Context Protocol server for shadcn/ui v4 components.
6-
* Provides AI assistants with access to component source code, demos, blocks, and metadata.
7-
*
8-
* Usage:
9-
* npx shadcn-ui-mcp-server
10-
* npx shadcn-ui-mcp-server --github-api-key YOUR_TOKEN
11-
* npx shadcn-ui-mcp-server -g YOUR_TOKEN
12-
*/
13-
import { Server } from "@modelcontextprotocol/sdk/server/index.js"
14-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
15-
import { setupHandlers } from "./handler.js"
16-
import {
17-
validateFrameworkSelection,
18-
getAxiosImplementation,
19-
} from "./utils/framework.js"
20-
import { z } from "zod"
21-
import { toolHandlers, toolSchemas } from "./tools/index.js"
22-
import { logError, logInfo, logWarning } from "./utils/logger.js"
2+
import { start } from "./server/index.js"
3+
import { logError } from "./utils/logger.js"
234

24-
/**
25-
* Parse command line arguments
26-
*/
27-
async function parseArgs() {
28-
const args = process.argv.slice(2)
29-
30-
// Help flag
31-
if (args.includes("--help") || args.includes("-h")) {
32-
console.log(`
33-
Shadcn UI v4 MCP Server
34-
35-
Usage:
36-
npx shadcn-ui-mcp-server [options]
37-
38-
Options:
39-
--github-api-key, -g <token> GitHub Personal Access Token for API access
40-
--framework, -f <framework> Framework to use: 'react' or 'svelte' (default: react)
41-
--help, -h Show this help message
42-
--version, -v Show version information
43-
44-
Examples:
45-
npx shadcn-ui-mcp-server
46-
npx shadcn-ui-mcp-server --github-api-key ghp_your_token_here
47-
npx shadcn-ui-mcp-server -g ghp_your_token_here
48-
npx shadcn-ui-mcp-server --framework svelte
49-
npx shadcn-ui-mcp-server -f react
50-
51-
Environment Variables:
52-
GITHUB_PERSONAL_ACCESS_TOKEN Alternative way to provide GitHub token
53-
FRAMEWORK Framework to use: 'react' or 'svelte' or 'vue' (default: react)
54-
LOG_LEVEL Log level (debug, info, warn, error) - default: info
55-
56-
For more information, visit: https://github.com/Jpisnice/shadcn-ui-mcp-server
57-
`)
58-
process.exit(0)
59-
}
60-
61-
// Version flag
62-
if (args.includes("--version") || args.includes("-v")) {
63-
// Read version from package.json
64-
try {
65-
const fs = await import("fs")
66-
const path = await import("path")
67-
const { fileURLToPath } = await import("url")
68-
69-
const __filename = fileURLToPath(import.meta.url)
70-
const __dirname = path.dirname(__filename)
71-
const packagePath = path.join(__dirname, "..", "package.json")
72-
73-
const packageContent = fs.readFileSync(packagePath, "utf8")
74-
const packageJson = JSON.parse(packageContent)
75-
console.log(`shadcn-ui-mcp-server v${packageJson.version}`)
76-
} catch (error) {
77-
console.log("shadcn-ui-mcp-server v1.0.2")
78-
}
79-
process.exit(0)
80-
}
81-
82-
// GitHub API key
83-
const githubApiKeyIndex = args.findIndex(
84-
(arg) => arg === "--github-api-key" || arg === "-g"
85-
)
86-
let githubApiKey = null
87-
88-
if (githubApiKeyIndex !== -1 && args[githubApiKeyIndex + 1]) {
89-
githubApiKey = args[githubApiKeyIndex + 1]
90-
} else if (process.env.GITHUB_PERSONAL_ACCESS_TOKEN) {
91-
githubApiKey = process.env.GITHUB_PERSONAL_ACCESS_TOKEN
92-
}
93-
94-
return { githubApiKey }
95-
}
96-
97-
/**
98-
* Main function to start the MCP server
99-
*/
100-
async function main() {
101-
try {
102-
logInfo("Starting Shadcn UI v4 MCP Server...")
103-
104-
const { githubApiKey } = await parseArgs()
105-
106-
// Validate and log framework selection
107-
validateFrameworkSelection()
108-
109-
// Get the appropriate axios implementation based on framework
110-
const axios = await getAxiosImplementation()
111-
112-
// Configure GitHub API key if provided
113-
if (githubApiKey) {
114-
axios.setGitHubApiKey(githubApiKey)
115-
logInfo("GitHub API configured with token")
116-
} else {
117-
logWarning(
118-
"No GitHub API key provided. Rate limited to 60 requests/hour."
119-
)
120-
}
121-
122-
// Initialize the MCP server with metadata and capabilities
123-
// Following MCP SDK 1.16.0 best practices
124-
const server = new Server(
125-
{
126-
name: "shadcn-ui-mcp-server",
127-
version: "1.0.2",
128-
},
129-
{
130-
capabilities: {
131-
resources: {
132-
get_components: {
133-
description:
134-
"List of available shadcn/ui components that can be used in the project",
135-
uri: "resource:get_components",
136-
contentType: "text/plain",
137-
},
138-
get_install_script_for_component: {
139-
description:
140-
"Generate installation script for a specific shadcn/ui component based on package manager",
141-
uriTemplate:
142-
"resource-template:get_install_script_for_component?packageManager={packageManager}&component={component}",
143-
contentType: "text/plain",
144-
},
145-
get_installation_guide: {
146-
description:
147-
"Get the installation guide for shadcn/ui based on build tool and package manager",
148-
uriTemplate:
149-
"resource-template:get_installation_guide?buildTool={buildTool}&packageManager={packageManager}",
150-
contentType: "text/plain",
151-
},
152-
},
153-
prompts: {
154-
component_usage: {
155-
description: "Get usage examples for a specific component",
156-
arguments: {
157-
componentName: {
158-
type: "string",
159-
description: "Name of the component to get usage for",
160-
},
161-
},
162-
},
163-
component_search: {
164-
description: "Search for components by name or description",
165-
arguments: {
166-
query: {
167-
type: "string",
168-
description: "Search query",
169-
},
170-
},
171-
},
172-
component_comparison: {
173-
description: "Compare two components side by side",
174-
arguments: {
175-
component1: {
176-
type: "string",
177-
description: "First component name",
178-
},
179-
component2: {
180-
type: "string",
181-
description: "Second component name",
182-
},
183-
},
184-
},
185-
component_recommendation: {
186-
description: "Get component recommendations based on use case",
187-
arguments: {
188-
useCase: {
189-
type: "string",
190-
description: "Use case description",
191-
},
192-
},
193-
},
194-
component_tutorial: {
195-
description: "Get a step-by-step tutorial for using a component",
196-
arguments: {
197-
componentName: {
198-
type: "string",
199-
description: "Name of the component for tutorial",
200-
},
201-
},
202-
},
203-
},
204-
tools: {
205-
get_component: {
206-
description:
207-
"Get the source code for a specific shadcn/ui v4 component",
208-
inputSchema: {
209-
type: "object",
210-
properties: {
211-
componentName: {
212-
type: "string",
213-
description:
214-
'Name of the shadcn/ui component (e.g., "accordion", "button")',
215-
},
216-
},
217-
required: ["componentName"],
218-
},
219-
},
220-
get_component_demo: {
221-
description:
222-
"Get demo code illustrating how a shadcn/ui v4 component should be used",
223-
inputSchema: {
224-
type: "object",
225-
properties: {
226-
componentName: {
227-
type: "string",
228-
description:
229-
'Name of the shadcn/ui component (e.g., "accordion", "button")',
230-
},
231-
},
232-
required: ["componentName"],
233-
},
234-
},
235-
list_components: {
236-
description: "Get all available shadcn/ui v4 components",
237-
inputSchema: {
238-
type: "object",
239-
properties: {},
240-
},
241-
},
242-
get_component_metadata: {
243-
description: "Get metadata for a specific shadcn/ui v4 component",
244-
inputSchema: {
245-
type: "object",
246-
properties: {
247-
componentName: {
248-
type: "string",
249-
description:
250-
'Name of the shadcn/ui component (e.g., "accordion", "button")',
251-
},
252-
},
253-
required: ["componentName"],
254-
},
255-
},
256-
get_directory_structure: {
257-
description:
258-
"Get the directory structure of the shadcn-ui v4 repository",
259-
inputSchema: {
260-
type: "object",
261-
properties: {
262-
path: {
263-
type: "string",
264-
description:
265-
"Path within the repository (default: v4 registry)",
266-
},
267-
owner: {
268-
type: "string",
269-
description: 'Repository owner (default: "shadcn-ui")',
270-
},
271-
repo: {
272-
type: "string",
273-
description: 'Repository name (default: "ui")',
274-
},
275-
branch: {
276-
type: "string",
277-
description: 'Branch name (default: "main")',
278-
},
279-
},
280-
},
281-
},
282-
get_block: {
283-
description:
284-
"Get source code for a specific shadcn/ui v4 block (e.g., calendar-01, dashboard-01)",
285-
inputSchema: {
286-
type: "object",
287-
properties: {
288-
blockName: {
289-
type: "string",
290-
description:
291-
'Name of the block (e.g., "calendar-01", "dashboard-01", "login-02")',
292-
},
293-
includeComponents: {
294-
type: "boolean",
295-
description:
296-
"Whether to include component files for complex blocks (default: true)",
297-
},
298-
},
299-
required: ["blockName"],
300-
},
301-
},
302-
list_blocks: {
303-
description:
304-
"Get all available shadcn/ui v4 blocks with categorization",
305-
inputSchema: {
306-
type: "object",
307-
properties: {
308-
category: {
309-
type: "string",
310-
description:
311-
"Filter by category (calendar, dashboard, login, sidebar, products)",
312-
},
313-
},
314-
},
315-
},
316-
},
317-
},
318-
}
319-
)
320-
321-
// Set up request handlers and register components (tools, resources, etc.)
322-
setupHandlers(server)
323-
324-
// Start server using stdio transport
325-
const transport = new StdioServerTransport()
326-
327-
logInfo("Transport initialized: stdio")
328-
329-
await server.connect(transport)
330-
331-
logInfo("Server started successfully")
332-
} catch (error) {
333-
logError("Failed to start server", error)
334-
process.exit(1)
335-
}
336-
}
337-
338-
// Start the server
339-
main().catch((error) => {
5+
start().catch((error:Error) => {
3406
logError("Unhandled startup error", error)
3417
process.exit(1)
342-
})
8+
})

0 commit comments

Comments
 (0)