Skip to main content
Glama
umshere
by umshere

generate_ui_flow

Create UI flow diagrams by scanning React/Angular repositories. Analyzes codebases to map components, relationships, and UI structure for local or GitHub repositories.

Instructions

Generate a UI flow diagram by analyzing React/Angular repositories. This tool scans the codebase to identify components, their relationships, and the overall UI structure.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
fileExtensionsNoList of file extensions to analyze (e.g., ['js', 'jsx', 'ts', 'tsx'] for React, ['ts', 'html'] for Angular)
isLocalYesWhether to analyze a local repository (true) or GitHub repository (false)
ownerNoGitHub repository owner (required if isLocal is false)
repoNoGitHub repository name (required if isLocal is false)
repoPathYesPath to local repository or empty string for GitHub repos

Implementation Reference

  • Main execution logic for the generate_ui_flow tool within the CallToolRequestSchema handler.
    if (request.params.name !== "generate_ui_flow") { throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}` ); } const args = request.params.arguments as { repoPath: string; isLocal: boolean; owner?: string; repo?: string; fileExtensions?: string[]; }; const { repoPath, isLocal, owner, repo, fileExtensions } = args; try { let contents: RepoContents[]; if (isLocal) { contents = await fetchLocalRepoContents(repoPath); } else { if (!owner || !repo) { throw new McpError( ErrorCode.InvalidParams, "Owner and repo are required for GitHub repositories" ); } contents = await fetchGitHubRepoContents(owner, repo); } const components = await parseUIFlow(contents, isLocal, fileExtensions); const mermaidChart = generateMermaidFlowchart(JSON.parse(components)); // Determine output path based on repository type const outputPath = isLocal ? path.join(repoPath, "userflo.md") : path.join(process.cwd(), "userflo.md"); const flowDescription = `# UI Flow Diagram\n\nThis document describes the UI flow of the application.\n\n`; const fullContent = flowDescription + "```mermaid\n" + mermaidChart + "\n```\n\n"; await fs.writeFile(outputPath, fullContent); console.log(`[MCP] UI flow saved to ${outputPath}`); return { content: [ { type: "text", text: mermaidChart, }, ], }; } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Failed to generate UI flow: ${ error instanceof Error ? error.message : String(error) }` ); }
  • Input schema definition for the generate_ui_flow tool.
    inputSchema: { type: "object", properties: { repoPath: { type: "string", description: "Path to local repository or empty string for GitHub repos", }, isLocal: { type: "boolean", description: "Whether to analyze a local repository (true) or GitHub repository (false)", }, owner: { type: "string", description: "GitHub repository owner (required if isLocal is false)", }, repo: { type: "string", description: "GitHub repository name (required if isLocal is false)", }, fileExtensions: { type: "array", items: { type: "string" }, description: "List of file extensions to analyze (e.g., ['js', 'jsx', 'ts', 'tsx'] for React, ['ts', 'html'] for Angular)", default: ["js", "jsx", "ts", "tsx"], }, }, required: ["repoPath", "isLocal"], additionalProperties: false, },
  • src/index.ts:34-73 (registration)
    Tool registration in server capabilities.
    generate_ui_flow: { name: "generate_ui_flow", description: "Generate a UI flow diagram by analyzing React/Angular repositories. This tool scans the codebase to identify components, their relationships, and the overall UI structure.", inputSchema: { type: "object", properties: { repoPath: { type: "string", description: "Path to local repository or empty string for GitHub repos", }, isLocal: { type: "boolean", description: "Whether to analyze a local repository (true) or GitHub repository (false)", }, owner: { type: "string", description: "GitHub repository owner (required if isLocal is false)", }, repo: { type: "string", description: "GitHub repository name (required if isLocal is false)", }, fileExtensions: { type: "array", items: { type: "string" }, description: "List of file extensions to analyze (e.g., ['js', 'jsx', 'ts', 'tsx'] for React, ['ts', 'html'] for Angular)", default: ["js", "jsx", "ts", "tsx"], }, }, required: ["repoPath", "isLocal"], additionalProperties: false, }, }, },
  • Core helper function that parses repository contents to extract UI component hierarchy and relationships.
    export async function parseUIFlow( contents: RepoContents[], isLocal: boolean, fileExtensions: string[] = ["js", "jsx", "ts", "tsx"] ): Promise<string> { console.log( `[MCP] Parsing UI flow with extensions: ${fileExtensions.join(", ")}` ); const components: { [key: string]: ComponentInfo } = {}; async function processContents( currentContents: RepoContents[], currentPath: string = "" ) { for (const item of currentContents) { if ( item.type === "file" && fileExtensions.some((ext) => item.name.endsWith(`.${ext}`)) ) { let content: string; if (isLocal) { content = item.content || ""; } else { try { const response = await axios.get(item.download_url || ""); content = response.data; } catch (error) { console.warn( `[MCP] Failed to fetch content for ${item.name}: ${error}` ); continue; } } const componentName = item.name.split(".")[0]; const componentPath = path.join(currentPath, componentName); const componentType = getComponentType(componentPath); components[componentPath] = { name: componentName, type: componentType, filePath: path.join(currentPath, item.name), imports: [], children: [], }; // Analyze import statements const importMatches = content.match( /import\s+(\w+|\{[^}]+\})\s+from\s+['"]([^'"]+)['"]/g ); if (importMatches) { importMatches.forEach((match) => { const [, importedComponent, importPath] = match.match( /import\s+(\w+|\{[^}]+\})\s+from\s+['"]([^'"]+)['"]/ ) || []; if (importedComponent) { const cleanedImport = importedComponent .replace(/[{}]/g, "") .trim(); const resolvedPath = path.join( currentPath, path.dirname(importPath), cleanedImport ); components[componentPath].imports.push(resolvedPath); } }); } } else if (item.type === "dir") { const subContents = isLocal ? await fetchLocalRepoContents(item.path) : await fetchGitHubRepoContents( item.owner || "", item.repo || "", item.path ); await processContents(subContents, path.join(currentPath, item.name)); } } } await processContents(contents); // Build component hierarchy const rootComponents: ComponentInfo[] = []; Object.values(components).forEach((component) => { component.imports.forEach((importPath) => { if (components[importPath]) { components[importPath].children.push(component); } }); if (component.imports.length === 0) { rootComponents.push(component); } }); return JSON.stringify(rootComponents, null, 2); }
  • Helper function that generates Mermaid flowchart syntax from parsed UI components.
    export function generateMermaidFlowchart(components: ComponentInfo[]): string { let chart = "flowchart TD\n"; // Create a map of all components for quick lookup const componentMap = new Map<string, ComponentInfo>(); components.forEach((component) => { componentMap.set(component.name, component); }); // Create nodes with proper styling and hierarchy const createNode = (component: ComponentInfo, depth: number = 0): string => { const nodeId = component.name.replace(/[^a-zA-Z0-9]/g, "_"); const indent = " ".repeat(depth); // Determine node style based on type let nodeStyle = ""; switch (component.type) { case "page": nodeStyle = "(( ))"; break; case "layout": nodeStyle = "{{ }}"; break; default: nodeStyle = "[/ /]"; } // Add node with proper indentation chart += `${indent}${nodeId}${nodeStyle}["${component.name} (${component.type})"]\n`; // Recursively process children component.children.forEach((child) => { const childComponent = componentMap.get(child.name); if (childComponent) { createNode(childComponent, depth + 1); } }); return nodeId; }; // Find root components (those with no parents) const rootComponents = components.filter( (component) => !components.some((c) => c.children.some((child) => child.name === component.name) ) ); // Start building the chart from root components rootComponents.forEach((component) => { createNode(component); }); // Create relationships with labels components.forEach((component) => { const parentId = component.name.replace(/[^a-zA-Z0-9]/g, "_"); component.children.forEach((child) => { const childId = child.name.replace(/[^a-zA-Z0-9]/g, "_"); const relationshipType = determineRelationshipType(component, child); chart += ` ${parentId} -->|${relationshipType}| ${childId}\n`; }); }); // Validate Mermaid.js syntax try { // Basic validation - check for required elements if (!chart.includes("flowchart TD")) { throw new Error("Missing flowchart declaration"); } if (!chart.match(/\[.*\]/)) { throw new Error("Missing node definitions"); } if (!chart.match(/-->|--/)) { throw new Error("Missing relationship definitions"); } } catch (error) { console.error("[MCP] Mermaid.js validation error:", error); throw new McpError( ErrorCode.InternalError, `Failed to generate valid Mermaid.js chart: ${error}` ); } return chart; }

Other Tools

Related Tools

Latest Blog Posts

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/umshere/uiflowchartcreator'

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