@jpisnice/shadcn-ui-mcp-server
Version:
A Model Context Protocol (MCP) server for shadcn/ui components, providing AI assistants with access to component source code, demos, blocks, and metadata.
280 lines (274 loc) • 11.9 kB
JavaScript
/**
* Shadcn UI v4 MCP Server
*
* A Model Context Protocol server for shadcn/ui v4 components.
* Provides AI assistants with access to component source code, demos, blocks, and metadata.
*
* Usage:
* npx shadcn-ui-mcp-server
* npx shadcn-ui-mcp-server --github-api-key YOUR_TOKEN
* npx shadcn-ui-mcp-server -g YOUR_TOKEN
*/
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { setupHandlers } from './handler.js';
import { axios } from './utils/axios.js';
import { logError, logInfo, logWarning } from './utils/logger.js';
/**
* Parse command line arguments
*/
async function parseArgs() {
const args = process.argv.slice(2);
// Help flag
if (args.includes('--help') || args.includes('-h')) {
console.log(`
Shadcn UI v4 MCP Server
Usage:
npx shadcn-ui-mcp-server [options]
Options:
--github-api-key, -g <token> GitHub Personal Access Token for API access
--help, -h Show this help message
--version, -v Show version information
Examples:
npx shadcn-ui-mcp-server
npx shadcn-ui-mcp-server --github-api-key ghp_your_token_here
npx shadcn-ui-mcp-server -g ghp_your_token_here
Environment Variables:
GITHUB_PERSONAL_ACCESS_TOKEN Alternative way to provide GitHub token
LOG_LEVEL Log level (debug, info, warn, error) - default: info
For more information, visit: https://github.com/Jpisnice/shadcn-ui-mcp-server
`);
process.exit(0);
}
// Version flag
if (args.includes('--version') || args.includes('-v')) {
// Read version from package.json
try {
const fs = await import('fs');
const path = await import('path');
const { fileURLToPath } = await import('url');
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const packagePath = path.join(__dirname, '..', 'package.json');
const packageContent = fs.readFileSync(packagePath, 'utf8');
const packageJson = JSON.parse(packageContent);
console.log(`shadcn-ui-mcp-server v${packageJson.version}`);
}
catch (error) {
console.log('shadcn-ui-mcp-server v1.0.2');
}
process.exit(0);
}
// GitHub API key
const githubApiKeyIndex = args.findIndex(arg => arg === '--github-api-key' || arg === '-g');
let githubApiKey = null;
if (githubApiKeyIndex !== -1 && args[githubApiKeyIndex + 1]) {
githubApiKey = args[githubApiKeyIndex + 1];
}
else if (process.env.GITHUB_PERSONAL_ACCESS_TOKEN) {
githubApiKey = process.env.GITHUB_PERSONAL_ACCESS_TOKEN;
}
return { githubApiKey };
}
/**
* Main function to start the MCP server
*/
async function main() {
try {
logInfo('Starting Shadcn UI v4 MCP Server...');
const { githubApiKey } = await parseArgs();
// Configure GitHub API key if provided
if (githubApiKey) {
axios.setGitHubApiKey(githubApiKey);
logInfo('GitHub API configured with token');
}
else {
logWarning('No GitHub API key provided. Rate limited to 60 requests/hour.');
}
// Initialize the MCP server with metadata and capabilities
// Following MCP SDK 1.16.0 best practices
const server = new Server({
name: "shadcn-ui-mcp-server",
version: "1.0.2",
}, {
capabilities: {
resources: {
"get_components": {
description: "List of available shadcn/ui components that can be used in the project",
uri: "resource:get_components",
contentType: "text/plain"
}
},
prompts: {
"component_usage": {
description: "Get usage examples for a specific component",
arguments: {
componentName: {
type: "string",
description: "Name of the component to get usage for"
}
}
},
"component_search": {
description: "Search for components by name or description",
arguments: {
query: {
type: "string",
description: "Search query"
}
}
},
"component_comparison": {
description: "Compare two components side by side",
arguments: {
component1: {
type: "string",
description: "First component name"
},
component2: {
type: "string",
description: "Second component name"
}
}
},
"component_recommendation": {
description: "Get component recommendations based on use case",
arguments: {
useCase: {
type: "string",
description: "Use case description"
}
}
},
"component_tutorial": {
description: "Get a step-by-step tutorial for using a component",
arguments: {
componentName: {
type: "string",
description: "Name of the component for tutorial"
}
}
}
},
tools: {
"get_component": {
description: "Get the source code for a specific shadcn/ui v4 component",
inputSchema: {
type: "object",
properties: {
componentName: {
type: "string",
description: "Name of the shadcn/ui component (e.g., \"accordion\", \"button\")"
}
},
required: ["componentName"]
}
},
"get_component_demo": {
description: "Get demo code illustrating how a shadcn/ui v4 component should be used",
inputSchema: {
type: "object",
properties: {
componentName: {
type: "string",
description: "Name of the shadcn/ui component (e.g., \"accordion\", \"button\")"
}
},
required: ["componentName"]
}
},
"list_components": {
description: "Get all available shadcn/ui v4 components",
inputSchema: {
type: "object",
properties: {}
}
},
"get_component_metadata": {
description: "Get metadata for a specific shadcn/ui v4 component",
inputSchema: {
type: "object",
properties: {
componentName: {
type: "string",
description: "Name of the shadcn/ui component (e.g., \"accordion\", \"button\")"
}
},
required: ["componentName"]
}
},
"get_directory_structure": {
description: "Get the directory structure of the shadcn-ui v4 repository",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "Path within the repository (default: v4 registry)"
},
owner: {
type: "string",
description: "Repository owner (default: \"shadcn-ui\")"
},
repo: {
type: "string",
description: "Repository name (default: \"ui\")"
},
branch: {
type: "string",
description: "Branch name (default: \"main\")"
}
}
}
},
"get_block": {
description: "Get source code for a specific shadcn/ui v4 block (e.g., calendar-01, dashboard-01)",
inputSchema: {
type: "object",
properties: {
blockName: {
type: "string",
description: "Name of the block (e.g., \"calendar-01\", \"dashboard-01\", \"login-02\")"
},
includeComponents: {
type: "boolean",
description: "Whether to include component files for complex blocks (default: true)"
}
},
required: ["blockName"]
}
},
"list_blocks": {
description: "Get all available shadcn/ui v4 blocks with categorization",
inputSchema: {
type: "object",
properties: {
category: {
type: "string",
description: "Filter by category (calendar, dashboard, login, sidebar, products)"
}
}
}
}
}
}
});
// Set up request handlers and register components (tools, resources, etc.)
setupHandlers(server);
// Start server using stdio transport
const transport = new StdioServerTransport();
logInfo('Transport initialized: stdio');
await server.connect(transport);
logInfo('Server started successfully');
}
catch (error) {
logError('Failed to start server', error);
process.exit(1);
}
}
// Start the server
main().catch((error) => {
logError('Unhandled startup error', error);
process.exit(1);
});