search_domain
Check domain availability and pricing across multiple TLDs to find available domains, compare costs, and see WHOIS privacy options.
Instructions
Search for domain availability and pricing across multiple TLDs.
Returns:
Availability status for each domain
Pricing (first year and renewal)
Whether WHOIS privacy is included
Human-readable insights and next steps
Examples:
search_domain("vibecoding") → checks vibecoding.com, .io, .dev
search_domain("myapp", ["com", "io"]) → checks specific TLDs
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| domain_name | Yes | The domain name to search (e.g., 'vibecoding'). No extension needed. | |
| tlds | No | TLD extensions to check (e.g., ['com', 'io', 'dev']). Defaults to ['com', 'io', 'dev']. | |
| registrars | No | Optional: specific registrars to check. Leave empty to auto-select. |
Implementation Reference
- src/tools/search_domain.ts:84-93 (handler)The main handler function for the 'search_domain' MCP tool. Validates input using Zod schema and delegates to the core searchDomain service function.export async function executeSearchDomain( input: SearchDomainInput, ): Promise<SearchResponse> { try { const { domain_name, tlds, registrars } = searchDomainSchema.parse(input); return await searchDomain(domain_name, tlds, registrars); } catch (error) { throw wrapError(error); } }
- src/tools/search_domain.ts:16-36 (schema)Zod input validation schema for the search_domain tool, defining parameters: domain_name (required), tlds (optional), registrars (optional).export const searchDomainSchema = z.object({ domain_name: z .string() .min(1) .max(63) .describe( "The domain name you want to check (e.g., 'vibecoding', 'myapp'). Don't include the extension (.com, .io, etc.)", ), tlds: z .array(z.string()) .optional() .describe( "TLD extensions to check (e.g., ['com', 'io', 'dev']). Defaults to ['com', 'io', 'dev'] if not specified.", ), registrars: z .array(z.string()) .optional() .describe( "Optional: specific registrars to check (e.g., ['porkbun', 'namecheap']). Leave empty to auto-select.", ), });
- src/tools/search_domain.ts:43-79 (registration)The tool registration object defining name 'search_domain', description, and JSON schema for MCP compatibility. Exported and used by server.ts.export const searchDomainTool = { name: 'search_domain', description: `Search for domain availability and pricing across multiple TLDs. Returns: - Availability status for each domain - Pricing (first year and renewal) - Whether WHOIS privacy is included - Human-readable insights and next steps Examples: - search_domain("vibecoding") → checks vibecoding.com, .io, .dev - search_domain("myapp", ["com", "io"]) → checks specific TLDs`, inputSchema: { type: 'object', properties: { domain_name: { type: 'string', description: "The domain name to search (e.g., 'vibecoding'). No extension needed.", }, tlds: { type: 'array', items: { type: 'string' }, description: "TLD extensions to check (e.g., ['com', 'io', 'dev']). Defaults to ['com', 'io', 'dev'].", }, registrars: { type: 'array', items: { type: 'string' }, description: "Optional: specific registrars to check. Leave empty to auto-select.", }, }, required: ['domain_name'], }, };
- src/server.ts:58-66 (registration)Server-wide registration of the searchDomainTool (imported from tools/index.js) into the MCP server's TOOLS list for listTools requests.const TOOLS: Tool[] = [ searchDomainTool as Tool, bulkSearchTool as Tool, compareRegistrarsTool as Tool, suggestDomainsTool as Tool, suggestDomainsSmartTool as Tool, tldInfoTool as Tool, checkSocialsTool as Tool, ];
- src/services/domain-search.ts:46-115 (helper)Core helper function implementing the domain search logic: parallel TLD checks with registrar fallbacks (Porkbun, Namecheap, GoDaddy, RDAP, WHOIS), caching, insights generation.export async function searchDomain( domainName: string, tlds: string[] = ['com', 'io', 'dev'], preferredRegistrars?: string[], ): Promise<SearchResponse> { const startTime = Date.now(); const normalizedDomain = validateDomainName(domainName); const normalizedTlds = validateTlds(tlds); logger.info('Domain search started', { domain: normalizedDomain, tlds: normalizedTlds, }); // Search each TLD const results: DomainResult[] = []; const errors: string[] = []; let fromCache = false; // Run TLD checks in parallel const promises = normalizedTlds.map(async (tld) => { try { const result = await searchSingleDomain( normalizedDomain, tld, preferredRegistrars, ); if (result.fromCache) fromCache = true; return { success: true as const, tld, result: result.result }; } catch (error) { const wrapped = wrapError(error); return { success: false as const, tld, error: wrapped }; } }); const outcomes = await Promise.all(promises); for (const outcome of outcomes) { if (outcome.success) { results.push(outcome.result); } else { errors.push(`${outcome.tld}: ${outcome.error.userMessage}`); logger.warn(`Failed to check .${outcome.tld}`, { domain: normalizedDomain, error: outcome.error.message, }); } } // Generate insights and next steps const insights = generateInsights(results, errors); const nextSteps = generateNextSteps(results); const duration = Date.now() - startTime; logger.info('Domain search completed', { domain: normalizedDomain, results_count: results.length, errors_count: errors.length, duration_ms: duration, from_cache: fromCache, }); return { results, insights, next_steps: nextSteps, from_cache: fromCache, duration_ms: duration, }; }