whois_lookup
Look up WHOIS information for a domain to find registrant, registrar, and expiration details.
Instructions
WHOIS lookup for a domain using the system whois command.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes |
Implementation Reference
- src/sounding/server.py:367-408 (handler)The whois_lookup tool handler function. It calls the system 'whois' command via asyncio, parses common fields (registrar, creation_date, expiry_date, name_servers) from the output, and returns them in a dict along with the raw output. Uses sanitize_domain() for input validation.
async def whois_lookup(domain: str) -> dict: """WHOIS lookup for a domain using the system ``whois`` command.""" domain = sanitize_domain(domain) try: proc = await asyncio.create_subprocess_exec( "whois", domain, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=30) except FileNotFoundError: return {"error": "whois command not found — install it on the host system"} except asyncio.TimeoutError: return {"error": "whois lookup timed out"} output = stdout.decode(errors="replace") # Parse common fields. info: dict[str, str | None] = { "domain": domain, "registrar": None, "creation_date": None, "expiry_date": None, "name_servers": [], } for line in output.splitlines(): lower = line.lower().strip() if lower.startswith("registrar:"): info["registrar"] = line.split(":", 1)[1].strip() elif lower.startswith("creation date:"): info["creation_date"] = line.split(":", 1)[1].strip() elif "expir" in lower and "date" in lower and ":" in line: info["expiry_date"] = line.split(":", 1)[1].strip() elif lower.startswith("name server:"): ns = line.split(":", 1)[1].strip() if ns: info["name_servers"].append(ns) info["raw"] = output return info - src/sounding/validators.py:219-235 (helper)sanitize_domain helper: strips whitespace, lowercases the domain, rejects shell metacharacters, and validates against a hostname regex pattern. Called by whois_lookup before executing the whois command.
def sanitize_domain(domain: str) -> str: """Sanitize a domain name for DNS lookups. Strips whitespace, lowercases, and rejects shell metacharacters. Returns the cleaned domain. """ domain = domain.strip().lower() if not domain: raise ValueError("Domain must not be empty") if _SHELL_META.search(domain): raise ValueError(f"Domain contains forbidden characters: {domain!r}") if not _HOSTNAME_RE.match(domain): raise ValueError(f"Invalid domain: {domain!r}") return domain - src/sounding/server.py:33-33 (registration)The FastMCP instance 'mcp' is created here. whois_lookup is registered via the @mcp.tool() decorator on line 366.
mcp = FastMCP("sounding") - src/sounding/server.py:362-366 (registration)The @mcp.tool() decorator registers whois_lookup as an MCP tool. Comment indicates it's tool #9.
# --------------------------------------------------------------------------- # 9. whois_lookup # --------------------------------------------------------------------------- @mcp.tool() - tests/test_tools.py:216-224 (helper)Test for whois_lookup: calls the function with 'google.com' and asserts the domain matches and raw or error is present in the result.
# ── whois_lookup ─────────────────────────────────────────────────────────── @pytest.mark.asyncio async def test_whois_shape(): """whois_lookup should return the expected dict shape.""" result = await whois_lookup("google.com") assert result["domain"] == "google.com" assert "raw" in result or "error" in result