Skip to main content
Glama

generate_system_flow

Auto-generate a Mermaid flowchart diagram of system module, class, and function connections. Understand project structure without reading every file by selecting scope: full, modules-only, or feature-focused.

Instructions

Auto-generate a Mermaid flowchart diagram showing how modules, classes, and functions connect in the system. Returns a Mermaid diagram string that AI can read to understand the full system flow without reading every file.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectNoProject name or path
scopeNoScope of the diagram: 'full' shows all entities, 'modules-only' shows only module relationships (recommended for large projects), 'feature' requires the 'feature' param
featureNoFeature keyword to focus the diagram on (e.g. 'auth', 'crawl', 'payment'). Only used when scope='feature'
maxNodesNoMaximum nodes in diagram (default: 60). Reduce for large projects

Implementation Reference

  • The main handler function for the 'generate_system_flow' tool. It loads analysis data, filters by scope (full/modules-only/feature), applies maxNodes limit, generates a Mermaid flowchart diagram string, and returns the result as JSON.
    // Tool 6: Generate System Flow — Auto-generate Mermaid diagram from code analysis
    server.tool(
      "generate_system_flow",
      "Auto-generate a Mermaid flowchart diagram showing how modules, classes, and functions connect in the system. Returns a Mermaid diagram string that AI can read to understand the full system flow without reading every file.",
      {
        project: z.string().optional().describe("Project name or path"),
        scope: z.enum(["full", "modules-only", "feature"]).optional().describe("Scope of the diagram: 'full' shows all entities, 'modules-only' shows only module relationships (recommended for large projects), 'feature' requires the 'feature' param"),
        feature: z.string().optional().describe("Feature keyword to focus the diagram on (e.g. 'auth', 'crawl', 'payment'). Only used when scope='feature'"),
        maxNodes: z.number().optional().describe("Maximum nodes in diagram (default: 60). Reduce for large projects"),
      },
      async ({ project, scope, feature, maxNodes }) => {
        const loaded = loadAnalysis(project);
        if (!loaded) {
          return { content: [{ type: "text" as const, text: "No analysis data found. Run 'CodeAtlas: Analyze Project' first." }] };
        }
    
        const max = maxNodes || 60;
        const diagramScope = scope || "modules-only";
        let nodes = loaded.analysis.graph.nodes;
        let links = loaded.analysis.graph.links;
        const nodeMap = new Map(nodes.map((n) => [n.id, n]));
    
        // Filter by scope
        if (diagramScope === "modules-only") {
          nodes = nodes.filter((n) => n.type === "module" && n.filePath);
          const nodeIds = new Set(nodes.map((n) => n.id));
          links = links.filter((l) => nodeIds.has(l.source) && nodeIds.has(l.target) && l.type === "import");
        } else if (diagramScope === "feature" && feature) {
          const q = feature.toLowerCase();
          // Find nodes matching the feature keyword
          const matchingNodes = new Set<string>();
          nodes.forEach((n) => {
            if (n.label.toLowerCase().includes(q) || (n.filePath && n.filePath.toLowerCase().includes(q))) {
              matchingNodes.add(n.id);
            }
          });
          // Expand to include connected nodes (1 hop)
          links.forEach((l) => {
            if (matchingNodes.has(l.source)) matchingNodes.add(l.target);
            if (matchingNodes.has(l.target)) matchingNodes.add(l.source);
          });
          nodes = nodes.filter((n) => matchingNodes.has(n.id));
          const nodeIds = new Set(nodes.map((n) => n.id));
          links = links.filter((l) => nodeIds.has(l.source) && nodeIds.has(l.target));
        }
    
        // Truncate if too many nodes
        if (nodes.length > max) {
          // Prioritize: modules > classes > functions > variables
          const priorityOrder = ["module", "class", "function", "variable"];
          nodes.sort((a, b) => {
            const ia = priorityOrder.indexOf(a.type);
            const ib = priorityOrder.indexOf(b.type);
            return (ia === -1 ? 99 : ia) - (ib === -1 ? 99 : ib);
          });
          nodes = nodes.slice(0, max);
        }
    
        const truncatedNodeIds = new Set(nodes.map((n) => n.id));
        links = links.filter((l) => truncatedNodeIds.has(l.source) && truncatedNodeIds.has(l.target));
    
        // Remove duplicate links
        const linkSet = new Set<string>();
        links = links.filter((l) => {
          const key = `${l.source}|${l.target}|${l.type}`;
          if (linkSet.has(key)) return false;
          linkSet.add(key);
          return true;
        });
    
        // Build Mermaid diagram
        const sanitize = (s: string) => s.replace(/[^a-zA-Z0-9_]/g, "_").substring(0, 40);
        const nodeIdMap = new Map<string, string>();
        let counter = 0;
    
        const getMermaidId = (nodeId: string) => {
          if (!nodeIdMap.has(nodeId)) {
            nodeIdMap.set(nodeId, `n${counter++}`);
          }
          return nodeIdMap.get(nodeId)!;
        };
    
        const lines: string[] = ["graph TD"];
    
        // Add node declarations
        for (const node of nodes) {
          const mid = getMermaidId(node.id);
          const label = node.label.replace(/"/g, "'");
          const typeIcon = node.type === "module" ? "📄" : node.type === "class" ? "🏗️" : node.type === "function" ? "⚡" : "📦";
          if (node.type === "module") {
            lines.push(`    ${mid}["${typeIcon} ${label}"]`);
          } else if (node.type === "class") {
            lines.push(`    ${mid}[["${typeIcon} ${label}"]]`);
          } else {
            lines.push(`    ${mid}("${typeIcon} ${label}")`);
          }
        }
    
        // Add link declarations
        const arrowMap: Record<string, string> = { import: "-->", call: "-.->", contains: "-->", implements: "-.->|implements|" };
        const labelMap: Record<string, string> = { import: "imports", call: "calls", contains: "contains", implements: "implements" };
        for (const link of links) {
          const src = getMermaidId(link.source);
          const tgt = getMermaidId(link.target);
          if (src && tgt) {
            const arrow = arrowMap[link.type] || "-->";
            if (link.type === "contains") {
              lines.push(`    ${src} ${arrow} ${tgt}`);
            } else {
              lines.push(`    ${src} ${arrow}|${labelMap[link.type] || link.type}| ${tgt}`);
            }
          }
        }
    
        const mermaid = lines.join("\n");
    
        const result = {
          project: loaded.projectName,
          scope: diagramScope,
          feature: feature || null,
          nodeCount: nodes.length,
          linkCount: links.length,
          truncated: loaded.analysis.graph.nodes.length > max,
          mermaidDiagram: mermaid,
          summary: `System flow for ${loaded.projectName}: ${nodes.filter((n) => n.type === "module").length} modules, ${nodes.filter((n) => n.type === "class").length} classes, ${nodes.filter((n) => n.type === "function").length} functions connected by ${links.length} relationships.`,
        };
    
        return { content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }] };
      }
    );
  • Input schema for generate_system_flow: accepts optional 'project' (string), 'scope' (enum of full/modules-only/feature), 'feature' (string), and 'maxNodes' (number, default 60).
    {
      project: z.string().optional().describe("Project name or path"),
      scope: z.enum(["full", "modules-only", "feature"]).optional().describe("Scope of the diagram: 'full' shows all entities, 'modules-only' shows only module relationships (recommended for large projects), 'feature' requires the 'feature' param"),
      feature: z.string().optional().describe("Feature keyword to focus the diagram on (e.g. 'auth', 'crawl', 'payment'). Only used when scope='feature'"),
      maxNodes: z.number().optional().describe("Maximum nodes in diagram (default: 60). Reduce for large projects"),
    },
  • index.ts:384-385 (registration)
    Registration of the tool with the MCP server via server.tool('generate_system_flow', ...).
    server.tool(
      "generate_system_flow",
  • The loadAnalysis helper function used by generate_system_flow to read analysis data from .codeatlas/analysis.json.
    function loadAnalysis(projectDir?: string): { analysis: AnalysisResult; projectName: string; projectDir: string } | null {
      const projects = discoverProjects();
      if (projects.length === 0) return null;
    
      let target = projects[0]; // default: most recently modified
    
      if (projectDir) {
        const match = projects.find(
          (p) => p.dir === projectDir || p.name.toLowerCase() === projectDir.toLowerCase()
        );
        if (match) target = match;
      }
    
      try {
        const data = fs.readFileSync(target.analysisPath, "utf-8");
        return { analysis: JSON.parse(data), projectName: target.name, projectDir: target.dir };
      } catch (e) {
        console.error(`[CodeAtlas] ERROR: Failed to parse analysis file at ${target.analysisPath}: ${e}`);
        return null;
      }
    }
  • The AnalysisResult interface defining the shape of graph data (nodes and links) consumed by generate_system_flow.
    interface AnalysisResult {
      graph: { nodes: GraphNode[]; links: GraphLink[] };
      insights: any[];
      stats?: { files: number; functions: number; classes: number; dependencies: number; circularDeps: number };
      entityCounts?: { modules: number; functions: number; classes: number; dependencies: number; circularDeps: number };
      totalFilesAnalyzed?: number;
      totalFilesSkipped?: number;
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must disclose behavioral traits. It states the tool is auto-generating and returns a diagram string, but lacks details on whether it is read-only, performance implications, accuracy, or limitations (e.g., dynamic connections). The basic behavior is conveyed, but not comprehensively.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description consists of two concise sentences that front-load the core purpose and output. It is efficient with no wasted words, though a slightly more structured breakdown of when each scope is appropriate could improve comprehension.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 4 well-documented parameters and no output schema, the description is adequate for basic usage but lacks critical guidance on sibling tool differentiation and behavioral context (e.g., read-only nature). It is incomplete for nuanced decision-making.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% description coverage for all 4 parameters, so the schema already explains them adequately. The description adds no additional meaning beyond what the schema provides, meeting the baseline for high coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool auto-generates a Mermaid flowchart showing module/class/function connections, specifying the output type. However, it does not explicitly differentiate from sibling 'generate_feature_flow_diagram', relying on the name and scope inference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use for understanding system flow without reading files, but gives no explicit guidance on when to use this vs. alternatives like 'generate_feature_flow_diagram' or 'get_dependencies'. No exclusion criteria or prerequisites are mentioned.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other 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/giauphan/codeatlas-mcp'

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