Skip to main content
Glama

flowzap_artifact_to_diagram

Convert HTTP logs, OpenAPI specs, and code snippets into visual workflow or sequence diagrams to explain and refine technical processes.

Instructions

Parse real artifacts (HTTP logs, OpenAPI specs, code snippets) into FlowZap Code diagrams. Use this to convert raw technical data into visual workflows that can be explained and refined.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
artifactTypeYesType of artifact: http_logs (request/response sequences), openapi (API specs), code (function call traces)
contentYesRaw artifact content to parse
viewNoPreferred diagram view (default: sequence for logs, workflow for openapi)

Implementation Reference

  • Main handler function that validates inputs, routes to appropriate parser based on artifactType (http_logs, openapi, code), creates playground URL, and returns the result
    export async function handleArtifactToDiagram(
      artifactType: unknown,
      content: unknown,
      view?: unknown
    ): Promise<string> {
      // Validate inputs
      if (typeof artifactType !== "string") {
        return JSON.stringify({
          success: false,
          error: "artifactType must be a string",
        });
      }
    
      if (!["http_logs", "openapi", "code"].includes(artifactType)) {
        return JSON.stringify({
          success: false,
          error: `Invalid artifactType "${artifactType}". Must be one of: http_logs, openapi, code`,
        });
      }
    
      if (typeof content !== "string") {
        return JSON.stringify({
          success: false,
          error: "content must be a string",
        });
      }
    
      if (content.trim().length === 0) {
        return JSON.stringify({
          success: false,
          error: "content cannot be empty",
        });
      }
    
      if (content.length > 100000) {
        return JSON.stringify({
          success: false,
          error: "content exceeds maximum length of 100,000 characters",
        });
      }
    
      try {
        let result: ParsedArtifact;
    
        switch (artifactType) {
          case "http_logs":
            result = parseHttpLogs(content);
            break;
          case "openapi":
            result = parseOpenAPI(content);
            break;
          case "code":
            result = parseCode(content);
            break;
          default:
            return JSON.stringify({
              success: false,
              error: `Unsupported artifact type: ${artifactType}`,
            });
        }
    
        // Override view if specified
        if (view === "workflow" || view === "sequence") {
          result.view = view;
        }
    
        // Auto-create playground URL
        const playground = await createPlaygroundUrl(result.code);
    
        return JSON.stringify({
          success: true,
          code: result.code,
          url: playground.url || null,
          view: result.view,
          notes: result.notes,
          stats: {
            actors: result.actors,
            stepCount: result.stepCount,
          },
          ...(playground.error && { playgroundError: playground.error }),
        }, null, 2);
      } catch (error) {
        return JSON.stringify({
          success: false,
          error: `Failed to parse artifact: ${error instanceof Error ? error.message : String(error)}`,
        });
      }
    }
  • Tool schema definition with name, description, and inputSchema defining artifactType (enum: http_logs, openapi, code), content (string), and optional view (enum: workflow, sequence)
    export const artifactToDiagramTool: Tool = {
      name: "flowzap_artifact_to_diagram",
      description:
        "Parse real artifacts (HTTP logs, OpenAPI specs, code snippets) into FlowZap Code diagrams. Use this to convert raw technical data into visual workflows that can be explained and refined.",
      inputSchema: {
        type: "object" as const,
        properties: {
          artifactType: {
            type: "string",
            enum: ["http_logs", "openapi", "code"],
            description: "Type of artifact: http_logs (request/response sequences), openapi (API specs), code (function call traces)",
          },
          content: {
            type: "string",
            description: "Raw artifact content to parse",
          },
          view: {
            type: "string",
            enum: ["workflow", "sequence"],
            description: "Preferred diagram view (default: sequence for logs, workflow for openapi)",
          },
        },
        required: ["artifactType", "content"],
      },
    };
  • Parses HTTP logs into FlowZap Code - handles Apache/Nginx logs, simple request/response pairs, and HAR-like JSON, extracting actors and steps for sequence diagrams
    function parseHttpLogs(content: string): ParsedArtifact {
      const lines = content.split("\n").filter((l) => l.trim());
      const actors = new Set<string>(["Client"]);
      const steps: Array<{ from: string; to: string; label: string }> = [];
    
      // Try to detect format
      let nodeId = 1;
    
      // Pattern 1: Simple "METHOD URL -> STATUS" or "CLIENT -> SERVER: MESSAGE"
      const simplePattern = /^(\w+)?\s*(?:->|→)\s*(\w+)(?:\s*:\s*(.+))?$/;
      const httpPattern = /^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(\S+)(?:\s+(\d{3}))?/i;
      const responsePattern = /^(\d{3})\s+(.+)/;
    
      let currentServer = "Server";
    
      for (const line of lines) {
        const trimmed = line.trim();
        if (!trimmed) continue;
    
        // Try HTTP method pattern
        const httpMatch = trimmed.match(httpPattern);
        if (httpMatch) {
          const [, method, path, status] = httpMatch;
          
          // Extract server from path if it's a full URL
          try {
            const url = new URL(path.startsWith("http") ? path : `https://example.com${path}`);
            currentServer = url.hostname.split(".")[0] || "Server";
          } catch {
            // Keep current server
          }
          
          actors.add(currentServer);
          
          // Request
          steps.push({
            from: "Client",
            to: currentServer,
            label: `${method} ${path.length > 30 ? path.substring(0, 30) + "..." : path}`,
          });
    
          // Response if status included
          if (status) {
            steps.push({
              from: currentServer,
              to: "Client",
              label: `${status} Response`,
            });
          }
          continue;
        }
    
        // Try simple arrow pattern
        const simpleMatch = trimmed.match(simplePattern);
        if (simpleMatch) {
          const [, from = "Client", to, message = "Request"] = simpleMatch;
          actors.add(from);
          actors.add(to);
          steps.push({ from, to, label: message });
          continue;
        }
    
        // Try response pattern (just status code)
        const responseMatch = trimmed.match(responsePattern);
        if (responseMatch && steps.length > 0) {
          const lastStep = steps[steps.length - 1];
          steps.push({
            from: lastStep.to,
            to: lastStep.from,
            label: `${responseMatch[1]} ${responseMatch[2]}`,
          });
        }
      }
    
      // If no steps parsed, create a placeholder
      if (steps.length === 0) {
        return {
          code: `client {\n  # Client\n  n1: circle label:"No parseable requests found"\n}`,
          view: "sequence",
          notes: "Could not parse HTTP log format. Try a simpler format like 'GET /api/users 200' or 'Client -> Server: Request'",
          actors: ["Client"],
          stepCount: 0,
        };
      }
    
      // Generate FlowZap Code
      const actorList = Array.from(actors);
      const laneNodes = new Map<string, string[]>();
      const allEdges: string[] = [];
    
      // Initialize lanes
      for (const actor of actorList) {
        laneNodes.set(actor, []);
      }
    
      // Create nodes and edges
      for (const step of steps) {
        const fromLane = step.from;
        const toLane = step.to;
        
        // Create source node if this is first action from this actor
        const fromNodes = laneNodes.get(fromLane) || [];
        let fromNodeId: string;
        
        if (fromNodes.length === 0) {
          fromNodeId = `n${nodeId++}`;
          fromNodes.push(`  ${fromNodeId}: rectangle label:"${escapeLabel(step.label)}"`);
          laneNodes.set(fromLane, fromNodes);
        } else {
          // Use last node as source
          const lastNode = fromNodes[fromNodes.length - 1];
          const match = lastNode.match(/^\s*(n\d+):/);
          fromNodeId = match ? match[1] : `n${nodeId++}`;
        }
    
        // Create target node
        const toNodes = laneNodes.get(toLane) || [];
        const toNodeId = `n${nodeId++}`;
        toNodes.push(`  ${toNodeId}: rectangle label:"${escapeLabel(step.label)}"`);
        laneNodes.set(toLane, toNodes);
    
        // Create edge
        if (fromLane === toLane) {
          allEdges.push(`  ${fromNodeId}.handle(right) -> ${toNodeId}.handle(left)`);
        } else {
          allEdges.push(`  ${fromNodeId}.handle(bottom) -> ${toLane.toLowerCase().replace(/\s+/g, "")}.${toNodeId}.handle(top) [label="${escapeLabel(step.label)}"]`);
        }
      }
    
      // Build code
      let code = "";
      for (const [actor, nodes] of laneNodes) {
        const laneId = actor.toLowerCase().replace(/\s+/g, "");
        code += `${laneId} {\n  # ${actor}\n`;
        code += nodes.join("\n") + "\n";
        
        // Add edges that originate from this lane
        const laneEdges = allEdges.filter((e) => e.includes(`${laneId}.`) || e.match(new RegExp(`^\\s*n\\d+\\.handle`)));
        if (laneEdges.length > 0) {
          code += laneEdges.join("\n") + "\n";
        }
        
        code += "}\n\n";
      }
    
      return {
        code: code.trim(),
        view: "sequence",
        notes: `Inferred ${actorList.length} actors and ${steps.length} steps from HTTP logs`,
        actors: actorList,
        stepCount: steps.length,
      };
    }
  • Parses OpenAPI specs (JSON/YAML) into FlowZap Code workflow diagrams, extracting API endpoints and generating node/edge connections
    function parseOpenAPI(content: string): ParsedArtifact {
      let spec: any;
      
      try {
        spec = JSON.parse(content);
      } catch {
        // Try YAML-like parsing (basic)
        try {
          // Very basic YAML parsing for common patterns
          const lines = content.split("\n");
          spec = { paths: {}, info: { title: "API" } };
          let currentPath = "";
          let currentMethod = "";
          
          for (const line of lines) {
            const pathMatch = line.match(/^\/[\w\-\/{}]+:/);
            if (pathMatch) {
              currentPath = pathMatch[0].replace(":", "");
              spec.paths[currentPath] = {};
            }
            const methodMatch = line.match(/^\s+(get|post|put|delete|patch):/i);
            if (methodMatch && currentPath) {
              currentMethod = methodMatch[1].toLowerCase();
              spec.paths[currentPath][currentMethod] = { summary: "" };
            }
            const summaryMatch = line.match(/^\s+summary:\s*(.+)/);
            if (summaryMatch && currentPath && currentMethod) {
              spec.paths[currentPath][currentMethod].summary = summaryMatch[1].trim().replace(/^["']|["']$/g, "");
            }
          }
        } catch {
          return {
            code: `api {\n  # API\n  n1: circle label:"Could not parse OpenAPI spec"\n}`,
            view: "workflow",
            notes: "Failed to parse OpenAPI content. Ensure it's valid JSON or YAML.",
            actors: ["API"],
            stepCount: 0,
          };
        }
      }
    
      const paths = spec.paths || {};
      const title = spec.info?.title || "API";
      const actors = new Set<string>(["Client", title]);
      const steps: Array<{ method: string; path: string; summary: string }> = [];
    
      // Extract endpoints
      for (const [path, methods] of Object.entries(paths)) {
        if (typeof methods !== "object" || methods === null) continue;
        
        for (const [method, details] of Object.entries(methods as Record<string, any>)) {
          if (!["get", "post", "put", "delete", "patch"].includes(method.toLowerCase())) continue;
          
          const summary = details?.summary || details?.operationId || `${method.toUpperCase()} ${path}`;
          steps.push({
            method: method.toUpperCase(),
            path,
            summary: String(summary),
          });
        }
      }
    
      if (steps.length === 0) {
        return {
          code: `api {\n  # ${title}\n  n1: circle label:"No endpoints found"\n}`,
          view: "workflow",
          notes: "No API endpoints found in the OpenAPI spec.",
          actors: [title],
          stepCount: 0,
        };
      }
    
      // Generate workflow diagram
      const apiLaneId = title.toLowerCase().replace(/\s+/g, "").replace(/[^a-z0-9]/g, "");
      let code = `client {\n  # Client\n  n1: circle label:"Start"\n}\n\n`;
      code += `${apiLaneId} {\n  # ${title}\n`;
    
      let nodeId = 2;
      const nodeIds: string[] = [];
    
      for (const step of steps) {
        const label = step.summary.length > 40 ? step.summary.substring(0, 40) + "..." : step.summary;
        code += `  n${nodeId}: rectangle label:"${escapeLabel(label)}"\n`;
        nodeIds.push(`n${nodeId}`);
        nodeId++;
      }
    
      // Add edges between consecutive endpoints
      for (let i = 0; i < nodeIds.length - 1; i++) {
        code += `  ${nodeIds[i]}.handle(right) -> ${nodeIds[i + 1]}.handle(left)\n`;
      }
    
      // Add end node
      code += `  n${nodeId}: circle label:"End"\n`;
      if (nodeIds.length > 0) {
        code += `  ${nodeIds[nodeIds.length - 1]}.handle(right) -> n${nodeId}.handle(left)\n`;
      }
    
      code += "}\n";
    
      // Add cross-lane edge from client to first API node
      code = code.replace(
        "n1: circle label:\"Start\"\n}",
        `n1: circle label:"Start"\n  n1.handle(bottom) -> ${apiLaneId}.n2.handle(top)\n}`
      );
    
      return {
        code,
        view: "workflow",
        notes: `Extracted ${steps.length} endpoints from OpenAPI spec "${title}"`,
        actors: Array.from(actors),
        stepCount: steps.length,
      };
    }
  • src/index.ts:496-500 (registration)
    Tool registration in the switch statement that routes tool calls to the handleArtifactToDiagram handler
    case "flowzap_artifact_to_diagram": {
      const { artifactType, content, view } = args as { artifactType?: unknown; content?: unknown; view?: unknown };
      const result = await handleArtifactToDiagram(artifactType, content, view);
      return { content: [{ type: "text", text: result }] };
    }
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. While it mentions parsing artifacts and converting them to diagrams, it lacks details on permissions, rate limits, error handling, or what the output looks like (e.g., diagram format, success/failure states). For a tool with no annotation coverage, this leaves significant gaps in understanding its behavior.

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

Conciseness5/5

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

The description is appropriately sized with two sentences that are front-loaded and efficient. The first sentence states the core purpose with specific examples, and the second explains the outcome without redundancy. Every sentence earns its place by adding value, making it concise and well-structured.

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?

Given the tool's complexity (parsing artifacts into diagrams), lack of annotations, and no output schema, the description is moderately complete. It covers the purpose and input types but misses behavioral details and output information. For a tool with 3 parameters and no structured safety or output guidance, it should do more to compensate, leaving room for improvement.

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?

Schema description coverage is 100%, so the schema already documents all parameters (artifactType, content, view) with descriptions and enums. The description adds minimal value by listing artifact types (matching the enum) and mentioning 'raw artifact content', but doesn't provide additional syntax, format details, or constraints beyond what the schema specifies. This meets the baseline for high schema 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's purpose: 'Parse real artifacts... into FlowZap Code diagrams' and 'convert raw technical data into visual workflows'. It specifies the verb (parse/convert) and resource (artifacts/technical data) with concrete examples (HTTP logs, OpenAPI specs, code snippets). However, it doesn't explicitly differentiate from sibling tools like flowzap_export_graph or flowzap_get_syntax, which might also handle diagrams or syntax.

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 usage context by listing specific artifact types (HTTP logs, OpenAPI specs, code snippets) and stating the outcome ('visual workflows that can be explained and refined'). However, it doesn't provide explicit guidance on when to use this tool versus alternatives like flowzap_apply_change or flowzap_validate, nor does it mention any exclusions or prerequisites for usage.

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/flowzap-xyz/flowzap-mcp'

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