Skip to main content
Glama

validate_diagram_spec

Validate diagram specifications before generation by checking node validity, connection references, and cluster memberships to prevent errors in diagram creation.

Instructions

Validate diagram before generation (dry-run).

Checks: node validity, connection references, cluster memberships. Returns: {"valid": true/false, "errors": [...], "warnings": [...]}

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nodesYesNodes to validate
connectionsYesConnections to validate
clustersNoClusters to validate

Implementation Reference

  • Tool registration decorator defining the tool's metadata, description, hints, and input schema via Annotated types.
    @mcp.tool( name="validate_diagram_spec", description="""Validate diagram before generation (dry-run). Checks: node validity, connection references, cluster memberships. Returns: {"valid": true/false, "errors": [...], "warnings": [...]}""", annotations={ "readOnlyHint": True, "destructiveHint": False, "idempotentHint": True, }, )
  • Main handler function implementing the validation logic: checks node validity, connection references, cluster node memberships and hierarchy, collects errors/warnings, returns formatted result.
    async def validate_diagram_spec( nodes: Annotated[List[NodeDef], Field(description="Nodes to validate")], connections: Annotated[List[ConnectionDef], Field(description="Connections to validate")], clusters: Annotated[ Optional[List[ClusterDef]], Field(description="Clusters to validate") ] = None, ) -> str: """Validate diagram specification.""" errors = [] warnings = [] try: # Validate nodes node_ids = {node.id for node in nodes} for node in nodes: try: validate_node_reference(node.provider, node.category, node.type) except ValueError as e: errors.append(f"Node '{node.id}': {str(e)}") # Validate connections for conn in connections: if conn.from_node not in node_ids: errors.append(f"Connection references unknown source node '{conn.from_node}'") targets = [conn.to_node] if isinstance(conn.to_node, str) else conn.to_node for target in targets: if target not in node_ids: errors.append(f"Connection references unknown target node '{target}'") # Validate clusters if clusters: cluster_names = {cluster.name for cluster in clusters} for cluster in clusters: # Check node references for node_id in cluster.node_ids: if node_id not in node_ids: errors.append( f"Cluster '{cluster.name}' references unknown node '{node_id}'" ) # Check parent cluster exists if cluster.parent_cluster and cluster.parent_cluster not in cluster_names: errors.append( f"Cluster '{cluster.name}' references unknown parent '{cluster.parent_cluster}'" ) # Check for empty clusters if not cluster.node_ids: warnings.append(f"Cluster '{cluster.name}' is empty") # Determine if valid valid = len(errors) == 0 # Build metadata metadata = { "node_count": len(nodes), "edge_count": len(connections), "cluster_count": len(clusters) if clusters else 0, } return format_validation_result(valid, errors, warnings, metadata) except Exception as e: return format_error(f"Validation failed: {str(e)}")
  • Pydantic model NodeDef defining input structure for nodes with validation for ID format and required fields.
    class NodeDef(BaseModel): """Definition of a diagram node.""" id: str = Field( description="Unique node ID (used in connections)", min_length=1, max_length=200, ) provider: str = Field( description="Provider - MUST be exact: aws, azure, gcp, k8s, onprem, generic, saas, etc.", min_length=1, ) category: str = Field( description="Category - MUST exist for provider: compute, database, network, storage, etc.", min_length=1, ) type: str = Field( description="Node type - MUST match class in diagrams.{provider}.{category}: EC2, RDS, Lambda, etc.", 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 contains only alphanumeric + underscore + hyphen.""" if not re.match(r"^[a-zA-Z0-9_-]+$", v): raise ValueError( f"Invalid node ID '{v}': only alphanumeric characters, " "underscores, and hyphens allowed" ) return v
  • Pydantic model ConnectionDef defining structure for connections/edges with optional styling.
    class ConnectionDef(BaseModel): """Definition of a connection between nodes.""" from_node: str = Field( description="Source node ID", min_length=1, ) to_node: str | List[str] = Field( description="Target node ID(s)", ) direction: Literal["forward", "reverse", "bidirectional"] = Field( default="forward", description="Direction (forward: >>, reverse: <<, bidirectional: -)", ) label: Optional[str] = Field( default=None, description="Connection label", ) color: Optional[str] = Field( default=None, description="Colour (name or hex, e.g. 'red', '#FF0000')", ) style: Optional[Literal["solid", "dashed", "dotted", "bold"]] = Field( default=None, description="Edge style", )
  • Pydantic model ClusterDef defining cluster grouping with support for nesting.
    class ClusterDef(BaseModel): """Definition of a cluster (logical grouping of nodes).""" name: str = Field( description="Cluster name", min_length=1, ) node_ids: List[str] = Field( description="Node IDs in this cluster", min_length=1, ) graph_attr: Optional[Dict[str, Any]] = Field( default=None, description="Graphviz attributes (bgcolor, pencolor...)", ) parent_cluster: Optional[str] = Field( default=None, description="Parent cluster for nesting", )

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