Skip to main content
Glama

@jpisnice/shadcn-ui-mcp-server

by Jpisnice
handler.ts11 kB
/** * Request handler setup for the Model Context Protocol (MCP) server. * * This file configures how the server responds to various MCP requests by setting up * handlers for resources, resource templates, tools, and prompts. * * Updated for MCP SDK 1.16.0 with improved error handling and request processing. */ import { CallToolRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ReadResourceRequestSchema, ListToolsRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js"; import { type Server } from "@modelcontextprotocol/sdk/server/index.js"; import { resourceHandlers, resources } from "../resources/index.js"; import { promptHandlers, prompts } from "../prompts/index.js"; import { toolHandlers, tools } from "../tools/index.js"; import { getResourceTemplate, resourceTemplates, } from "../resource-templates/index.js"; import { z } from "zod"; import { validateAndSanitizeParams } from '../utils/validation.js'; import { circuitBreakers } from '../utils/circuit-breaker.js'; import { logError, logInfo } from '../utils/logger.js'; // Define basic component schemas here for tool validation const componentSchema = { componentName: z.string() }; const searchSchema = { query: z.string() }; const themesSchema = { query: z.string().optional() }; const blocksSchema = { query: z.string().optional(), category: z.string().optional() }; /** * Wrapper function to handle requests with simple error handling */ async function handleRequest<T>( method: string, params: any, handler: (validatedParams: any) => Promise<T> ): Promise<T> { try { // Validate and sanitize input parameters const validatedParams = validateAndSanitizeParams(method, params); // Execute the handler with circuit breaker protection for external calls const result = await circuitBreakers.external.execute(() => handler(validatedParams)); return result; } catch (error) { logError(`Error in ${method}`, error); throw error; } } /** * Sets up all request handlers for the MCP server * Following MCP SDK 1.16.0 best practices for handler registration * @param server - The MCP server instance */ export const setupHandlers = (server: Server): void => { logInfo('Setting up request handlers...'); // List available resources when clients request them server.setRequestHandler( ListResourcesRequestSchema, async (request) => { return await handleRequest( 'list_resources', request.params, async () => ({ resources }) ); } ); // Resource Templates server.setRequestHandler(ListResourceTemplatesRequestSchema, async (request) => { return await handleRequest( 'list_resource_templates', request.params, async () => ({ resourceTemplates }) ); }); // List available tools server.setRequestHandler(ListToolsRequestSchema, async (request) => { return await handleRequest( 'list_tools', request.params, async () => { // Return the tools that are registered with the server const registeredTools = [ { name: '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'], }, }, { name: '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'], }, }, { name: 'list_components', description: 'Get all available shadcn/ui v4 components', inputSchema: { type: 'object', properties: {}, }, }, { name: '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'], }, }, { name: '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")', }, }, }, }, { name: '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'], }, }, { name: '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)', }, }, }, }, ]; return { tools: registeredTools }; } ); }); // Return resource content when clients request it server.setRequestHandler(ReadResourceRequestSchema, async (request) => { return await handleRequest( 'read_resource', request.params, async (validatedParams: any) => { const { uri } = validatedParams; // Check if this is a static resource const resourceHandler = resourceHandlers[uri as keyof typeof resourceHandlers]; if (resourceHandler) { const result = await Promise.resolve(resourceHandler()); return { contentType: result.contentType, contents: [{ uri: uri, text: result.content }] }; } // Check if this is a generated resource from a template const resourceTemplateHandler = getResourceTemplate(uri); if (resourceTemplateHandler) { const result = await Promise.resolve(resourceTemplateHandler()); return { contentType: result.contentType, contents: [{ uri: uri, text: result.content }] }; } throw new Error(`Resource not found: ${uri}`); } ); }); // List available prompts server.setRequestHandler(ListPromptsRequestSchema, async (request) => { return await handleRequest( 'list_prompts', request.params, async () => ({ prompts: Object.values(prompts) }) ); }); // Get specific prompt content with optional arguments server.setRequestHandler(GetPromptRequestSchema, async (request) => { return await handleRequest( 'get_prompt', request.params, async (validatedParams: any) => { const { name, arguments: args } = validatedParams; const promptHandler = promptHandlers[name as keyof typeof promptHandlers]; if (!promptHandler) { throw new Error(`Prompt not found: ${name}`); } return promptHandler(args as any); } ); }); // Tool request Handler - executes the requested tool with provided parameters server.setRequestHandler(CallToolRequestSchema, async (request) => { return await handleRequest( 'call_tool', request.params, async (validatedParams: any) => { const { name, arguments: params } = validatedParams; if (!name || typeof name !== 'string') { throw new Error("Tool name is required"); } const handler = toolHandlers[name as keyof typeof toolHandlers]; if (!handler) { throw new Error(`Tool not found: ${name}`); } // Execute handler with circuit breaker protection const result = await circuitBreakers.external.execute(() => Promise.resolve(handler(params || {})) ); return result; } ); }); // Add global error handler server.onerror = (error) => { logError('MCP server error', error); }; logInfo('Handlers setup complete'); }; /** * Get Zod schema for tool validation if available * Following MCP SDK 1.16.0 best practices for schema validation * @param toolName Name of the tool * @returns Zod schema or undefined */ function getToolSchema(toolName: string): z.ZodType | undefined { try { switch(toolName) { case 'get_component': case 'get_component_details': return z.object(componentSchema); case 'get_examples': return z.object(componentSchema); case 'get_usage': return z.object(componentSchema); case 'search_components': return z.object(searchSchema); case 'get_themes': return z.object(themesSchema); case 'get_blocks': return z.object(blocksSchema); default: return undefined; } } catch (error) { logError('Schema error', error); return undefined; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jpisnice/shadcn-ui-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server