UNPKG

@yeepay/awesome-components-mcp

Version:

MCP server providing access to awesome-components documentation and integration guides with dual-mode operation: direct fetch and GitLab MCP instruction generation

221 lines (184 loc) 6.49 kB
/** * Components Discovery MCP Tool * * This tool discovers and categorizes all available components from the main llms.txt file. * It supports multiple output formats: raw, parsed, and summary. */ import { z } from 'zod'; import { config } from '../config.js'; import { fetchGitLabFileContentSafe, GitLabError } from '../services/gitlabClient.js'; /** * Schema for components discovery tool parameters */ export const componentsDiscoverySchema = z.object({}); export type ComponentsDiscoveryParams = z.infer<typeof componentsDiscoverySchema>; /** * Interface for parsed component information */ interface ParsedComponent { name: string; type: 'component' | 'guide' | 'documentation' | 'tutorial' | 'other'; path: string; } /** * Interface for parsed components data */ interface ParsedComponentsData { totalComponents: number; componentsByType: Record<string, number>; components: ParsedComponent[]; } /** * Parses llms.txt content and categorizes components */ function parseComponentsContent(content: string): ParsedComponentsData { const lines = content.split('\n') .map(line => line.trim()) .filter(line => line && !line.startsWith('#') && !line.startsWith('//')); const components: ParsedComponent[] = lines.map(line => { const name = line.split('/').pop() || line; let type: ParsedComponent['type'] = 'other'; if (line.includes('/guide') || line.startsWith('guide/')) { type = 'guide'; } else if (line.includes('/docs') || line.includes('/documentation') || line.endsWith('.md')) { type = 'documentation'; } else if (line.includes('/tutorial') || line.startsWith('tutorial/')) { type = 'tutorial'; } else if (!line.includes('/') || line.split('/').length <= 2) { type = 'component'; } return { name, type, path: line }; }); const componentsByType: Record<string, number> = {}; components.forEach(comp => { componentsByType[comp.type] = (componentsByType[comp.type] || 0) + 1; }); return { totalComponents: components.length, componentsByType, components }; } /** * Formats content as JSON data */ function formatOutput(content: string, sourceUrl?: string): string { const source = sourceUrl || config.llmsTxtUrl || config.urls.mainLlms; const parsed = parseComponentsContent(content); // Always return JSON format return JSON.stringify({ source, totalComponents: parsed.totalComponents, componentsByType: parsed.componentsByType, components: parsed.components }, null, 2); } /** * Interface for gitlab-mcp instruction */ interface GitLabMcpInstruction { action_type: 'mcp_call'; tool_name: string; parameters: { project_id: string; file_path: string; ref: string; }; } /** * Components Discovery MCP Tool Implementation */ export async function componentsDiscoveryTool(): Promise<{ content: Array<{ type: 'text'; text: string }>; isError?: boolean }> { try { // Mode 1: Direct fetch mode (when LLMS_TXT_URL is configured) if (config.llmsTxtUrl) { console.log(`Fetching components list from: ${config.llmsTxtUrl}`); // Fetch content from the configured URL const content = await fetchGitLabFileContentSafe(config.llmsTxtUrl); // Format the output as JSON const formattedOutput = formatOutput(content, config.llmsTxtUrl); return { content: [{ type: 'text', text: formattedOutput }] }; } // Mode 2: gitlab-mcp instruction mode (when GITLAB_PROJECT_ID and LLMS_TXT_FILE are configured) if (config.llmsTxtProjectId) { console.log(`Generating gitlab-mcp instruction for project: ${config.llmsTxtProjectId}, file: ${config.llmsTxtFile}`); // Generate JSON instruction for LLM to call gitlab-mcp const instruction: GitLabMcpInstruction = { action_type: 'mcp_call', tool_name: 'get_file_contents', parameters: { project_id: config.llmsTxtProjectId, // Already URL-encoded as per PRD file_path: config.llmsTxtFile, ref: 'main' // Default branch } }; const instructionOutput = `# Components Discovery - GitLab MCP Instruction To retrieve the components list, please call the gitlab-mcp server with the following instruction: \`\`\`json ${JSON.stringify(instruction, null, 2)} \`\`\` **Instructions for LLM:** 1. Use the above JSON instruction to call the gitlab-mcp server 2. Call the \`get_file_contents\` tool with the provided parameters 3. The response will contain the components list (llms.txt content) **Configuration:** - Project ID: \`${config.llmsTxtProjectId}\` - File Path: \`${config.llmsTxtFile}\` - Branch: \`main\``; return { content: [{ type: 'text', text: instructionOutput }] }; } // Configuration error: neither mode is properly configured throw new Error('Configuration error: Either LLMS_TXT_URL or both GITLAB_PROJECT_ID and LLMS_TXT_FILE must be configured'); } catch (error) { console.error('Components discovery failed:', error); let errorMessage = 'Unknown error occurred'; let statusInfo = ''; if (error instanceof GitLabError) { errorMessage = `GitLab Error: ${error.message}`; if (error.statusCode) { statusInfo = `\n**Status Code:** ${error.statusCode}`; } if (error.url) { statusInfo += `\n**URL:** ${error.url}`; } } else if (error instanceof Error) { errorMessage = `Error: ${error.message}`; } else { errorMessage = `Error: ${String(error)}`; } const errorResponse = `# Error: Components Discovery Failed ${errorMessage}${statusInfo} **Suggestions:** - Check your network connection - Verify the GitLab URL is accessible: ${config.llmsTxtUrl || config.urls.mainLlms} - Ensure you have proper authentication if the repository is private - Check if the llms.txt file exists at the specified location **Configuration:** - Mode: ${config.llmsTxtUrl ? 'Direct fetch' : 'GitLab MCP instruction'} - LLMS_TXT_URL: ${config.llmsTxtUrl || 'Not configured'} - GITLAB_PROJECT_ID: ${config.llmsTxtProjectId || 'Not configured'} - LLMS_TXT_FILE: ${config.llmsTxtFile || 'Not configured'} - Authentication: ${config.auth.gitlabToken ? 'Configured' : 'Not configured'}`; return { content: [{ type: 'text', text: errorResponse }], isError: true }; } }