UNPKG

@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.

138 lines (137 loc) 4.87 kB
import Joi from 'joi'; /** * Validation schemas for different request types */ export const validationSchemas = { // Component-related schemas componentName: Joi.object({ componentName: Joi.string().required().min(1).max(100) .description('Name of the shadcn/ui component') }), // Search schemas searchQuery: Joi.object({ query: Joi.string().required().min(1).max(500) .description('Search query string') }), // Optional query schemas optionalQuery: Joi.object({ query: Joi.string().optional().max(500) .description('Optional query string') }), // Block schemas blockQuery: Joi.object({ query: Joi.string().optional().max(500) .description('Optional search query'), category: Joi.string().optional().max(100) .description('Optional category filter') }), // Directory structure schemas directoryStructure: Joi.object({ path: Joi.string().optional().max(500) .description('Path within the repository'), owner: Joi.string().optional().max(100) .description('Repository owner'), repo: Joi.string().optional().max(100) .description('Repository name'), branch: Joi.string().optional().max(100) .description('Branch name') }), // Block schemas blockRequest: Joi.object({ blockName: Joi.string().required().min(1).max(200) .description('Name of the block'), includeComponents: Joi.boolean().optional() .description('Whether to include component files') }), // Resource schemas resourceRequest: Joi.object({ uri: Joi.string().required().min(1).max(1000) .description('Resource URI') }), // Prompt schemas promptRequest: Joi.object({ name: Joi.string().required().min(1).max(200) .description('Prompt name'), arguments: Joi.object().optional() .description('Prompt arguments') }), // Tool schemas toolRequest: Joi.object({ name: Joi.string().required().min(1).max(200) .description('Tool name'), arguments: Joi.object().optional() .description('Tool arguments') }) }; /** * Validate request parameters against a schema * @param schema Joi schema to validate against * @param params Parameters to validate * @returns Validated parameters * @throws ValidationError if validation fails */ export function validateRequest(schema, params) { try { const { error, value } = schema.validate(params, { abortEarly: false, stripUnknown: true, allowUnknown: false }); if (error) { const errorMessages = error.details.map(detail => `${detail.path.join('.')}: ${detail.message}`).join(', '); throw new Error(`Validation failed: ${errorMessages}`); } return value; } catch (error) { if (error instanceof Error) { throw error; } throw new Error(`Unexpected validation error: ${error instanceof Error ? error.message : String(error)}`); } } /** * Get validation schema for a specific method * @param method Method name * @returns Joi schema or undefined */ export function getValidationSchema(method) { const schemaMap = { // Component methods 'get_component': validationSchemas.componentName, 'get_component_demo': validationSchemas.componentName, 'get_component_metadata': validationSchemas.componentName, 'get_component_details': validationSchemas.componentName, 'get_examples': validationSchemas.componentName, 'get_usage': validationSchemas.componentName, // Search methods 'search_components': validationSchemas.searchQuery, 'get_themes': validationSchemas.optionalQuery, 'get_blocks': validationSchemas.blockQuery, // Directory methods 'get_directory_structure': validationSchemas.directoryStructure, // Block methods 'get_block': validationSchemas.blockRequest, // Resource methods 'read_resource': validationSchemas.resourceRequest, // Prompt methods 'get_prompt': validationSchemas.promptRequest, // Tool methods 'call_tool': validationSchemas.toolRequest }; return schemaMap[method]; } /** * Validate and sanitize input parameters * @param method Method name * @param params Parameters to validate * @returns Validated and sanitized parameters */ export function validateAndSanitizeParams(method, params) { const schema = getValidationSchema(method); if (!schema) { // If no specific schema found, return params as-is return params; } return validateRequest(schema, params); }