Skip to main content
Glama

create_flowchart

Generate process flowcharts using 24 shapes like StartEnd, Process, and Decision to visualize workflows and decision trees.

Instructions

Create process flowcharts with 24 shapes (StartEnd, Process, Decision, etc.).

Example: steps=[{"id":"start","shape":"StartEnd","label":"Start"},...] flows=[{"from_step":"start","to_step":"check"},...]

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYesFlowchart title
stepsYesFlowchart steps
flowsYesConnections between steps
directionNoLayout directionTB
output_formatNoOutput format(s): png, pdf, jpg, dotpng
output_dirNoOutput directory (default: current directory). Auto-created if missing.
graph_attrNoGraphviz graph attributes (overrides defaults)
return_base64NoReturn base64 images

Implementation Reference

  • Registers the create_flowchart tool with MCP using the @mcp.tool decorator, including name, description, and annotations.
    @mcp.tool(
        name="create_flowchart",
        description="""Create process flowcharts with 24 shapes (StartEnd, Process, Decision, etc.).
    
    Example:
    steps=[{"id":"start","shape":"StartEnd","label":"Start"},...]
    flows=[{"from_step":"start","to_step":"check"},...]""",
        annotations={
            "readOnlyHint": False,
            "destructiveHint": False,
            "idempotentHint": True,
        },
    )
  • The main handler function that validates inputs, maps shapes to diagrams.programming.flowchart classes, builds the diagram with connections, generates output files in specified formats, and returns formatted results.
    async def create_flowchart(
        name: Annotated[str, Field(description="Flowchart title")],
        steps: Annotated[List[FlowStepDef], Field(description="Flowchart steps")],
        flows: Annotated[List[FlowConnectionDef], Field(description="Connections between steps")],
        direction: Annotated[
            Literal["LR", "RL", "TB", "BT"], Field(description="Layout direction")
        ] = "TB",
        output_format: Annotated[
            str | List[str], Field(description="Output format(s): png, pdf, jpg, dot")
        ] = "png",
        output_dir: Annotated[
            Optional[str],
            Field(
                description="Output directory (default: current directory). Auto-created if missing."
            ),
        ] = None,
        graph_attr: Annotated[
            Optional[Dict[str, Any]],
            Field(description="Graphviz graph attributes (overrides defaults)"),
        ] = None,
        return_base64: Annotated[bool, Field(description="Return base64 images")] = False,
    ) -> str:
        """Create flowchart diagram."""
        start_time = time.time()
    
        try:
            from diagrams.programming.flowchart import (
                Action,
                Collate,
                Database,
                Decision,
                Delay,
                Display,
                Document,
                InputOutput,
                Inspection,
                InternalStorage,
                LoopLimit,
                ManualInput,
                ManualLoop,
                Merge,
                MultipleDocuments,
                OffPageConnectorLeft,
                OffPageConnectorRight,
                Or,
                PredefinedProcess,
                Preparation,
                Sort,
                StartEnd,
                StoredData,
                SummingJunction,
            )
    
            # Map shape names to classes (including user-friendly aliases)
            shape_map = {
                # User-friendly aliases
                "Process": PredefinedProcess,
                "Data": InputOutput,
                # Standard flowchart shapes
                "StartEnd": StartEnd,
                "Decision": Decision,
                "Document": Document,
                "Database": Database,
                "Delay": Delay,
                # All other available shapes
                "Action": Action,
                "Collate": Collate,
                "Display": Display,
                "Inspection": Inspection,
                "InternalStorage": InternalStorage,
                "InputOutput": InputOutput,
                "LoopLimit": LoopLimit,
                "ManualInput": ManualInput,
                "ManualLoop": ManualLoop,
                "Merge": Merge,
                "MultipleDocuments": MultipleDocuments,
                "OffPageConnectorLeft": OffPageConnectorLeft,
                "OffPageConnectorRight": OffPageConnectorRight,
                "Or": Or,
                "PredefinedProcess": PredefinedProcess,
                "Preparation": Preparation,
                "Sort": Sort,
                "StoredData": StoredData,
                "SummingJunction": SummingJunction,
            }
    
            # Validate steps
            step_ids = {step.id for step in steps}
            for step in steps:
                if step.shape not in shape_map:
                    available = ", ".join(sorted(shape_map.keys()))
                    raise ValueError(f"Unknown flowchart shape '{step.shape}'. Available: {available}")
    
            # Validate flows
            for flow in flows:
                if flow.from_step not in step_ids:
                    raise ValueError(f"Flow references unknown step '{flow.from_step}'")
    
                targets = [flow.to_step] if isinstance(flow.to_step, str) else flow.to_step
                for target in targets:
                    if target not in step_ids:
                        raise ValueError(f"Flow references unknown step '{target}'")
    
            # Generate flowchart
            formats = [output_format] if isinstance(output_format, str) else output_format
    
            # Reject SVG - it's buggy and unsupported
            if any("svg" in fmt.lower() for fmt in formats):
                raise ValueError("SVG output is not supported. Use png, pdf, jpg, or dot instead.")
    
            original_dir = os.getcwd()
            if output_dir:
                os.makedirs(output_dir, exist_ok=True)
                os.chdir(output_dir)
    
            try:
                # Hide diagram title and set better flowchart layout attributes
                default_graph_attr = {
                    "label": "",
                    "splines": "ortho",  # Orthogonal edges with 90-degree angles
                    "nodesep": "0.8",  # Horizontal spacing between nodes (inches)
                    "ranksep": "0.75",  # Vertical spacing between ranks (inches)
                }
                merged_graph_attr = {**default_graph_attr, **(graph_attr or {})}
    
                with Diagram(
                    name=name,
                    show=False,
                    direction=direction,
                    outformat=formats,
                    graph_attr=merged_graph_attr,
                ) as _:
                    # Create step objects
                    step_objects = {}
                    for step in steps:
                        ShapeClass = shape_map[step.shape]
                        step_obj = ShapeClass(step.label)
                        step_objects[step.id] = step_obj
    
                    # Create flows
                    edge_count = 0
                    for flow in flows:
                        from_obj = step_objects[flow.from_step]
                        targets = [flow.to_step] if isinstance(flow.to_step, str) else flow.to_step
    
                        for target in targets:
                            to_obj = step_objects[target]
    
                            if flow.label:
                                edge = Edge(label=flow.label)
                                _ = from_obj >> edge >> to_obj
                            else:
                                _ = from_obj >> to_obj
    
                            edge_count += 1
    
                # Get file paths
                diagram_filename = name.replace(" ", "_").replace("-", "_").lower()
                file_paths = []
                for fmt in formats:
                    file_path = f"{diagram_filename}.{fmt}"
                    if output_dir:
                        file_path = os.path.join(output_dir, file_path)
                    file_paths.append(os.path.abspath(file_path))
    
                # Build metadata
                generation_time_ms = (time.time() - start_time) * 1000
                metadata = build_diagram_metadata(
                    file_paths,
                    node_count=len(steps),
                    edge_count=edge_count,
                    cluster_count=0,
                    generation_time_ms=generation_time_ms,
                )
    
                # Base64 if requested
                base64_images = None
                if return_base64:
                    base64_images = {}
                    for path in file_paths:
                        ext = Path(path).suffix[1:]
                        if ext != "dot":
                            try:
                                base64_images[ext] = encode_file_base64(path)
                            except Exception:
                                pass
    
                return format_diagram_result(file_paths, metadata, base64_images)
    
            finally:
                if output_dir:
                    os.chdir(original_dir)
    
        except Exception as e:
            return format_error(f"Failed to create flowchart: {str(e)}")
  • Pydantic model defining the structure and validation for flowchart steps (id, shape, label).
    class FlowStepDef(BaseModel):
        """Definition of a flowchart step."""
    
        id: str = Field(
            description="Unique step ID",
            min_length=1,
            max_length=200,
        )
        shape: str = Field(
            description="Shape (StartEnd, Process, Decision, Data...)",
            min_length=1,
        )
        label: str = Field(
            description="Display label",
            min_length=1,
        )
    
        @field_validator("id")
        @classmethod
        def validate_id_format(cls, v: str) -> str:
            """Validate ID format."""
            if not re.match(r"^[a-zA-Z0-9_-]+$", v):
                raise ValueError(
                    f"Invalid step ID '{v}': only alphanumeric characters, "
                    "underscores, and hyphens allowed"
                )
            return v
  • Pydantic model defining the structure and validation for flowchart connections (from_step, to_step, label, condition).
    class FlowConnectionDef(BaseModel):
        """Definition of a flowchart connection."""
    
        from_step: str = Field(
            description="Source step ID",
            min_length=1,
        )
        to_step: str | List[str] = Field(
            description="Target step ID(s)",
        )
        label: Optional[str] = Field(
            default=None,
            description="Label (e.g. 'Yes', 'No')",
        )
        condition: Optional[str] = Field(
            default=None,
            description="Condition description",
        )

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/apetta/diagrams-mcp'

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