UNPKG

templui-mcp-server

Version:

A Model Context Protocol (MCP) server for TemplUI components, providing AI assistants with access to component source code, documentation, demos, and metadata.

166 lines 7.59 kB
import { TEMPLUI_COMPONENTS, getComponentsByCategory } from '../data/components-list.js'; import { cache } from '../utils/cache.js'; import { logError, logInfo, logDebug } from '../utils/logger.js'; // Dynamic imports for GitHub integration let githubClient = null; let updater = null; // Initialize GitHub integration export function initializeGitHubIntegration(client, updateService) { githubClient = client; updater = updateService; } export async function handleListComponents({ category, useDynamic } = {}) { try { logInfo(`Listing components${category ? ` in category: ${category}` : ''}${useDynamic ? ' (dynamic mode)' : ''}`); // Create cache key const cacheKey = `list-components:${category || 'all'}${useDynamic ? ':dynamic' : ''}`; const cached = await cache.get(cacheKey); if (cached) { logInfo(`Returning cached component list`); return { content: [{ type: "text", text: cached }] }; } let components; let isDynamicData = false; // Try to use dynamic GitHub data if available and requested if (useDynamic && githubClient) { try { logDebug('Attempting to fetch components dynamically from GitHub'); const dynamicComponents = await githubClient.getComponentsFromRepository(); // Convert GitHub data to component format components = dynamicComponents.map((comp) => ({ name: comp.name, displayName: comp.name.charAt(0).toUpperCase() + comp.name.slice(1), description: `Component dynamically discovered from TemplUI repository`, category: 'dynamic', hasJavaScript: false, // Will be determined when component is accessed installCommand: `Add ${comp.name} component to your project` })); // Filter by category if specified (though dynamic components don't have categories yet) if (category && category !== 'dynamic') { components = []; } isDynamicData = true; logInfo(`Successfully fetched ${components.length} components dynamically from GitHub`); } catch (error) { logDebug(`Dynamic fetch failed, falling back to static data: ${error instanceof Error ? error.message : String(error)}`); // Fall back to static data components = category ? getComponentsByCategory(category) : TEMPLUI_COMPONENTS; } } else { // Use static component data components = category ? getComponentsByCategory(category) : TEMPLUI_COMPONENTS; } if (components.length === 0) { const message = category ? `No components found in category "${category}"` : 'No components found'; return { content: [{ type: "text", text: message }] }; } // Format the components list const formattedList = formatComponentsList(components, category, isDynamicData); // Cache the result with shorter TTL for dynamic data const cacheTTL = isDynamicData ? 1800 : undefined; // 30 minutes for dynamic data await cache.set(cacheKey, formattedList, cacheTTL); logInfo(`Successfully listed ${components.length} components`); return { content: [{ type: "text", text: formattedList }] }; } catch (error) { logError(`Failed to list components`, error); throw new Error(`Failed to list components: ${error instanceof Error ? error.message : String(error)}`); } } function formatComponentsList(components, category, isDynamic) { const sections = []; // Header if (category) { sections.push(`# TemplUI Components - ${category.charAt(0).toUpperCase() + category.slice(1)} Category`); } else { sections.push('# TemplUI Components'); } if (isDynamic) { sections.push('*Dynamically discovered from GitHub repository*'); } sections.push(''); sections.push(`Found ${components.length} component${components.length === 1 ? '' : 's'}`); sections.push(''); // Group by category if showing all components if (!category) { const grouped = components.reduce((acc, component) => { if (!acc[component.category]) { acc[component.category] = []; } acc[component.category].push(component); return acc; }, {}); Object.entries(grouped).forEach(([cat, comps]) => { sections.push(`## ${cat.charAt(0).toUpperCase() + cat.slice(1)} (${comps.length})`); sections.push(''); comps.forEach((component) => { sections.push(`### ${component.displayName}`); sections.push(`- **Name**: \`${component.name}\``); sections.push(`- **Description**: ${component.description}`); sections.push(`- **JavaScript**: ${component.hasJavaScript ? 'Yes' : 'No'}`); sections.push(`- **Install**: \`${component.installCommand}\``); sections.push(''); }); }); } else { // List components in the specified category components.forEach(component => { sections.push(`## ${component.displayName}`); sections.push(`- **Name**: \`${component.name}\``); sections.push(`- **Description**: ${component.description}`); sections.push(`- **JavaScript**: ${component.hasJavaScript ? 'Yes' : 'No'}`); sections.push(`- **Install**: \`${component.installCommand}\``); sections.push(''); }); } // Usage instructions sections.push('---'); sections.push(''); sections.push('## Usage'); sections.push(''); sections.push('To get more information about a specific component, use:'); sections.push('- `get_component` - Get the source code'); sections.push('- `get_component_docs` - Get documentation'); sections.push('- `get_component_demo` - Get example usage'); sections.push('- `get_component_metadata` - Get detailed metadata'); sections.push('- `get_component_javascript` - Get JavaScript code (if available)'); sections.push(''); // Categories summary if (!category) { const categories = [...new Set(components.map(c => c.category))].sort(); sections.push('## Available Categories'); sections.push(''); categories.forEach(cat => { const count = components.filter(c => c.category === cat).length; sections.push(`- **${cat}**: ${count} component${count === 1 ? '' : 's'}`); }); sections.push(''); } sections.push('*Visit [templui.io](https://templui.io) for complete documentation and live examples.*'); return sections.join('\n'); } export const schema = { category: { type: 'string', description: 'Optional category to filter components (form, layout, navigation, overlay, feedback, display, dynamic)', enum: ['form', 'layout', 'navigation', 'overlay', 'feedback', 'display', 'dynamic'] }, useDynamic: { type: 'boolean', description: 'Use dynamic component discovery from GitHub repository (may be slower but always up-to-date)', default: false } }; //# sourceMappingURL=list-components.js.map