Skip to main content
Glama

darwin_list_options

Lists all nix-darwin configuration option categories with their option counts to help users explore available system configuration settings.

Instructions

List all nix-darwin option categories.

Enumerates all top-level categories with their option counts.

Returns: Plain text list of categories sorted alphabetically with option counts

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The main handler function for the 'darwin_list_options' MCP tool. It parses the nix-darwin HTML manual using parse_html_options, extracts and filters top-level option categories using a darwin-specific valid_categories set, counts options per category, sorts them by count descending then alphabetically, and returns a formatted plain-text list.
    @mcp.tool()
    async def darwin_list_options() -> str:
        """List all nix-darwin option categories.
    
        Enumerates all top-level categories with their option counts.
    
        Returns:
            Plain text list of categories sorted alphabetically with option counts
        """
        try:
            # Get more options to see all categories (default 100 is too few)
            options = parse_html_options(DARWIN_URL, limit=2000)
            categories: dict[str, int] = {}
    
            for opt in options:
                name = opt["name"]
                # Process option names
                if name and not name.startswith("."):
                    if "." in name:
                        cat = name.split(".")[0]
                    else:
                        cat = name  # Option without dot is its own category
                    # Valid categories should:
                    # - Be more than 1 character
                    # - Be a valid identifier (allows underscores)
                    # - Not be common value words
                    # - Match typical nix option category patterns
                    if (
                        len(cat) > 1 and cat.isidentifier() and (cat.islower() or cat.startswith("_"))
                    ):  # This ensures valid identifier
                        # Additional filtering for known valid Darwin categories
                        valid_categories = {
                            "documentation",
                            "environment",
                            "fonts",
                            "homebrew",
                            "ids",
                            "launchd",
                            "networking",
                            "nix",
                            "nixpkgs",
                            "power",
                            "programs",
                            "security",
                            "services",
                            "system",
                            "targets",
                            "time",
                            "users",
                        }
                        # Only include if it's in the known valid list or looks like a typical category
                        if cat in valid_categories or (len(cat) >= 3 and not any(char.isdigit() for char in cat)):
                            categories[cat] = categories.get(cat, 0) + 1
    
            results = []
            results.append(f"nix-darwin option categories ({len(categories)} total):\n")
    
            # Sort by count descending, then alphabetically
            sorted_cats = sorted(categories.items(), key=lambda x: (-x[1], x[0]))
    
            for cat, count in sorted_cats:
                results.append(f"• {cat} ({count} options)")
    
            return "\n".join(results)
    
        except Exception as e:
            return error(str(e))
  • Core helper function parse_html_options that fetches and parses HTML documentation from nix-darwin manual (or home-manager), extracts option names, descriptions, and types from <dt>/<dd> pairs, applies query/prefix filters, and returns structured option data. Called by darwin_list_options at line 1053.
    def parse_html_options(url: str, query: str = "", prefix: str = "", limit: int = 100) -> list[dict[str, str]]:
        """Parse options from HTML documentation."""
        try:
            resp = requests.get(url, timeout=30)  # Increase timeout for large docs
            resp.raise_for_status()
            # Use resp.content to let BeautifulSoup handle encoding detection
            # This prevents encoding errors like "unknown encoding: windows-1252"
            soup = BeautifulSoup(resp.content, "html.parser")
            options = []
    
            # Get all dt elements
            dts = soup.find_all("dt")
    
            for dt in dts:
                # Get option name
                name = ""
                if "home-manager" in url:
                    # Home Manager uses anchor IDs like "opt-programs.git.enable"
                    anchor = dt.find("a", id=True)
                    if anchor:
                        anchor_id = anchor.get("id", "")
                        # Remove "opt-" prefix and convert underscores
                        if anchor_id.startswith("opt-"):
                            name = anchor_id[4:]  # Remove "opt-" prefix
                            # Convert _name_ placeholders back to <name>
                            name = name.replace("_name_", "<name>")
                    else:
                        # Fallback to text content
                        name_elem = dt.find(string=True, recursive=False)
                        if name_elem:
                            name = name_elem.strip()
                        else:
                            name = dt.get_text(strip=True)
                else:
                    # Darwin and fallback - use text content
                    name = dt.get_text(strip=True)
    
                # Skip if it doesn't look like an option (must contain a dot)
                # But allow single-word options in some cases
                if "." not in name and len(name.split()) > 1:
                    continue
    
                # Filter by query or prefix
                if query and query.lower() not in name.lower():
                    continue
                if prefix and not (name.startswith(prefix + ".") or name == prefix):
                    continue
    
                # Find the corresponding dd element
                dd = dt.find_next_sibling("dd")
                if dd:
                    # Extract description (first p tag or direct text)
                    desc_elem = dd.find("p")
                    if desc_elem:
                        description = desc_elem.get_text(strip=True)
                    else:
                        # Get first text node, handle None case
                        text = dd.get_text(strip=True)
                        description = text.split("\n")[0] if text else ""
    
                    # Extract type info - look for various patterns
                    type_info = ""
                    # Pattern 1: <span class="term">Type: ...</span>
                    type_elem = dd.find("span", class_="term")
                    if type_elem and "Type:" in type_elem.get_text():
                        type_info = type_elem.get_text(strip=True).replace("Type:", "").strip()
                    # Pattern 2: Look for "Type:" in text
                    elif "Type:" in dd.get_text():
                        text = dd.get_text()
                        type_start = text.find("Type:") + 5
                        type_end = text.find("\n", type_start)
                        if type_end == -1:
                            type_end = len(text)
                        type_info = text[type_start:type_end].strip()
    
                    options.append(
                        {
                            "name": name,
                            "description": description[:200] if len(description) > 200 else description,
                            "type": type_info,
                        }
                    )
    
                    if len(options) >= limit:
                        break
    
            return options
        except Exception as exc:
            raise DocumentParseError(f"Failed to fetch docs: {str(exc)}") from exc
  • Constant defining the URL of the nix-darwin manual HTML used by darwin_list_options and related tools to fetch option documentation.
    DARWIN_URL = "https://nix-darwin.github.io/nix-darwin/manual/index.html"
  • FastMCP decorator @mcp.tool() that registers the darwin_list_options function as an MCP tool.
    @mcp.tool()

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/utensils/mcp-nixos'

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