list_available_nodes
Discover available diagram nodes by provider, category, or search term to ensure valid selections before creating infrastructure diagrams.
Instructions
Discover 500+ node types across providers.
⚠️ USE THIS FIRST before create_diagram to avoid invalid node errors.
Filters: provider, category, search_term
Examples: AWS compute: provider="aws", category="compute" → EC2, Lambda, ECS, EKS... Search DBs: search_term="db" → RDS, DynamoDB, SQL across providers
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| provider | No | Filter by provider (aws, azure, gcp, etc.) | |
| category | No | Filter by category (compute, database, etc.) | |
| search_term | No | Search term for node type names | |
| limit | No | Maximum results to return |
Implementation Reference
- src/diagrams_mcp/tools/core.py:573-589 (registration)MCP tool registration decorator defining the tool name, description, annotations, and input schema via subsequent parameter annotations.@mcp.tool( name="list_available_nodes", description="""Discover 500+ node types across providers. ⚠️ USE THIS FIRST before create_diagram to avoid invalid node errors. Filters: provider, category, search_term Examples: AWS compute: provider="aws", category="compute" → EC2, Lambda, ECS, EKS... Search DBs: search_term="db" → RDS, DynamoDB, SQL across providers""", annotations={ "readOnlyHint": True, "destructiveHint": False, "idempotentHint": True, }, )
- src/diagrams_mcp/tools/core.py:590-620 (handler)The async handler function implementing the tool logic: validates inputs implicitly via types, calls search_nodes helper, formats output or error.async def list_available_nodes( provider: Annotated[ Optional[str], Field(description="Filter by provider (aws, azure, gcp, etc.)") ] = None, category: Annotated[ Optional[str], Field(description="Filter by category (compute, database, etc.)") ] = None, search_term: Annotated[ Optional[str], Field(description="Search term for node type names") ] = None, limit: Annotated[int, Field(description="Maximum results to return", ge=1, le=500)] = 100, ) -> str: """List available diagram node types.""" try: # Search nodes nodes = search_nodes( provider=provider, category=category, search_term=search_term, limit=limit, ) # Calculate total (for this implementation, returned = total due to limit) total_count = len(nodes) returned_count = len(nodes) return format_node_catalog(nodes, total_count, returned_count) except Exception as e: return format_error(f"Failed to list nodes: {str(e)}")
- Primary helper function that performs the node discovery and filtering logic by introspecting the diagrams library modules.def search_nodes( provider: Optional[str] = None, category: Optional[str] = None, search_term: Optional[str] = None, limit: int = 100, ) -> List[Dict[str, str]]: """Search for nodes matching criteria using dynamic discovery. Args: provider: Optional provider filter category: Optional category filter search_term: Optional search term for node type limit: Maximum number of results to return Returns: List of matching nodes with their information """ # Get discovered nodes (cached after first call) all_nodes = _discover_all_nodes() results = [] # Determine which providers to search providers_to_search = [provider] if provider else all_nodes.keys() for prov in providers_to_search: if prov not in all_nodes: continue provider_nodes = all_nodes[prov] # Determine which categories to search categories_to_search = [category] if category else provider_nodes.keys() for cat in categories_to_search: if cat not in provider_nodes: continue # Get nodes in this category nodes = provider_nodes[cat] for node in nodes: # Apply search filter if provided if search_term and search_term.lower() not in node.lower(): continue node_info = get_node_info(prov, cat, node) results.append(node_info) if len(results) >= limit: return results return results
- Cached helper that dynamically discovers all node classes by importing and introspecting diagrams library provider/category modules.@lru_cache(maxsize=1) def _discover_all_nodes() -> Dict[str, Dict[str, List[str]]]: """Dynamically discover all available nodes from diagrams library. Results are cached for performance. Returns: Dict mapping provider -> category -> list of node types """ import diagrams # noqa: F401 results = {} # Only introspect known providers for provider in PROVIDER_CATEGORIES.keys(): try: provider_module = __import__(f"diagrams.{provider}", fromlist=[""]) results[provider] = {} # Get all submodules (categories) provider_path = provider_module.__path__ for _importer, category, _ispkg in pkgutil.iter_modules(provider_path): # Skip private/internal modules if category.startswith("_"): continue try: cat_module = __import__( f"diagrams.{provider}.{category}", fromlist=[""], ) nodes = [] # Get all classes that don't start with underscore for name, obj in inspect.getmembers(cat_module): if ( inspect.isclass(obj) and not name.startswith("_") and hasattr(obj, "_icon") ): # Ensure it's a node class nodes.append(name) if nodes: results[provider][category] = sorted(nodes) except (ImportError, AttributeError): # Skip categories that can't be imported pass except ImportError: # Skip providers that aren't installed pass return results