Skip to main content
Glama

Enhanced Reablocks MCP Server

by qdhenry
index.ts47.1 kB
import { McpAgent } from "agents/mcp"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; // Simplified but enhanced component metadata interface ComponentSchema { name: string; category: string; description: string; props: PropDefinition[]; variants: string[]; examples: CodeExample[]; useCases: string[]; relatedComponents: string[]; } interface PropDefinition { name: string; type: string; required: boolean; description: string; defaultValue?: any; } interface CodeExample { title: string; code: string; description: string; } interface GenerationRequest { type: 'dashboard' | 'form' | 'table' | 'navigation' | 'custom'; description: string; requirements: string[]; styling?: { theme?: 'light' | 'dark' | 'auto'; spacing?: 'compact' | 'normal' | 'spacious'; colorScheme?: string; }; } // Natural Language Processing for component requirements class ComponentNLP { private intentPatterns = { dashboard: /dashboard|overview|summary|metrics|analytics|admin/i, table: /table|list|grid|data|rows|columns|display.*data/i, form: /form|input|submit|validate|fields|contact|login|register/i, navigation: /nav|menu|sidebar|header|navigation|breadcrumb/i, layout: /layout|structure|arrange|organize|card|container/i, interactive: /button|click|action|interactive|toggle|select/i, data: /data|information|content|text|display/i }; private componentKeywords = { 'Button': ['button', 'click', 'action', 'submit', 'cancel'], 'Input': ['input', 'field', 'text', 'email', 'password', 'form'], 'Card': ['card', 'container', 'panel', 'section', 'content'], 'Dialog': ['dialog', 'modal', 'popup', 'overlay', 'alert'], 'Table': ['table', 'list', 'grid', 'data', 'rows'], 'Menu': ['menu', 'navigation', 'nav', 'sidebar'], 'Tabs': ['tabs', 'tabbed', 'sections', 'pages'], 'Select': ['select', 'dropdown', 'choose', 'options'], 'Checkbox': ['checkbox', 'check', 'multi-select', 'toggle'], 'Badge': ['badge', 'label', 'tag', 'status'], 'Avatar': ['avatar', 'profile', 'user', 'image'], 'Notification': ['notification', 'alert', 'message', 'toast'], 'Breadcrumbs': ['breadcrumb', 'navigation', 'path', 'trail'] }; parseRequest(description: string): GenerationRequest { const requirements: string[] = []; let type: GenerationRequest['type'] = 'custom'; // Detect intent for (const [intent, pattern] of Object.entries(this.intentPatterns)) { if (pattern.test(description)) { requirements.push(intent); if (intent === 'dashboard') type = 'dashboard'; else if (intent === 'table') type = 'table'; else if (intent === 'form') type = 'form'; else if (intent === 'navigation') type = 'navigation'; } } return { type, description, requirements }; } suggestComponents(description: string): string[] { const suggested = new Set<string>(); const descLower = description.toLowerCase(); for (const [component, keywords] of Object.entries(this.componentKeywords)) { if (keywords.some(keyword => descLower.includes(keyword))) { suggested.add(component); } } return Array.from(suggested); } } // Enhanced component database with real Reablocks components const ENHANCED_REABLOCKS_COMPONENTS: Record<string, ComponentSchema> = { Button: { name: 'Button', category: 'Elements', description: 'A fundamental UI element designed for interactions, offering a variety of styles, sizes, and colors to accommodate different use cases within an application.', props: [ { name: 'variant', type: '"filled" | "outline" | "text"', required: false, description: 'The visual style variant of the button', defaultValue: 'filled' }, { name: 'size', type: '"small" | "medium" | "large"', required: false, description: 'The size of the button', defaultValue: 'medium' }, { name: 'color', type: '"default" | "primary" | "secondary" | "success" | "warning" | "error"', required: false, description: 'The color theme of the button', defaultValue: 'default' }, { name: 'disabled', type: 'boolean', required: false, description: 'Whether the button is disabled', defaultValue: false }, { name: 'fullWidth', type: 'boolean', required: false, description: 'Whether the button should take the full width of its container', defaultValue: false }, { name: 'onClick', type: '(event: MouseEvent) => void', required: false, description: 'Handler function called when the button is clicked' }, { name: 'children', type: 'ReactNode', required: true, description: 'The content to display inside the button' } ], variants: ['filled', 'outline', 'text'], examples: [ { title: 'Basic Button', code: '<Button>Click Me</Button>', description: 'A simple button with default styling' }, { title: 'Primary Action', code: '<Button variant="filled" color="primary">Save Changes</Button>', description: 'A prominent button for primary actions' }, { title: 'Secondary Action', code: '<Button variant="outline" color="secondary">Cancel</Button>', description: 'A less prominent button for secondary actions' } ], useCases: ['Primary actions', 'Form submissions', 'Navigation triggers', 'Modal actions'], relatedComponents: ['IconButton', 'ButtonGroup'] }, Input: { name: 'Input', category: 'Form', description: 'A fundamental element in form design, allowing users to enter data. Its versatility supports a variety of applications, from simple text entries to complex data inputs.', props: [ { name: 'type', type: 'string', required: false, description: 'The type of input (text, email, password, etc.)', defaultValue: 'text' }, { name: 'placeholder', type: 'string', required: false, description: 'Placeholder text to display when input is empty' }, { name: 'value', type: 'string', required: false, description: 'The controlled value of the input' }, { name: 'onChange', type: '(value: string) => void', required: false, description: 'Handler called when input value changes' }, { name: 'disabled', type: 'boolean', required: false, description: 'Whether the input is disabled', defaultValue: false }, { name: 'error', type: 'string', required: false, description: 'Error message to display' }, { name: 'size', type: '"small" | "medium" | "large"', required: false, description: 'The size of the input', defaultValue: 'medium' }, { name: 'fullWidth', type: 'boolean', required: false, description: 'Whether input takes full width', defaultValue: false } ], variants: ['default', 'error', 'disabled'], examples: [ { title: 'Basic Input', code: '<Input placeholder="Enter text" />', description: 'A simple text input field' }, { title: 'Email Input', code: '<Input type="email" placeholder="Enter email" />', description: 'Input specifically for email addresses' }, { title: 'Input with Error', code: '<Input placeholder="Email" error="Invalid email format" />', description: 'Input field with error state' } ], useCases: ['Text entry', 'Form fields', 'Search boxes', 'Data input'], relatedComponents: ['Textarea', 'Select', 'DebouncedInput'] }, Card: { name: 'Card', category: 'Layout', description: 'Cards are a fundamental building block for compositions, such as forms, or sections. They provide a consistent container for content with optional padding and styling.', props: [ { name: 'children', type: 'ReactNode', required: true, description: 'The content to display inside the card' }, { name: 'className', type: 'string', required: false, description: 'Additional CSS classes to apply' }, { name: 'disablePadding', type: 'boolean', required: false, description: 'Whether to disable default padding', defaultValue: false } ], variants: ['default', 'elevated', 'outlined'], examples: [ { title: 'Basic Card', code: '<Card><h3>Card Title</h3><p>Card content goes here.</p></Card>', description: 'A simple card with content' }, { title: 'Card without Padding', code: '<Card disablePadding><img src="image.jpg" alt="Full width image" /></Card>', description: 'Card that allows content to fill the entire space' } ], useCases: ['Content containers', 'Information panels', 'Dashboard widgets', 'Form sections'], relatedComponents: ['Block', 'Stack', 'Divider'] }, Dialog: { name: 'Dialog', category: 'Layers', description: 'The Dialog component serves as a pop-up or modal window that overlays the main content, allowing the display of important messages, forms, or user interactions while grabbing user\'s focus.', props: [ { name: 'open', type: 'boolean', required: true, description: 'Whether the dialog is open' }, { name: 'onClose', type: '() => void', required: true, description: 'Function called when dialog should close' }, { name: 'title', type: 'string', required: false, description: 'The title of the dialog' }, { name: 'children', type: 'ReactNode', required: true, description: 'The content to display inside the dialog' }, { name: 'size', type: '"small" | "medium" | "large"', required: false, description: 'The size of the dialog', defaultValue: 'medium' } ], variants: ['default', 'fullscreen'], examples: [ { title: 'Basic Dialog', code: '<Dialog open={isOpen} onClose={() => setIsOpen(false)} title="Confirm Action"><p>Are you sure?</p></Dialog>', description: 'A simple confirmation dialog' }, { title: 'Form Dialog', code: '<Dialog open={isOpen} onClose={handleClose} title="Edit Profile"><form>...</form></Dialog>', description: 'Dialog containing a form' } ], useCases: ['Confirmations', 'Forms', 'Detailed views', 'Alerts'], relatedComponents: ['Drawer', 'ConfirmDialog', 'Notification'] }, Stack: { name: 'Stack', category: 'Layout', description: 'Component that sets component spacing. It can be used to add space between components such as a menu or form elements.', props: [ { name: 'direction', type: '"row" | "column" | "rowReverse" | "columnReverse"', required: false, description: 'The direction of the stack', defaultValue: 'column' }, { name: 'spacing', type: '"xs" | "sm" | "md" | "lg" | "xl"', required: false, description: 'The spacing between items', defaultValue: 'md' }, { name: 'alignItems', type: '"start" | "end" | "center" | "stretch"', required: false, description: 'How items are aligned', defaultValue: 'stretch' }, { name: 'justifyContent', type: '"start" | "end" | "center" | "spaceBetween"', required: false, description: 'How items are justified', defaultValue: 'start' }, { name: 'children', type: 'ReactNode', required: true, description: 'The items to stack' } ], variants: ['row', 'column', 'dense', 'inline'], examples: [ { title: 'Vertical Stack', code: '<Stack><Button>First</Button><Button>Second</Button></Stack>', description: 'Stack items vertically with default spacing' }, { title: 'Horizontal Stack', code: '<Stack direction="row" spacing="lg"><Button>Cancel</Button><Button>Save</Button></Stack>', description: 'Stack items horizontally with large spacing' } ], useCases: ['Form layouts', 'Button groups', 'Content sections', 'Navigation items'], relatedComponents: ['Divider', 'Card', 'Block'] }, Select: { name: 'Select', category: 'Form', description: 'The Select component enhances user interaction by allowing the selection of a value or multiple values from a list of options with support for filtering, creation, and async loading.', props: [ { name: 'options', type: 'SelectOption[]', required: true, description: 'Array of options to select from' }, { name: 'value', type: 'any', required: false, description: 'The selected value(s)' }, { name: 'onChange', type: '(value: any) => void', required: false, description: 'Handler called when selection changes' }, { name: 'placeholder', type: 'string', required: false, description: 'Placeholder text when no selection' }, { name: 'multiple', type: 'boolean', required: false, description: 'Allow multiple selections', defaultValue: false }, { name: 'searchable', type: 'boolean', required: false, description: 'Enable search/filtering', defaultValue: true }, { name: 'createable', type: 'boolean', required: false, description: 'Allow creating new options', defaultValue: false }, { name: 'disabled', type: 'boolean', required: false, description: 'Whether the select is disabled', defaultValue: false } ], variants: ['single', 'multiple', 'searchable', 'createable'], examples: [ { title: 'Basic Select', code: '<Select options={[{label: "Option 1", value: "1"}]} placeholder="Choose..." />', description: 'Simple single selection' }, { title: 'Multi-Select', code: '<Select multiple options={options} placeholder="Select multiple..." />', description: 'Multiple selection with chips' } ], useCases: ['Option selection', 'Filtering', 'Multi-choice inputs', 'Searchable dropdowns'], relatedComponents: ['Input', 'Checkbox', 'Radio', 'Menu'] }, DataSize: { name: 'DataSize', category: 'Data', description: 'The Data Size component is designed to display data sizes in a human-readable format using the human-format library, converting bytes into understandable formats like MB, GB, etc.', props: [ { name: 'value', type: 'number | string | null | undefined', required: true, description: 'The byte value to format' }, { name: 'placeholder', type: 'string', required: false, description: 'Text to show when value is null/undefined', defaultValue: '--' } ], variants: ['default'], examples: [ { title: 'File Size', code: '<DataSize value={1048576} />', description: 'Displays "1 MB"' }, { title: 'Large File', code: '<DataSize value={324344535345232482} />', description: 'Displays in appropriate unit (TB, PB, etc.)' } ], useCases: ['File sizes', 'Data usage', 'Storage displays', 'Download sizes'], relatedComponents: ['Duration', 'DateFormat', 'Pluralize'] }, Notification: { name: 'Notification', category: 'Layers', description: 'The Notification component delivers real-time messages or alerts to users, providing important updates, feedback, or information within an application.', props: [ { name: 'title', type: 'string', required: false, description: 'The notification title' }, { name: 'body', type: 'string | ReactNode', required: false, description: 'The notification content' }, { name: 'variant', type: '"default" | "success" | "warning" | "error" | "info"', required: false, description: 'The notification type', defaultValue: 'default' }, { name: 'timeout', type: 'number', required: false, description: 'Auto-dismiss timeout in ms', defaultValue: 5000 }, { name: 'showClose', type: 'boolean', required: false, description: 'Show close button', defaultValue: true } ], variants: ['default', 'success', 'warning', 'error', 'info'], examples: [ { title: 'Success Message', code: 'notify("Changes saved successfully!", { variant: "success" })', description: 'Show success notification' }, { title: 'Error Alert', code: 'notify("Something went wrong", { variant: "error", timeout: 0 })', description: 'Show persistent error' } ], useCases: ['Status updates', 'Error messages', 'Success confirmations', 'Information alerts'], relatedComponents: ['Dialog', 'Toast', 'Alert'] } }; // Intelligent code generator class SmartCodeGenerator { private nlp: ComponentNLP; constructor() { this.nlp = new ComponentNLP(); } generateDashboard(request: GenerationRequest): string { const components = this.selectComponents(request); const layout = this.determineLayout(request); return this.composeDashboard(components, layout, request); } private selectComponents(request: GenerationRequest): ComponentSchema[] { const suggested = this.nlp.suggestComponents(request.description); // Add essential dashboard components const essentialComponents = ['Card', 'Button', 'Stack']; const allComponents = [...new Set([...suggested, ...essentialComponents])]; return allComponents .map(name => ENHANCED_REABLOCKS_COMPONENTS[name]) .filter(Boolean); } private determineLayout(request: GenerationRequest): 'grid' | 'stack' | 'flex' { if (request.description.includes('grid') || request.type === 'dashboard') return 'grid'; if (request.description.includes('vertical') || request.description.includes('stack')) return 'stack'; return 'flex'; } private composeDashboard(components: ComponentSchema[], layout: string, request: GenerationRequest): string { const imports = this.generateImports(components); const componentCode = this.generateDashboardComponent(components, layout, request); return `${imports} ${componentCode}`; } private generateImports(components: ComponentSchema[]): string { const componentNames = components.map(c => c.name); return `import React, { useState, useEffect } from 'react'; import { ${componentNames.join(', ')} } from 'reablocks';`; } private generateDashboardComponent(components: ComponentSchema[], layout: string, request: GenerationRequest): string { const hasForm = request.requirements.includes('form'); const hasTable = request.requirements.includes('table'); const hasDashboard = request.requirements.includes('dashboard'); if (hasForm) { return this.generateFormLayout(components); } else if (hasTable) { return this.generateTableLayout(components); } else if (hasDashboard) { return this.generateDashboardLayout(components); } else { return this.generateGenericLayout(components, layout); } } private generateFormLayout(components: ComponentSchema[]): string { return `interface FormData { name: string; email: string; message: string; } export const GeneratedForm: React.FC = () => { const [formData, setFormData] = useState<FormData>({ name: '', email: '', message: '' }); const [isSubmitting, setIsSubmitting] = useState(false); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setIsSubmitting(true); try { // Add your form submission logic here console.log('Form submitted:', formData); await new Promise(resolve => setTimeout(resolve, 1000)); // Simulate API call alert('Form submitted successfully!'); } catch (error) { console.error('Submission failed:', error); } finally { setIsSubmitting(false); } }; const handleChange = (field: keyof FormData) => (value: string) => { setFormData(prev => ({ ...prev, [field]: value })); }; return ( <Card className="max-w-md mx-auto p-6"> <h2 className="text-2xl font-bold mb-6">Contact Form</h2> <form onSubmit={handleSubmit}> <Stack spacing="lg"> <Input placeholder="Your Name" value={formData.name} onChange={handleChange('name')} fullWidth /> <Input type="email" placeholder="Email Address" value={formData.email} onChange={handleChange('email')} fullWidth /> <Input placeholder="Message" value={formData.message} onChange={handleChange('message')} fullWidth /> <Stack direction="row" spacing="md" justifyContent="end"> <Button variant="outline" disabled={isSubmitting} onClick={() => setFormData({ name: '', email: '', message: '' })} > Clear </Button> <Button type="submit" color="primary" disabled={isSubmitting} > {isSubmitting ? 'Submitting...' : 'Submit'} </Button> </Stack> </Stack> </form> </Card> ); };`; } private generateDashboardLayout(components: ComponentSchema[]): string { return `interface DashboardProps { data?: any[]; loading?: boolean; onRefresh?: () => void; } export const GeneratedDashboard: React.FC<DashboardProps> = ({ data = [], loading = false, onRefresh }) => { const [selectedMetric, setSelectedMetric] = useState<string>('users'); const metrics = [ { id: 'users', label: 'Total Users', value: '12,345', change: '+12%', color: 'primary' }, { id: 'revenue', label: 'Revenue', value: '$67,890', change: '+8%', color: 'success' }, { id: 'orders', label: 'Orders', value: '1,234', change: '-3%', color: 'warning' } ]; if (loading) { return ( <div className="flex items-center justify-center min-h-screen"> <div>Loading dashboard...</div> </div> ); } return ( <div className="min-h-screen bg-gray-50 p-6"> <div className="max-w-7xl mx-auto"> {/* Header */} <div className="flex items-center justify-between mb-8"> <h1 className="text-3xl font-bold text-gray-900">Dashboard</h1> <Button variant="outline" onClick={onRefresh}> Refresh Data </Button> </div> {/* Metrics Grid */} <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8"> {metrics.map((metric) => ( <Card key={metric.id} className="cursor-pointer hover:shadow-lg transition-shadow"> <div className="p-6"> <h3 className="text-sm font-medium text-gray-500 mb-2">{metric.label}</h3> <div className="flex items-baseline justify-between"> <p className="text-3xl font-bold text-gray-900">{metric.value}</p> <span className={\`text-sm font-medium \${ metric.change.startsWith('+') ? 'text-green-600' : 'text-red-600' }\`}> {metric.change} </span> </div> </div> </Card> ))} </div> {/* Main Content */} <div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> {/* Chart Area */} <Card className="lg:col-span-2"> <div className="p-6"> <h3 className="text-lg font-semibold mb-4">Analytics Overview</h3> <div className="h-64 flex items-center justify-center bg-gray-100 rounded"> <p className="text-gray-500">Chart component would go here</p> </div> </div> </Card> {/* Side Panel */} <Card> <div className="p-6"> <h3 className="text-lg font-semibold mb-4">Quick Actions</h3> <Stack spacing="md"> <Button fullWidth color="primary"> Create New </Button> <Button fullWidth variant="outline"> View Reports </Button> <Button fullWidth variant="outline"> Settings </Button> </Stack> </div> </Card> </div> </div> </div> ); };`; } private generateTableLayout(components: ComponentSchema[]): string { return `interface TableItem { id: string; name: string; status: 'active' | 'inactive' | 'pending'; date: string; value: number; } export const GeneratedTable: React.FC = () => { const [items, setItems] = useState<TableItem[]>([ { id: '1', name: 'Item 1', status: 'active', date: '2024-01-15', value: 1250 }, { id: '2', name: 'Item 2', status: 'pending', date: '2024-01-14', value: 890 }, { id: '3', name: 'Item 3', status: 'inactive', date: '2024-01-13', value: 2100 } ]); const [selectedItems, setSelectedItems] = useState<string[]>([]); const [searchTerm, setSearchTerm] = useState(''); const filteredItems = items.filter(item => item.name.toLowerCase().includes(searchTerm.toLowerCase()) ); const handleSelectAll = () => { if (selectedItems.length === filteredItems.length) { setSelectedItems([]); } else { setSelectedItems(filteredItems.map(item => item.id)); } }; const handleSelectItem = (id: string) => { setSelectedItems(prev => prev.includes(id) ? prev.filter(itemId => itemId !== id) : [...prev, id] ); }; const getStatusColor = (status: TableItem['status']) => { switch (status) { case 'active': return 'success'; case 'pending': return 'warning'; case 'inactive': return 'error'; default: return 'default'; } }; return ( <div className="p-6"> <Card> <div className="p-6"> {/* Header */} <div className="flex items-center justify-between mb-6"> <h2 className="text-2xl font-bold">Data Table</h2> <Stack direction="row" spacing="md"> <Input placeholder="Search items..." value={searchTerm} onChange={setSearchTerm} /> <Button color="primary">Add New</Button> </Stack> </div> {/* Bulk Actions */} {selectedItems.length > 0 && ( <div className="mb-4 p-3 bg-blue-50 rounded-lg"> <Stack direction="row" spacing="md" alignItems="center"> <span className="text-sm text-blue-700"> {selectedItems.length} item(s) selected </span> <Button size="small" variant="outline"> Delete Selected </Button> <Button size="small" variant="outline"> Export Selected </Button> </Stack> </div> )} {/* Table */} <div className="overflow-x-auto"> <table className="w-full"> <thead> <tr className="border-b"> <th className="text-left py-3 px-2"> <input type="checkbox" checked={selectedItems.length === filteredItems.length} onChange={handleSelectAll} /> </th> <th className="text-left py-3 px-4">Name</th> <th className="text-left py-3 px-4">Status</th> <th className="text-left py-3 px-4">Date</th> <th className="text-left py-3 px-4">Value</th> <th className="text-left py-3 px-4">Actions</th> </tr> </thead> <tbody> {filteredItems.map((item) => ( <tr key={item.id} className="border-b hover:bg-gray-50"> <td className="py-3 px-2"> <input type="checkbox" checked={selectedItems.includes(item.id)} onChange={() => handleSelectItem(item.id)} /> </td> <td className="py-3 px-4 font-medium">{item.name}</td> <td className="py-3 px-4"> <span className={\`px-2 py-1 rounded-full text-xs font-medium \${ item.status === 'active' ? 'bg-green-100 text-green-800' : item.status === 'pending' ? 'bg-yellow-100 text-yellow-800' : 'bg-red-100 text-red-800' }\`}> {item.status} </span> </td> <td className="py-3 px-4 text-gray-600">{item.date}</td> <td className="py-3 px-4"> <DataSize value={item.value * 1024} /> </td> <td className="py-3 px-4"> <Stack direction="row" spacing="sm"> <Button size="small" variant="text">Edit</Button> <Button size="small" variant="text" color="error">Delete</Button> </Stack> </td> </tr> ))} </tbody> </table> </div> {filteredItems.length === 0 && ( <div className="text-center py-8 text-gray-500"> No items found matching your search. </div> )} </div> </Card> </div> ); };`; } private generateGenericLayout(components: ComponentSchema[], layout: string): string { const componentList = components.map(c => c.name).join(', '); return `export const GeneratedComponent: React.FC = () => { const [state, setState] = useState({}); return ( <div className="p-6"> <Card> <div className="p-6"> <h2 className="text-2xl font-bold mb-6">Generated Component</h2> <Stack spacing="lg"> {/* Components: ${componentList} */} <div className="space-y-4"> <p className="text-gray-600"> This component was generated based on your requirements. It includes the following Reablocks components: ${componentList} </p> <Stack direction="row" spacing="md"> <Button color="primary">Primary Action</Button> <Button variant="outline">Secondary Action</Button> </Stack> <div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <Card> <div className="p-4"> <h3 className="font-semibold mb-2">Section 1</h3> <p className="text-sm text-gray-600">Content goes here</p> </div> </Card> <Card> <div className="p-4"> <h3 className="font-semibold mb-2">Section 2</h3> <p className="text-sm text-gray-600">More content here</p> </div> </Card> </div> </div> </Stack> </div> </Card> </div> ); };`; } } // Main MCP Server Class export class MyMCP extends McpAgent { private codeGenerator: SmartCodeGenerator; private nlp: ComponentNLP; server = new McpServer({ name: "Enhanced Reablocks MCP Server", version: "1.0.0", }); constructor(ctx: DurableObjectState, env: any) { super(ctx, env); this.codeGenerator = new SmartCodeGenerator(); this.nlp = new ComponentNLP(); } async init() { // Tool 1: Intelligent Dashboard Generation this.server.tool( "generate_intelligent_dashboard", { description: z.string().describe("Natural language description of what you want to build"), requirements: z.array(z.string()).optional().describe("Specific requirements"), styling: z.object({ theme: z.enum(['light', 'dark', 'auto']).optional(), spacing: z.enum(['compact', 'normal', 'spacious']).optional(), colorScheme: z.string().optional() }).optional() }, async ({ description, requirements = [], styling }) => { try { const request: GenerationRequest = { type: 'dashboard', description, requirements, styling }; const generatedCode = this.codeGenerator.generateDashboard(request); const suggestedComponents = this.nlp.suggestComponents(description); return { content: [{ type: "text", text: `# Generated Dashboard Component ## Description ${description} ## Detected Components ${suggestedComponents.join(', ')} ## Generated Code \`\`\`tsx ${generatedCode} \`\`\` ## Usage Instructions 1. **Install reablocks**: \`npm install reablocks\` 2. **Copy the generated code** into your React project 3. **Import and use** the component: \`<GeneratedDashboard />\` 4. **Customize** the styling and data as needed ## Features Included - ✅ Responsive design - ✅ TypeScript support - ✅ Error handling - ✅ Loading states - ✅ Interactive components - ✅ Modern styling with Tailwind CSS ## Next Steps - Connect your data source - Customize colors and spacing - Add additional functionality as needed` }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } } ); // Tool 2: Component Explorer this.server.tool( "explore_reablocks_components", { category: z.enum(['Elements', 'Form', 'Layout', 'Layers', 'Data', 'Typography']).optional(), search: z.string().optional() }, async ({ category, search }) => { try { let components = Object.values(ENHANCED_REABLOCKS_COMPONENTS); if (category) { components = components.filter(c => c.category === category); } if (search) { const searchLower = search.toLowerCase(); components = components.filter(c => c.name.toLowerCase().includes(searchLower) || c.description.toLowerCase().includes(searchLower) || c.useCases.some(use => use.toLowerCase().includes(searchLower)) ); } const componentList = components.map(comp => `## ${comp.name} **Category**: ${comp.category} **Description**: ${comp.description} **Key Props**: ${comp.props.slice(0, 4).map(prop => `- **${prop.name}** (${prop.type}): ${prop.description}`).join('\n')} **Use Cases**: ${comp.useCases.join(', ')} **Related**: ${comp.relatedComponents.join(', ')} **Example**: \`\`\`tsx ${comp.examples[0]?.code || `<${comp.name}>Content</${comp.name}>`} \`\`\` `).join('\n---\n'); return { content: [{ type: "text", text: `# Reablocks Component Explorer Found ${components.length} components${category ? ` in ${category}` : ''}${search ? ` matching "${search}"` : ''}. ${componentList}` }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } } ); // Tool 3: Natural Language Component Query this.server.tool( "ask_about_components", { question: z.string().describe("Ask questions about Reablocks components in natural language") }, async ({ question }) => { try { const request = this.nlp.parseRequest(question); const suggestedComponents = this.nlp.suggestComponents(question); const relevantComponents = suggestedComponents .map(name => ENHANCED_REABLOCKS_COMPONENTS[name]) .filter(Boolean); let response = `# Answer to: "${question}"\n\n`; if (relevantComponents.length > 0) { response += `## Suggested Components\n\n`; relevantComponents.forEach(comp => { response += `### ${comp.name} ${comp.description} **Perfect for**: ${comp.useCases.join(', ')} **Quick Example**: \`\`\`tsx ${comp.examples[0]?.code || `<${comp.name} />`} \`\`\` `; }); response += `## Complete Example\n\n`; if (request.type === 'form') { response += `Here's a complete form example using the suggested components: \`\`\`tsx import { ${suggestedComponents.join(', ')} } from 'reablocks'; export const ExampleForm = () => { const [formData, setFormData] = useState({}); return ( <Card> <Stack spacing="lg"> <Input placeholder="Name" /> <Input type="email" placeholder="Email" /> <Button color="primary">Submit</Button> </Stack> </Card> ); }; \`\`\``; } else if (request.type === 'dashboard') { response += `Here's a dashboard example: \`\`\`tsx import { ${suggestedComponents.join(', ')} } from 'reablocks'; export const ExampleDashboard = () => ( <div className="grid grid-cols-1 md:grid-cols-3 gap-4"> <Card><DataSize value={1024000} /></Card> <Card><Button>Action</Button></Card> <Card>Content</Card> </div> ); \`\`\``; } } else { response += `I didn't find specific components matching your question, but here are some general recommendations: - For **forms**: Use Input, Select, Button, Checkbox, Radio - For **data display**: Use Card, DataSize, DateFormat, Table components - For **navigation**: Use Menu, Breadcrumbs, Tabs - For **feedback**: Use Notification, Dialog, Badge - For **layout**: Use Stack, Card, Divider Would you like me to generate a specific example for any of these?`; } return { content: [{ type: "text", text: response }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } } ); // Tool 4: Component Documentation this.server.tool( "get_component_documentation", { componentName: z.string().describe("Name of the Reablocks component to get documentation for") }, async ({ componentName }) => { try { const component = ENHANCED_REABLOCKS_COMPONENTS[componentName]; if (!component) { const available = Object.keys(ENHANCED_REABLOCKS_COMPONENTS).join(', '); return { content: [{ type: "text", text: `Component "${componentName}" not found. Available components: ${available}` }] }; } const documentation = `# ${component.name} Documentation ## Overview ${component.description} **Category**: ${component.category} ## Props | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| ${component.props.map(prop => `| ${prop.name} | \`${prop.type}\` | ${prop.required ? '✅' : '❌'} | ${prop.defaultValue || '-'} | ${prop.description} |` ).join('\n')} ## Examples ${component.examples.map((example, i) => `### ${example.title} ${example.description} \`\`\`tsx ${example.code} \`\`\` `).join('\n')} ## Use Cases ${component.useCases.map(use => `- ${use}`).join('\n')} ## Related Components ${component.relatedComponents.map(comp => `- ${comp}`).join('\n')} ## Variants ${component.variants.map(variant => `- \`${variant}\``).join('\n')} --- *Part of the Reablocks component library*`; return { content: [{ type: "text", text: documentation }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } } ); // Tool 5: List All Components this.server.tool( "list_all_components", {}, async () => { try { const components = Object.values(ENHANCED_REABLOCKS_COMPONENTS); const byCategory = components.reduce((acc, comp) => { if (!acc[comp.category]) acc[comp.category] = []; acc[comp.category].push(comp); return acc; }, {} as Record<string, ComponentSchema[]>); let response = `# All Reablocks Components (${components.length} total)\n\n`; Object.entries(byCategory).forEach(([category, comps]) => { response += `## ${category} (${comps.length})\n\n`; comps.forEach(comp => { response += `### ${comp.name} ${comp.description} **Use for**: ${comp.useCases.slice(0, 2).join(', ')} `; }); }); response += `\n## Quick Usage Examples \`\`\`tsx // Basic button <Button color="primary">Click me</Button> // Form input <Input placeholder="Enter text" /> // Card container <Card> <h3>Title</h3> <p>Content</p> </Card> // Data display <DataSize value={1048576} /> // Shows "1 MB" // Layout stack <Stack spacing="lg"> <Button>First</Button> <Button>Second</Button> </Stack> \`\`\``; return { content: [{ type: "text", text: response }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } } ); // Tool 6: Get Examples and Learning Materials this.server.tool( "get_examples_and_tutorials", { type: z.enum(['all', 'prompts', 'components', 'patterns', 'getting-started']).optional().default('all'), skill_level: z.enum(['beginner', 'intermediate', 'advanced']).optional().default('beginner') }, async ({ type, skill_level }) => { try { let content = ''; if (type === 'all' || type === 'getting-started') { content += `# 🚀 Getting Started with Enhanced Reablocks MCP Server ## What is this MCP Server? This server helps you generate React components using Reablocks (a modern component library) through natural language. Just describe what you want, and get production-ready code! ## 🎯 Quick Start Examples ### 1. Your First Component Try this prompt: \`\`\` "Create a simple button that says Hello World" \`\`\` ### 2. Build a Contact Form Try this prompt: \`\`\` "I need a contact form with name, email, and message fields" \`\`\` ### 3. Create a Dashboard Try this prompt: \`\`\` "Generate a dashboard with user statistics and action buttons" \`\`\` --- `; } if (type === 'all' || type === 'prompts') { content += `# 💬 Example Prompts to Try ## 🔰 Beginner Prompts ${skill_level === 'beginner' ? '**👈 Perfect for you!**' : ''} ### Simple Components - "Create a blue button" - "Make an input field for email" - "Show me a card component" - "I need a simple form" ### Basic Layouts - "Create a form with two buttons" - "Make a card with a title and content" - "Show me a navigation menu" ## 🚀 Intermediate Prompts ${skill_level === 'intermediate' ? '**👈 Perfect for you!**' : ''} ### Forms and Validation - "Create a login form with email and password validation" - "I need a registration form with multiple fields and error handling" - "Build a contact form that shows success/error messages" ### Data Display - "Create a data table with search and sorting" - "Show me components for displaying file sizes and dates" - "I need a dashboard with metrics cards" ### Interactive Components - "Create a multi-step form with navigation" - "Build a sidebar with collapsible menu items" - "Make a modal dialog for editing user profiles" ## 🎖️ Advanced Prompts ${skill_level === 'advanced' ? '**👈 Perfect for you!**' : ''} ### Complex Dashboards - "Generate an admin dashboard with user management, analytics cards, and data tables with filtering" - "Create a project management dashboard with task lists, progress indicators, and team member avatars" - "Build a e-commerce admin panel with product listings, order management, and sales metrics" ### Specialized Components - "Create a file upload component with drag-and-drop, progress indicators, and file type validation" - "Build a data visualization dashboard with interactive charts and filtering controls" - "Generate a real-time messaging interface with user status, message history, and typing indicators" --- `; } if (type === 'all' || type === 'components') { content += `# 🧩 Component Discovery Examples ## Finding the Right Components ### By Purpose Ask: \`"What components should I use for..."\` - "...displaying user information?" → Avatar, Card, Badge - "...creating forms?" → Input, Select, Button, Checkbox - "...showing data?" → DataSize, DateFormat, Table components - "...navigation?" → Menu, Breadcrumbs, Tabs ### By Category Use: \`explore_reablocks_components\` tool - \`category: "Form"\` - All form-related components - \`category: "Layout"\` - Cards, Stack, Divider, etc. - \`category: "Data"\` - DataSize, Pager, Sort, etc. ### By Search Use: \`explore_reablocks_components\` tool - \`search: "button"\` - Finds Button, IconButton, etc. - \`search: "input"\` - Finds Input, Select, Textarea, etc. - \`search: "data"\` - Finds DataSize, DateFormat, etc. ## Component Documentation Get detailed info: \`get_component_documentation\` - \`componentName: "Button"\` - Complete Button documentation - \`componentName: "Input"\` - All Input props and examples - \`componentName: "Card"\` - Card usage patterns --- `; } if (type === 'all' || type === 'patterns') { content += `# 📋 Common UI Patterns ## Authentication Patterns ### Login Form \`\`\` "Create a login form with email, password, remember me checkbox, and forgot password link" \`\`\` ### Registration Form \`\`\` "Build a registration form with validation, terms agreement, and success confirmation" \`\`\` ## Dashboard Patterns ### Analytics Dashboard \`\`\` "Generate a dashboard with KPI cards, charts, recent activity table, and quick actions" \`\`\` ### Admin Panel \`\`\` "Create an admin panel with user management table, search, filters, and batch actions" \`\`\` ## Data Management Patterns ### CRUD Interface \`\`\` "Build a user management interface with create, edit, delete, and search functionality" \`\`\` ### Data Table \`\`\` "Create a data table with sorting, filtering, pagination, and row selection" \`\`\` ## Form Patterns ### Multi-Step Form \`\`\` "Create a multi-step checkout form with progress indicator and navigation" \`\`\` ### Dynamic Form \`\`\` "Build a form that adds/removes fields dynamically with validation" \`\`\` ## Layout Patterns ### Sidebar Layout \`\`\` "Create a layout with collapsible sidebar navigation and main content area" \`\`\` ### Card Grid \`\`\` "Generate a responsive grid of cards showing product information" \`\`\` --- `; } content += `# 🎓 Learning Tips ## Start Simple 1. Begin with single component requests 2. Gradually combine multiple components 3. Add complexity like validation and state management ## Experiment with Language - Be descriptive: "Create a blue primary button with large size" - Use UI terms: "dashboard", "form", "table", "navigation" - Specify requirements: "with validation", "responsive", "accessible" ## Iterate and Refine 1. Start with a basic prompt 2. Ask for specific modifications 3. Request additional features 4. Combine multiple components ## Get Help Anytime - \`ask_about_components\` - Ask questions in natural language - \`list_all_components\` - See everything available - \`get_component_documentation\` - Deep dive into specific components --- # 🎉 Ready to Start? Try your first prompt now! Here are some suggestions: **For Beginners:** - "Create a simple contact form" - "Show me a button with different colors" - "Make a card component with a title" **For Developers:** - "Generate a user dashboard with metrics" - "Create a data table with search functionality" - "Build a modal dialog for editing profiles" **For Designers:** - "Create a landing page hero section" - "Build a pricing table with feature comparison" - "Generate a testimonial card grid" Happy building! 🚀`; return { content: [{ type: "text", text: content }] }; } catch (error) { return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } } ); } } export default { fetch(request: Request, env: Env, ctx: ExecutionContext) { const url = new URL(request.url); if (url.pathname === "/sse" || url.pathname === "/sse/message") { return MyMCP.serveSSE("/sse").fetch(request, env, ctx); } if (url.pathname === "/mcp") { return MyMCP.serve("/mcp").fetch(request, env, ctx); } return new Response("Not found", { status: 404 }); }, };

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/qdhenry/reablocks-mcp-server-experiment'

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