@joseph.andrade.ii/dns-lookup-mcp
Version:
MCP server for performing DNS lookups with TypeScript
262 lines • 9.67 kB
JavaScript
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