UNPKG

@joseph.andrade.ii/dns-lookup-mcp

Version:

MCP server for performing DNS lookups with TypeScript

262 lines 9.67 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { Resolver } from 'dns/promises'; class DnsLookupServer { server; resolver; constructor() { this.resolver = new Resolver(); this.server = new Server({ name: 'dns-lookup-mcp', version: '1.0.0', }, { capabilities: { tools: {}, }, }); this.setupHandlers(); } setupHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: this.getTools(), })); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; switch (name) { case 'dns_lookup': if (!args || typeof args !== 'object' || !('hostname' in args)) { throw new Error('dns_lookup requires hostname parameter'); } return await this.performDnsLookup(args); case 'reverse_dns': if (!args || typeof args !== 'object' || !('ip' in args)) { throw new Error('reverse_dns requires ip parameter'); } return await this.performReverseDns(args); case 'dns_resolve_all': if (!args || typeof args !== 'object' || !('hostname' in args)) { throw new Error('dns_resolve_all requires hostname parameter'); } return await this.resolveAllRecords(args); default: throw new Error(`Unknown tool: ${name}`); } }); } getTools() { return [ { name: 'dns_lookup', description: 'Perform DNS lookup for a hostname with specified record type', inputSchema: { type: 'object', properties: { hostname: { type: 'string', description: 'The hostname to look up', }, recordType: { type: 'string', enum: ['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'NS', 'PTR', 'SOA', 'SRV', 'CAA', 'ANY'], description: 'DNS record type to query (default: A)', default: 'A', }, timeout: { type: 'number', description: 'Query timeout in milliseconds (default: 5000)', default: 5000, }, servers: { type: 'array', items: { type: 'string' }, description: 'Custom DNS servers to use (optional)', }, }, required: ['hostname'], }, }, { name: 'reverse_dns', description: 'Perform reverse DNS lookup for an IP address', inputSchema: { type: 'object', properties: { ip: { type: 'string', description: 'The IP address to perform reverse lookup on', }, }, required: ['ip'], }, }, { name: 'dns_resolve_all', description: 'Resolve all common DNS record types for a hostname', inputSchema: { type: 'object', properties: { hostname: { type: 'string', description: 'The hostname to resolve all records for', }, }, required: ['hostname'], }, }, ]; } async performDnsLookup(args) { const startTime = Date.now(); const { hostname, recordType = 'A', timeout = 5000, servers } = args; if (servers && servers.length > 0) { this.resolver.setServers(servers); } try { let results; switch (recordType) { case 'A': results = await this.resolver.resolve4(hostname); break; case 'AAAA': results = await this.resolver.resolve6(hostname); break; case 'CNAME': results = await this.resolver.resolveCname(hostname); break; case 'MX': results = await this.resolver.resolveMx(hostname); break; case 'TXT': results = await this.resolver.resolveTxt(hostname); break; case 'NS': results = await this.resolver.resolveNs(hostname); break; case 'PTR': results = await this.resolver.resolvePtr(hostname); break; case 'SOA': results = await this.resolver.resolveSoa(hostname); break; case 'SRV': results = await this.resolver.resolveSrv(hostname); break; case 'CAA': results = await this.resolver.resolveCaa(hostname); break; case 'ANY': results = await this.resolver.resolveAny(hostname); break; default: results = await this.resolver.resolve4(hostname); } const queryTime = Date.now() - startTime; const result = { hostname, recordType, results, timestamp: new Date().toISOString(), queryTime, }; return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ error: error.message, hostname, recordType, timestamp: new Date().toISOString(), }, null, 2), }, ], isError: true, }; } } async performReverseDns(args) { const startTime = Date.now(); const { ip } = args; try { const hostnames = await this.resolver.reverse(ip); const queryTime = Date.now() - startTime; return { content: [ { type: 'text', text: JSON.stringify({ ip, hostnames, timestamp: new Date().toISOString(), queryTime, }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ error: error.message, ip, timestamp: new Date().toISOString(), }, null, 2), }, ], isError: true, }; } } async resolveAllRecords(args) { const { hostname } = args; const recordTypes = ['A', 'AAAA', 'CNAME', 'MX', 'TXT', 'NS', 'SOA', 'CAA']; const results = {}; for (const recordType of recordTypes) { try { const response = await this.performDnsLookup({ hostname, recordType: recordType }); const data = JSON.parse(response.content[0].text); if (!data.error) { results[recordType] = data.results; } } catch (error) { // Skip errors for individual record types } } return { content: [ { type: 'text', text: JSON.stringify({ hostname, records: results, timestamp: new Date().toISOString(), }, null, 2), }, ], }; } async start() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('DNS Lookup MCP Server started'); } } const server = new DnsLookupServer(); server.start().catch(console.error); //# sourceMappingURL=index.js.map