check_availability
Check if a domain name is available for registration using RDAP/WHOIS protocols. Optionally retrieve pricing information when a provider is configured.
Instructions
Check domain availability. Zero-config via RDAP/WHOIS; adds pricing if provider configured.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | e.g. 'myapp' or 'myapp.com' | |
| tlds | No | e.g. ['com','io','dev']; default .com | |
| provider | No | provider for pricing (optional) |
Implementation Reference
- src/tools/availability.ts:56-121 (handler)Main handler function that orchestrates domain availability checking. It builds domain lists from input, runs parallel availability checks using RDAP/public/WHOIS fallback chain, and enriches results with pricing from configured providers.
export async function handleCheckAvailability( input: CheckAvailabilityInput, registry: ProviderRegistry, ): Promise<Record<string, unknown>> { const domains = buildDomainList(input); // Run all availability checks in parallel (RDAP/public/WHOIS — no provider needed) const rawResults = await Promise.allSettled(domains.map(checkSingleDomain)); const results: AvailabilityResult[] = rawResults.map((r, i) => { if (r.status === 'rejected') { return { domain: domains[i], available: false, premium: false, availabilitySource: 'error', error: errorToObject(r.reason), }; } return r.value; }); // Enrich available domains with pricing — fetch pricing table ONCE per provider // instead of one API call per domain const providerName = input.provider ?? registry.names()[0]; if (providerName) { try { const provider = registry.get(providerName); if (!provider.supports(Feature.Pricing)) return stripSources(results); const availableDomains = results.filter((r) => r.available); if (availableDomains.length > 0) { if (provider.getPricingTable) { // Batch: one API call for all TLD prices const pricingTable = await provider.getPricingTable(); for (const result of availableDomains) { const tld = result.domain.split('.').slice(1).join('.'); const price = pricingTable[tld]; if (price) { result.price = price; result.priceSource = providerName; } } } else { // Fallback: per-domain enrichment for providers without getPricingTable await Promise.allSettled( availableDomains.map(async (result) => { try { const enriched = await provider.checkAvailability(result.domain); if (enriched.price) { result.price = enriched.price; result.priceSource = enriched.priceSource ?? providerName; } } catch { // Pricing enrichment failure is non-fatal } }), ); } } } catch { // No provider or pricing failure — proceed without pricing } } return stripSources(results); } - src/tools/availability.ts:10-22 (schema)Input schema definition using Zod. Validates domain format with regex, optional TLDs array, and optional provider name for pricing enrichment.
export const CheckAvailabilityInputSchema = z.object({ domain: z .string() .regex( /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/, "Must be a valid domain label (e.g. 'myapp' or 'myapp.com')", ) .describe("e.g. 'myapp' or 'myapp.com'"), tlds: z.array(z.string()).optional().describe("e.g. ['com','io','dev']; default .com"), provider: z.string().optional().describe('provider for pricing (optional)'), }); export type CheckAvailabilityInput = z.infer<typeof CheckAvailabilityInputSchema>; - src/server.ts:38-51 (registration)Tool registration with MCP server. Registers 'check_availability' tool with description, schema, and async handler that calls handleCheckAvailability.
// check_availability server.tool( 'check_availability', 'Check domain availability. Zero-config via RDAP/WHOIS; adds pricing if provider configured.', CheckAvailabilityInputSchema.shape, async (input) => { try { const result = await handleCheckAvailability(input as CheckAvailabilityInput, registry); return { content: [{ type: 'text', text: JSON.stringify(result) }] }; } catch (err) { return { content: [{ type: 'text', text: formatErrorForAgent(err) }], isError: true }; } }, ); - src/lookup/rdap.ts:6-49 (helper)RDAP lookup helper that checks domain availability via rdap.org. Returns available=true on 404, available=false on 200. First method in the fallback chain.
export async function checkAvailabilityRDAP(domain: string): Promise<AvailabilityResult> { const url = `${RDAP_BASE}${encodeURIComponent(domain)}`; try { const res = await fetch(url, { headers: { 'Accept': 'application/json' }, signal: AbortSignal.timeout(10000), }); if (res.status === 404) { // 404 = not registered = available return { domain, available: true, premium: false, availabilitySource: 'rdap', }; } if (res.status === 200) { // Domain exists = not available return { domain, available: false, premium: false, availabilitySource: 'rdap', }; } // Other status codes — treat as inconclusive, let fallback handle throw new Error(`RDAP returned status ${res.status}`); } catch (err) { if (err instanceof Error && err.name === 'TimeoutError') { throw new AgentError( 'RDAP_TIMEOUT', `RDAP lookup timed out for domain '${domain}'.`, 'Try again or use a configured provider for availability checking.', 'rdap', String(err), ); } throw err; } } - src/lookup/public.ts:6-49 (helper)Public API lookup helper using GoDaddy's public availability endpoint. Second fallback method after RDAP, checks availability with FAST check type.
export async function checkAvailabilityPublic(domain: string): Promise<AvailabilityResult> { const url = `${GODADDY_PUBLIC_BASE}?domain=${encodeURIComponent(domain)}&checkType=FAST&forTransfer=false`; let res: Response; try { res = await fetch(url, { headers: { 'Accept': 'application/json' }, signal: AbortSignal.timeout(10000), }); } catch (err) { const isTimeout = err instanceof Error && (err.name === 'TimeoutError' || err.name === 'AbortError'); throw new AgentError( isTimeout ? 'TIMEOUT' : 'NETWORK_ERROR', isTimeout ? 'Domain availability check timed out after 10 seconds.' : `Network error: ${err instanceof Error ? err.message : String(err)}`, 'Try again or check your internet connection.', 'public', ); } if (!res.ok) { throw new AgentError( 'AVAILABILITY_ERROR', `Domain availability check failed with status ${res.status}.`, 'Try again or check your internet connection.', 'public', ); } const data = await res.json() as { available: boolean; definitive: boolean; domain: string; premium?: boolean; price?: number; currency?: string; }; return { domain, available: data.available, premium: data.premium ?? false, availabilitySource: 'public', }; }