Skip to main content
Glama

DNS MCP Server

by cenemil
dns-resolver.ts6.84 kB
import * as dns from 'dns/promises'; import { Resolver } from 'dns/promises'; import { DnsRecord, DnsRecordType, DnsLookupResult, DnsError, DnsServerConfig } from './types/dns'; export class DnsResolver { private resolver: Resolver; private config: DnsServerConfig; constructor(config?: DnsServerConfig) { this.resolver = new Resolver(); this.config = config || { servers: ['8.8.8.8', '8.8.4.4', '1.1.1.1', '1.0.0.1'], timeout: 5000, retries: 2 }; if (this.config.servers && this.config.servers.length > 0) { this.resolver.setServers(this.config.servers); } } async lookup(domain: string, recordType: DnsRecordType, timeout?: number): Promise<DnsLookupResult> { const startTime = Date.now(); const records: DnsRecord[] = []; try { switch (recordType) { case 'A': const aRecords = await this.resolver.resolve4(domain, { ttl: true }); records.push(...aRecords.map(r => ({ type: 'A' as DnsRecordType, name: domain, value: r.address, ttl: r.ttl }))); break; case 'AAAA': const aaaaRecords = await this.resolver.resolve6(domain, { ttl: true }); records.push(...aaaaRecords.map(r => ({ type: 'AAAA' as DnsRecordType, name: domain, value: r.address, ttl: r.ttl }))); break; case 'CNAME': const cnameRecords = await this.resolver.resolveCname(domain); records.push(...cnameRecords.map(r => ({ type: 'CNAME' as DnsRecordType, name: domain, value: r }))); break; case 'MX': const mxRecords = await this.resolver.resolveMx(domain); records.push(...mxRecords.map(r => ({ type: 'MX' as DnsRecordType, name: domain, value: r.exchange, priority: r.priority }))); break; case 'TXT': const txtRecords = await this.resolver.resolveTxt(domain); records.push(...txtRecords.map(r => ({ type: 'TXT' as DnsRecordType, name: domain, value: r.join('') }))); break; case 'NS': const nsRecords = await this.resolver.resolveNs(domain); records.push(...nsRecords.map(r => ({ type: 'NS' as DnsRecordType, name: domain, value: r }))); break; case 'SOA': const soaRecord = await this.resolver.resolveSoa(domain); if (soaRecord) { records.push({ type: 'SOA' as DnsRecordType, name: domain, value: JSON.stringify(soaRecord) }); } break; case 'PTR': const ptrRecords = await this.resolver.resolvePtr(domain); records.push(...ptrRecords.map(r => ({ type: 'PTR' as DnsRecordType, name: domain, value: r }))); break; case 'SRV': const srvRecords = await this.resolver.resolveSrv(domain); records.push(...srvRecords.map(r => ({ type: 'SRV' as DnsRecordType, name: domain, value: r.name, priority: r.priority, weight: r.weight, port: r.port }))); break; case 'CAA': const caaRecords = await this.resolver.resolveCaa(domain); records.push(...caaRecords.map(r => ({ type: 'CAA' as DnsRecordType, name: domain, value: `${r.critical ? '128' : '0'} ${r.issue || r.issuewild || r.iodef || ''}` }))); break; default: throw new Error(`Unsupported record type: ${recordType}`); } return { domain, recordType, records, queryTime: Date.now() - startTime, server: this.config.servers[0], timestamp: new Date().toISOString() }; } catch (error: any) { throw { code: error.code || 'UNKNOWN_ERROR', message: error.message || 'An unknown error occurred', domain, recordType } as DnsError; } } async reverseLookup(ipAddress: string): Promise<string[]> { try { return await this.resolver.reverse(ipAddress); } catch (error: any) { throw { code: error.code || 'REVERSE_LOOKUP_FAILED', message: error.message || 'Reverse lookup failed', domain: ipAddress } as DnsError; } } async batchLookup( queries: { domain: string; recordTypes: DnsRecordType[] }[], parallel: boolean = true ): Promise<{ results: DnsLookupResult[]; errors: DnsError[] }> { const results: DnsLookupResult[] = []; const errors: DnsError[] = []; const performQuery = async (domain: string, recordType: DnsRecordType) => { try { const result = await this.lookup(domain, recordType); results.push(result); } catch (error) { errors.push(error as DnsError); } }; const allQueries = queries.flatMap(q => q.recordTypes.map(rt => ({ domain: q.domain, recordType: rt })) ); if (parallel) { await Promise.all( allQueries.map(q => performQuery(q.domain, q.recordType)) ); } else { for (const q of allQueries) { await performQuery(q.domain, q.recordType); } } return { results, errors }; } async traceDns(domain: string, recordType: DnsRecordType = 'A'): Promise<any> { const trace: any[] = []; try { const rootServers = await this.resolver.resolveNs('.'); trace.push({ level: 'root', servers: rootServers }); const parts = domain.split('.').reverse(); let currentDomain = ''; for (const part of parts) { currentDomain = currentDomain ? `${part}.${currentDomain}` : part; try { const nsRecords = await this.resolver.resolveNs(currentDomain); trace.push({ level: currentDomain, servers: nsRecords }); } catch (error) { break; } } const finalResult = await this.lookup(domain, recordType); trace.push({ level: 'final', result: finalResult }); return trace; } catch (error: any) { throw { code: 'TRACE_FAILED', message: error.message || 'DNS trace failed', domain, recordType } as DnsError; } } updateServers(servers: string[]) { this.config.servers = servers; this.resolver.setServers(servers); } }

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/cenemil/dns-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server