Skip to main content
Glama

DNS MCP Server

by cenemil
index.ts7.61 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, Tool } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; import { DnsResolver } from './dns-resolver.js'; import { DnsLookupSchema, ReverseDnsSchema, BatchDnsSchema, DnsTraceSchema, DnsLookupInput, ReverseDnsInput, BatchDnsInput, DnsTraceInput } from './tools/schemas.js'; import { DnsRecordType } from './types/dns.js'; import { ConfigManager } from './utils/config.js'; import { Logger } from './utils/logger.js'; const configManager = new ConfigManager(); const logger = new Logger( configManager.getLoggingConfig()?.level || 'info', configManager.getLoggingConfig()?.file ); const server = new Server( { name: 'dns-mcp-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); const dnsResolver = new DnsResolver(configManager.getDnsConfig()); const TOOLS: Tool[] = [ { name: 'dns_lookup', description: 'Perform DNS lookup for a domain to retrieve various record types (A, AAAA, MX, TXT, etc.)', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'The domain name to lookup' }, recordType: { type: 'string', enum: ['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'NS', 'SOA', 'PTR', 'SRV', 'CAA'], default: 'A', description: 'The type of DNS record to query' }, useCustomServer: { type: 'boolean', description: 'Use custom DNS server if configured' }, timeout: { type: 'number', description: 'Query timeout in milliseconds' } }, required: ['domain'] } }, { name: 'reverse_dns', description: 'Perform reverse DNS lookup to find the hostname for an IP address', inputSchema: { type: 'object', properties: { ipAddress: { type: 'string', description: 'The IP address to perform reverse lookup on' }, timeout: { type: 'number', description: 'Query timeout in milliseconds' } }, required: ['ipAddress'] } }, { name: 'batch_dns', description: 'Perform multiple DNS lookups in a single operation', inputSchema: { type: 'object', properties: { queries: { type: 'array', items: { type: 'object', properties: { domain: { type: 'string' }, recordTypes: { type: 'array', items: { type: 'string', enum: ['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'NS', 'SOA', 'PTR', 'SRV', 'CAA'] } } }, required: ['domain', 'recordTypes'] }, description: 'Array of DNS queries to perform' }, parallel: { type: 'boolean', default: true, description: 'Execute queries in parallel' }, timeout: { type: 'number', description: 'Query timeout per request' } }, required: ['queries'] } }, { name: 'dns_trace', description: 'Trace the DNS resolution path from root servers to the final result', inputSchema: { type: 'object', properties: { domain: { type: 'string', description: 'The domain to trace DNS resolution path' }, recordType: { type: 'string', enum: ['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'NS', 'SOA', 'PTR', 'SRV', 'CAA'], default: 'A', description: 'The record type to trace' } }, required: ['domain'] } } ]; server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: TOOLS }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const { name, arguments: args } = request.params; switch (name) { case 'dns_lookup': { const input = DnsLookupSchema.parse(args) as DnsLookupInput; logger.info(`DNS lookup request for ${input.domain} (${input.recordType})`); const result = await dnsResolver.lookup( input.domain, input.recordType as DnsRecordType, input.timeout ); logger.debug('DNS lookup result', result); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2) } ] }; } case 'reverse_dns': { const input = ReverseDnsSchema.parse(args) as ReverseDnsInput; logger.info(`Reverse DNS lookup for ${input.ipAddress}`); const hostnames = await dnsResolver.reverseLookup(input.ipAddress); logger.debug('Reverse DNS result', hostnames); return { content: [ { type: 'text', text: JSON.stringify({ ipAddress: input.ipAddress, hostnames, timestamp: new Date().toISOString() }, null, 2) } ] }; } case 'batch_dns': { const input = BatchDnsSchema.parse(args) as BatchDnsInput; const startTime = Date.now(); const { results, errors } = await dnsResolver.batchLookup( input.queries.map(q => ({ domain: q.domain, recordTypes: q.recordTypes as DnsRecordType[] })), input.parallel ); return { content: [ { type: 'text', text: JSON.stringify({ results, errors, totalTime: Date.now() - startTime, timestamp: new Date().toISOString() }, null, 2) } ] }; } case 'dns_trace': { const input = DnsTraceSchema.parse(args) as DnsTraceInput; const trace = await dnsResolver.traceDns( input.domain, input.recordType as DnsRecordType ); return { content: [ { type: 'text', text: JSON.stringify({ domain: input.domain, recordType: input.recordType, trace, timestamp: new Date().toISOString() }, null, 2) } ] }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error: any) { if (error instanceof z.ZodError) { logger.error('Validation error', error.errors); return { content: [ { type: 'text', text: `Validation error: ${JSON.stringify(error.errors, null, 2)}` } ], isError: true }; } logger.error('Tool execution error', error); return { content: [ { type: 'text', text: `Error: ${error.message || 'An unknown error occurred'}` } ], isError: true }; } }); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); logger.info('DNS MCP Server started successfully'); } main().catch((error) => { logger.error('Failed to start DNS MCP Server:', error); process.exit(1); });

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