Skip to main content
Glama

darwin_info

Retrieve detailed configuration information for nix-darwin options, including type and description, with suggestions for similar options when exact matches aren't found.

Instructions

Get detailed information about a specific nix-darwin option.

Requires an exact option name match. If not found, suggests similar options.

Args: name: The exact option name (e.g., 'system.defaults.dock.autohide')

Returns: Plain text with option details (name, type, description) or error with suggestions

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYes

Implementation Reference

  • Main handler function for the 'darwin_info' tool. It parses the nix-darwin HTML manual, searches for the exact option name, and returns formatted details including type and description. Provides suggestions if not found.
    @mcp.tool()
    async def darwin_info(name: str) -> str:
        """Get detailed information about a specific nix-darwin option.
    
        Requires an exact option name match. If not found, suggests similar options.
    
        Args:
            name: The exact option name (e.g., 'system.defaults.dock.autohide')
    
        Returns:
            Plain text with option details (name, type, description) or error with suggestions
        """
        try:
            # Search more broadly first
            options = parse_html_options(DARWIN_URL, name, "", 100)
    
            # Look for exact match
            for opt in options:
                if opt["name"] == name:
                    info = []
                    info.append(f"Option: {name}")
                    if opt["type"]:
                        info.append(f"Type: {opt['type']}")
                    if opt["description"]:
                        info.append(f"Description: {opt['description']}")
                    return "\n".join(info)
    
            # If not found, check if there are similar options to suggest
            if options:
                suggestions = []
                for opt in options[:5]:  # Show up to 5 suggestions
                    if name in opt["name"] or opt["name"].startswith(name + "."):
                        suggestions.append(opt["name"])
    
                if suggestions:
                    return error(
                        f"Option '{name}' not found. Did you mean one of these?\n"
                        + "\n".join(f"  • {s}" for s in suggestions)
                        + f"\n\nTip: Use darwin_options_by_prefix('{name}') to browse all options with this prefix.",
                        "NOT_FOUND",
                    )
    
            return error(
                f"Option '{name}' not found.\n"
                + f"Tip: Use darwin_options_by_prefix('{name}') to browse available options.",
                "NOT_FOUND",
            )
    
        except Exception as e:
            return error(str(e))
  • Core helper function used by darwin_info to parse nix-darwin (and home-manager) HTML documentation pages and extract structured option data (name, type, description).
    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 URL for the nix-darwin manual index page, used by darwin_info and related tools to fetch option documentation.
    DARWIN_URL = "https://nix-darwin.github.io/nix-darwin/manual/index.html"
  • FastMCP decorator that registers the darwin_info 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