darwin_search
Search and retrieve nix-darwin macOS configuration options by name and description, providing a plain text list of matches with name, type, and details.
Instructions
Search nix-darwin (macOS) configuration options.
Searches through available nix-darwin options by name and description.
Args: query: The search query string to match against option names and descriptions limit: Maximum number of results to return (default: 20, max: 100)
Returns: Plain text list of matching options with name, type, and description
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes |
Implementation Reference
- mcp_nixos/server.py:902-938 (handler)The primary handler function for the 'darwin_search' tool. It is decorated with @mcp.tool() which registers it with the FastMCP server. Searches nix-darwin configuration options by parsing HTML documentation, filtering by query, and formatting results as readable plain text bullet points.async def darwin_search(query: str, limit: int = 20) -> str: """Search nix-darwin (macOS) configuration options. Searches through available nix-darwin options by name and description. Args: query: The search query string to match against option names and descriptions limit: Maximum number of results to return (default: 20, max: 100) Returns: Plain text list of matching options with name, type, and description """ if not 1 <= limit <= 100: return error("Limit must be 1-100") try: options = parse_html_options(DARWIN_URL, query, "", limit) if not options: return f"No nix-darwin options found matching '{query}'" results = [] results.append(f"Found {len(options)} nix-darwin options matching '{query}':\n") for opt in options: results.append(f"• {opt['name']}") if opt["type"]: results.append(f" Type: {opt['type']}") if opt["description"]: results.append(f" {opt['description']}") results.append("") return "\n".join(results).strip() except Exception as e: return error(str(e))
- mcp_nixos/server.py:247-336 (helper)Shared helper function that parses HTML documentation pages (used by darwin_search, home_manager_search, etc.) to extract configuration options, handling Home Manager and nix-darwin specific formats, filtering by query/prefix, extracting types and descriptions.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
- mcp_nixos/server.py:902-902 (registration)The @mcp.tool() decorator registers the darwin_search function as an MCP tool named 'darwin_search' with the FastMCP server instance defined at line 28.async def darwin_search(query: str, limit: int = 20) -> str:
- mcp_nixos/server.py:903-913 (schema)Input schema and documentation for darwin_search tool, defining parameters 'query' (str, required) and 'limit' (int, default 20, 1-100), plus description of output format."""Search nix-darwin (macOS) configuration options. Searches through available nix-darwin options by name and description. Args: query: The search query string to match against option names and descriptions limit: Maximum number of results to return (default: 20, max: 100) Returns: Plain text list of matching options with name, type, and description """
- mcp_nixos/server.py:52-52 (helper)Constant URL for nix-darwin documentation, used exclusively by darwin_search and related tools to fetch the HTML options index.DARWIN_URL = "https://nix-darwin.github.io/nix-darwin/manual/index.html"