@modular-intelligence/dns-recon
v1.0.0
Published
MCP server for DNS & WHOIS reconnaissance
Downloads
78
Readme
DNS Reconnaissance MCP Server
A Model Context Protocol (MCP) server for performing DNS and WHOIS reconnaissance tasks. Query DNS records, perform reverse lookups, retrieve WHOIS registration data, discover subdomains via certificate transparency, and check DNS propagation across global resolvers.
Overview
This MCP server provides a comprehensive toolkit for network reconnaissance and DNS enumeration. It wraps standard command-line tools (dig, whois) and the free Certificate Transparency API (crt.sh) to enable Claude and other MCP clients to:
- Query various DNS record types (A, AAAA, MX, NS, TXT, CNAME, SOA, PTR, SRV, CAA)
- Perform reverse DNS lookups
- Retrieve WHOIS registration information for domains and IP addresses
- Discover subdomains and certificate information via Certificate Transparency logs
- Perform passive subdomain enumeration from multiple sources with optional DNS brute-force
- Check DNS record propagation across global DNS resolvers
- Attempt DNS zone transfers (AXFR)
All operations include input validation and security checks to prevent injection attacks and invalid queries.
Tools
| Tool | Description | Use Case |
|------|-------------|----------|
| dns_lookup | Query DNS records with dig | Find A, MX, NS, TXT and other DNS records |
| dns_reverse | Reverse DNS lookup for IP | Identify hostname associated with an IP |
| whois_lookup | WHOIS registration data | Get registrar, nameservers, and domain/IP details |
| cert_transparency | Search Certificate Transparency logs | Discover subdomains via SSL/TLS certificates |
| dns_zone_transfer | Attempt DNS AXFR zone transfer | Test for misconfigured nameservers (usually blocked) |
| subdomain_enum | Multi-source passive subdomain enumeration | Discover subdomains from cert transparency with optional DNS brute-force |
| dns_propagation | Check DNS propagation across global resolvers | Verify DNS record consistency and global propagation |
dns_lookup
Query DNS records for a domain using the dig command.
Input Schema:
{
"domain": "string (required)",
"record_type": "enum: A | AAAA | MX | NS | TXT | CNAME | SOA | PTR | SRV | CAA | ANY (default: A)",
"nameserver": "string (optional, e.g., 8.8.8.8)"
}Example Request:
{
"domain": "example.com",
"record_type": "MX"
}Example Response:
{
"domain": "example.com",
"record_type": "MX",
"records": [
{
"name": "example.com",
"type": "MX",
"ttl": 3600,
"value": "10 mail.example.com"
},
{
"name": "example.com",
"type": "MX",
"ttl": 3600,
"value": "20 mail2.example.com"
}
],
"query_time_ms": 45,
"server": "default"
}Common Record Types:
- A: IPv4 address
- AAAA: IPv6 address
- MX: Mail exchange server
- NS: Nameserver
- TXT: Text record (DKIM, SPF, DMARC, verification)
- CNAME: Canonical name (alias)
- SOA: Start of Authority
- PTR: Pointer record (reverse DNS)
- SRV: Service record
- CAA: Certificate Authority Authorization
- ANY: All record types
dns_reverse
Perform a reverse DNS lookup to find the hostname associated with an IP address.
Input Schema:
{
"ip": "string (required, IPv4 address)"
}Example Request:
{
"ip": "93.184.216.34"
}Example Response:
{
"ip": "93.184.216.34",
"hostname": "example.com",
"query_time_ms": 32
}Note: Many IP addresses do not have reverse DNS records configured. When no PTR record exists, hostname will be null.
whois_lookup
Retrieve WHOIS registration information for a domain or IP address.
Input Schema:
{
"query": "string (required, domain or IP address)"
}Example Request (Domain):
{
"query": "example.com"
}Example Response (Domain):
{
"query": "example.com",
"registrar": "VeriSign Global Registry Services",
"creation_date": "1995-08-14T00:00:00Z",
"expiration_date": "2025-08-13T23:59:59Z",
"updated_date": "2022-08-14T00:00:00Z",
"name_servers": [
"a.iana-servers.net",
"b.iana-servers.net"
],
"status": [
"clientDeleteProhibited",
"clientTransferProhibited",
"clientUpdateProhibited"
],
"raw": "[Full WHOIS output truncated to 3000 characters...]"
}Example Request (IP Address):
{
"query": "93.184.216.0"
}Example Response (IP):
{
"query": "93.184.216.0",
"registrar": "ARIN",
"creation_date": "2010-06-18T00:00:00Z",
"expiration_date": null,
"updated_date": "2010-06-18T00:00:00Z",
"name_servers": [],
"status": [],
"raw": "[Full WHOIS output truncated to 3000 characters...]"
}Note: The WHOIS response includes parsed fields (registrar, dates, nameservers, status) as well as the raw WHOIS output. Parsing varies by registry and type.
cert_transparency
Search Certificate Transparency (CT) logs via crt.sh to discover subdomains and certificate information.
Input Schema:
{
"domain": "string (required)",
"include_expired": "boolean (default: false)"
}Example Request:
{
"domain": "example.com",
"include_expired": false
}Example Response:
{
"domain": "example.com",
"certificate_count": 42,
"certificates": [
{
"issuer_name": "Let's Encrypt Authority X3",
"common_name": "example.com",
"name_value": "example.com\nwww.example.com\nmail.example.com",
"not_before": "2023-11-15T10:30:00Z",
"not_after": "2024-02-13T10:29:59Z",
"serial_number": "abc123def456"
},
{
"issuer_name": "DigiCert Global CA G2",
"common_name": "*.example.com",
"name_value": "*.example.com\nexample.com",
"not_before": "2023-01-10T00:00:00Z",
"not_after": "2024-01-10T23:59:59Z",
"serial_number": "xyz789uvw012"
}
],
"unique_subdomains": [
"api.example.com",
"blog.example.com",
"example.com",
"mail.example.com",
"www.example.com"
]
}About Certificate Transparency:
Certificate Transparency is a system where publicly-issued SSL/TLS certificates are logged in append-only ledgers. The crt.sh website (run by Comodo) provides free search access to these logs. This is a legitimate, legal, and widely-used reconnaissance technique. No API key is required; the service is free and public.
Use Cases:
- Discover subdomains without executing network queries
- Find certificate issuance history
- Identify new services that may not be DNS enumerated
- Monitoring unauthorized certificate issuance
subdomain_enum
Perform multi-source passive subdomain enumeration using Certificate Transparency logs and optional DNS brute-force.
Input Parameters:
{
domain: string // Required: Domain to enumerate
use_bruteforce: boolean // Optional: Enable DNS brute-force (default: false)
max_results: number // Optional: Maximum results to return 1-500 (default: 100)
}Example Request:
{
"domain": "example.com",
"use_bruteforce": false,
"max_results": 100
}Example Output:
{
"domain": "example.com",
"total_found": 12,
"sources": {
"crt.sh": 12,
"dns_bruteforce": 0
},
"subdomains": [
"api.example.com",
"blog.example.com",
"cdn.example.com",
"dev.example.com",
"example.com",
"mail.example.com",
"staging.example.com",
"static.example.com",
"support.example.com",
"test.example.com",
"wiki.example.com",
"www.example.com"
]
}With Brute-Force Example Request:
{
"domain": "example.com",
"use_bruteforce": true,
"max_results": 50
}With Brute-Force Example Output:
{
"domain": "example.com",
"total_found": 18,
"sources": {
"crt.sh": 12,
"dns_bruteforce": 6
},
"subdomains": [
"admin.example.com",
"api.example.com",
"app.example.com",
"blog.example.com",
"cdn.example.com",
"dashboard.example.com",
"dev.example.com",
"docs.example.com",
"example.com",
"ftp.example.com",
"mail.example.com",
"staging.example.com",
"static.example.com",
"support.example.com",
"test.example.com",
"wiki.example.com",
"www.example.com"
]
}How It Works:
The tool uses multiple passive enumeration sources:
Certificate Transparency (crt.sh): Queries public CT logs for SSL/TLS certificates issued to the domain and extracts all Subject Alternative Names (SANs). This is the primary source and requires no DNS queries.
DNS Brute-Force (Optional): If enabled, attempts to resolve common subdomain names (www, mail, api, admin, etc.) by querying Google and Cloudflare DNS. This actively probes for resolvable subdomains.
The results are merged, deduplicated, sorted alphabetically, and limited by the max_results parameter.
dns_propagation
Check DNS record propagation across multiple global resolvers to verify record consistency and propagation status.
Input Parameters:
{
domain: string // Required: Domain to check
record_type: "A" | "AAAA" | "MX" | "NS" | "TXT" | "CNAME" // Required: DNS record type (default: A)
}Example Request:
{
"domain": "example.com",
"record_type": "A"
}Example Output:
{
"domain": "example.com",
"record_type": "A",
"is_consistent": true,
"responding_resolvers": 8,
"total_resolvers": 8,
"propagation_percentage": 100,
"results": [
{
"resolver": "Google",
"ip": "8.8.8.8",
"location": "Global",
"records": [
"93.184.216.34"
],
"latency_ms": 12
},
{
"resolver": "Google Secondary",
"ip": "8.8.4.4",
"location": "Global",
"records": [
"93.184.216.34"
],
"latency_ms": 15
},
{
"resolver": "Cloudflare",
"ip": "1.1.1.1",
"location": "Global",
"records": [
"93.184.216.34"
],
"latency_ms": 11
},
{
"resolver": "Cloudflare Secondary",
"ip": "1.0.0.1",
"location": "Global",
"records": [
"93.184.216.34"
],
"latency_ms": 14
},
{
"resolver": "OpenDNS",
"ip": "208.67.222.222",
"location": "US",
"records": [
"93.184.216.34"
],
"latency_ms": 28
},
{
"resolver": "Quad9",
"ip": "9.9.9.9",
"location": "Global",
"records": [
"93.184.216.34"
],
"latency_ms": 13
},
{
"resolver": "Level3",
"ip": "4.2.2.1",
"location": "US",
"records": [
"93.184.216.34"
],
"latency_ms": 32
},
{
"resolver": "Comodo",
"ip": "8.26.56.26",
"location": "US",
"records": [
"93.184.216.34"
],
"latency_ms": 26
}
]
}Inconsistent Records Example:
{
"domain": "example.com",
"record_type": "MX",
"is_consistent": false,
"responding_resolvers": 7,
"total_resolvers": 8,
"propagation_percentage": 87,
"results": [
{
"resolver": "Google",
"ip": "8.8.8.8",
"location": "Global",
"records": [
"10 mail1.example.com",
"20 mail2.example.com"
],
"latency_ms": 14
},
{
"resolver": "Cloudflare",
"ip": "1.1.1.1",
"location": "Global",
"records": [
"10 mail-new.example.com"
],
"latency_ms": 12
}
]
}Global Resolvers Included:
The tool queries the following public DNS resolvers distributed globally:
- Google (8.8.8.8, 8.8.4.4) - Global
- Cloudflare (1.1.1.1, 1.0.0.1) - Global
- OpenDNS (208.67.222.222) - US
- Quad9 (9.9.9.9) - Global
- Level3 (4.2.2.1) - US
- Comodo (8.26.56.26) - US
Use Cases:
- Verify DNS record propagation after updates
- Check for DNS inconsistencies across resolvers
- Detect if a new DNS record has reached all major resolvers
- Monitor DNS cache status globally
- Troubleshoot DNS configuration issues
dns_zone_transfer
Attempt a DNS zone transfer (AXFR) against a nameserver. Zone transfers are typically restricted, but misconfigured servers may allow them.
Input Schema:
{
"domain": "string (required)",
"nameserver": "string (required, IP or nameserver domain)"
}Example Request:
{
"domain": "example.com",
"nameserver": "ns1.example.com"
}Example Response (Successful Transfer):
{
"domain": "example.com",
"nameserver": "ns1.example.com",
"success": true,
"record_count": 28,
"records": [
{
"name": "example.com",
"type": "SOA",
"ttl": 3600,
"value": "ns1.example.com. hostmaster.example.com. 2023101401 10800 3600 604800 86400"
},
{
"name": "www",
"type": "A",
"ttl": 3600,
"value": "93.184.216.34"
},
{
"name": "mail",
"type": "A",
"ttl": 3600,
"value": "93.184.216.35"
}
],
"message": "Zone transfer successful: 28 records retrieved"
}Example Response (Transfer Refused):
{
"domain": "example.com",
"nameserver": "8.8.8.8",
"success": false,
"record_count": 0,
"records": [],
"message": "Zone transfer refused by nameserver (this is expected — most servers restrict AXFR)"
}Important Notes:
- Zone transfers are rarely permitted on modern nameservers as they expose the entire zone file
- Most responses will be "refused" — this is expected and indicates proper security
- Successful transfers are rare and indicate a misconfiguration worth investigating
- Only attempt against nameservers you are authorized to test
Prerequisites
This server requires:
dig (DNS lookup utility)
- Included in
bind-toolsordnsutilspackage - macOS: Included by default
- Linux:
sudo apt-get install dnsutils(Debian/Ubuntu) orsudo yum install bind-utils(RedHat/CentOS)
- Included in
whois (WHOIS client)
- macOS: Included by default
- Linux:
sudo apt-get install whois(most distributions)
Node.js/Bun Runtime
- Bun 1.0+ recommended for optimal performance
- Or Node.js 18+ with compatible runtime
No API keys are required. The crt.sh Certificate Transparency API is completely free and public.
Installation
1. Install Bun
If you don't have Bun installed, install it from bun.sh:
curl -fsSL https://bun.sh/install | bash2. Clone or navigate to the server directory
cd /path/to/dns-recon3. Install dependencies
bun install4. Build the server
bun run buildThis creates a compiled binary in the dist/ directory.
5. Verify installation
# Test that dig and whois are available
dig -v
whois -v
# Test the server startup (will hang until interrupted with Ctrl+C)
bun run startUsage
Via Claude Desktop
Add this to your claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"dns-recon": {
"command": "bun",
"args": ["run", "/absolute/path/to/dns-recon/src/index.ts"]
}
}
}Or with the built binary:
{
"mcpServers": {
"dns-recon": {
"command": "bun",
"args": ["/absolute/path/to/dns-recon/dist/index.js"]
}
}
}Via Claude Code (MCP Settings)
Create or update ~/.mcp/settings.json:
{
"servers": {
"dns-recon": {
"command": "bun",
"args": ["run", "/absolute/path/to/dns-recon/src/index.ts"],
"env": {}
}
}
}Stdio Transport
The server uses stdio transport (stdin/stdout) for MCP communication. This is the standard transport for MCP servers and is used by Claude Desktop and compatible clients.
Testing Manually
Use the test-client.js pattern or invoke tools programmatically:
# Start the server
bun run start &
# The server will wait for MCP protocol messages on stdin
# Each tool can be invoked via the standard MCP tool_call interfaceExamples
Query A Records
Find the IPv4 address of a domain:
User: "Get the A records for example.com"Response:
{
"domain": "example.com",
"record_type": "A",
"records": [
{
"name": "example.com",
"type": "A",
"ttl": 3600,
"value": "93.184.216.34"
}
],
"query_time_ms": 42,
"server": "default"
}Discover Subdomains
Find subdomains via certificate transparency:
User: "Discover subdomains of example.com using certificate transparency"Response:
{
"domain": "example.com",
"certificate_count": 15,
"unique_subdomains": [
"api.example.com",
"example.com",
"staging.example.com",
"www.example.com"
],
"certificates": [...]
}Enumerate Subdomains with Brute-Force
Find all subdomains using passive and active techniques:
User: "Enumerate subdomains for example.com with DNS brute-force"Response:
{
"domain": "example.com",
"total_found": 18,
"sources": {
"crt.sh": 12,
"dns_bruteforce": 6
},
"subdomains": [
"admin.example.com",
"api.example.com",
"app.example.com",
"blog.example.com",
"cdn.example.com",
"dashboard.example.com",
"dev.example.com",
"docs.example.com",
"example.com",
"ftp.example.com",
"mail.example.com",
"staging.example.com",
"static.example.com",
"support.example.com",
"test.example.com",
"wiki.example.com",
"www.example.com"
]
}Check DNS Propagation
Verify DNS record propagation globally:
User: "Check if A records for example.com have propagated to all major DNS resolvers"Response:
{
"domain": "example.com",
"record_type": "A",
"is_consistent": true,
"responding_resolvers": 8,
"total_resolvers": 8,
"propagation_percentage": 100,
"results": [
{
"resolver": "Google",
"ip": "8.8.8.8",
"location": "Global",
"records": ["93.184.216.34"],
"latency_ms": 12
},
{
"resolver": "Cloudflare",
"ip": "1.1.1.1",
"location": "Global",
"records": ["93.184.216.34"],
"latency_ms": 11
}
]
}Check Mail Configuration
Find MX records for a domain:
User: "What are the mail servers for example.com?"Response:
{
"domain": "example.com",
"record_type": "MX",
"records": [
{
"name": "example.com",
"type": "MX",
"ttl": 3600,
"value": "10 mail.example.com"
},
{
"name": "example.com",
"type": "MX",
"ttl": 3600,
"value": "20 mail2.example.com"
}
],
"query_time_ms": 35,
"server": "default"
}Retrieve Domain Registration Info
Get WHOIS information:
User: "Who registered example.com and when?"Response:
{
"query": "example.com",
"registrar": "VeriSign Global Registry Services",
"creation_date": "1995-08-14T00:00:00Z",
"expiration_date": "2025-08-13T23:59:59Z",
"updated_date": "2022-08-14T00:00:00Z",
"name_servers": [
"a.iana-servers.net",
"b.iana-servers.net"
],
"status": ["clientDeleteProhibited"],
"raw": "[raw WHOIS data]"
}Reverse DNS Lookup
Find hostname from IP:
User: "What domain is hosted at 93.184.216.34?"Response:
{
"ip": "93.184.216.34",
"hostname": "example.com",
"query_time_ms": 28
}Security Considerations
Input Validation
All inputs are validated before execution:
- Domain names must match the pattern
[a-zA-Z0-9][a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}and not exceed 253 characters - IPv4 addresses must match standard dotted-decimal notation with octets 0-255
- Nameservers can be either valid IP addresses or domain names (same validation as above)
- Record types are restricted to a whitelist: A, AAAA, MX, NS, TXT, CNAME, SOA, PTR, SRV, CAA, ANY
Command Injection Prevention
- All inputs are passed as separate arguments to
execFile, not through shell interpretation - Special characters are not expanded or interpreted
- No shell metacharacters (
;,|,&,>,<) can be injected
Network Limitations
- Commands have a 30-second timeout (except zone transfers which use 15 seconds)
- Output is buffered with a 5MB limit to prevent memory exhaustion
- Only standard, authorized network tools (
dig,whois) are invoked
WHOIS and Privacy
- WHOIS lookups retrieve publicly available information
- Some registries implement GDPR privacy masking for personal details
- Use responsibly and comply with your local regulations
Rate Limiting
- This server does not implement rate limiting
- When integrating with Claude or automation, respect the rate limits of:
- Your configured DNS servers (typically very lenient)
- The whois registry (varies, typically 1-2 requests per second)
- crt.sh (very lenient, no documented rate limit)
Legal and Ethical Use
DNS reconnaissance and WHOIS lookups are completely legal, public operations. However:
- Only perform reconnaissance on systems you own or have explicit permission to test
- Zone transfer attempts should only be made against infrastructure you're authorized to test
- Use this server for authorized security testing, research, and legitimate business purposes
- Do not use for harassment, unauthorized access attempts, or illegal surveillance
Troubleshooting
"Command not found: dig"
Ensure bind-tools/dnsutils is installed:
- macOS: Should be pre-installed; try
/usr/bin/dig - Linux: Install with
sudo apt-get install dnsutilsor equivalent
"Command not found: whois"
Ensure whois is installed:
- macOS: Should be pre-installed; try
/usr/bin/whois - Linux: Install with
sudo apt-get install whois
"Invalid domain name format"
Domain must:
- Start with alphanumeric character
- Contain only alphanumerics, dots, and hyphens
- End with at least 2-letter TLD
- Not exceed 253 characters
Valid: example.com, sub.example.co.uk, test-domain.org
Invalid: -example.com, example, example..com, example.c
"Invalid IPv4 address format"
IP must be four decimal numbers 0-255 separated by dots.
Valid: 93.184.216.34, 8.8.8.8, 1.1.1.1
Invalid: 256.1.1.1, 1.1.1, 192.168.0.1.1
"Command timed out"
The operation exceeded the timeout limit (30 seconds for most queries, 15 seconds for zone transfers). This typically indicates:
- A very slow DNS server
- Network connectivity issues
- A nameserver that doesn't respond quickly
Try:
- Specifying a different nameserver
- Checking your internet connection
- Using a public DNS server like 8.8.8.8
"crt.sh API error"
The Certificate Transparency API is temporarily unavailable. Try again in a few moments. This is rare as crt.sh has excellent uptime.
Development
Project Structure
dns-recon/
├── src/
│ ├── index.ts # Main server setup and tool registration
│ ├── types.ts # TypeScript interfaces for responses
│ ├── schemas.ts # Zod validation schemas
│ ├── security.ts # Input validation functions
│ ├── cli-executor.ts # Command execution wrapper
│ └── tools/
│ ├── dns-lookup.ts # dig-based DNS queries
│ ├── dns-reverse.ts # Reverse DNS lookups
│ ├── whois-lookup.ts # WHOIS data retrieval
│ ├── cert-transparency.ts # crt.sh integration
│ ├── dns-zone-transfer.ts # AXFR zone transfers
│ ├── subdomain-enum.ts # Passive subdomain enumeration
│ └── dns-propagation.ts # DNS propagation checking
├── dist/ # Compiled output (generated by `bun build`)
├── package.json # Dependencies and scripts
└── README.md # This fileAdding a New Tool
- Create a new file in
src/tools/with a schema and function - Export the schema and function
- Import in
src/index.ts - Register with
server.tool()in main
Example:
// src/tools/my-tool.ts
import { z } from "zod";
import { domainSchema } from "../schemas.js";
export const myToolSchema = z.object({
domain: domainSchema,
});
export async function myTool(input: z.infer<typeof myToolSchema>) {
// Implementation
return { result: "..." };
}Then in src/index.ts:
import { myToolSchema, myTool } from "./tools/my-tool.js";
server.tool("my_tool", "Description", myToolSchema.shape, toolHandler(myTool));Testing
The server uses stdio transport, so testing requires:
- Starting the server
- Sending MCP protocol messages to stdin
- Reading responses from stdout
Or use Claude Desktop/Claude Code with the config above.
Performance
- DNS lookups: Typically 20-100ms depending on server and query complexity
- Reverse DNS: Typically 20-50ms
- WHOIS lookups: Typically 200-500ms due to internet latency
- Certificate Transparency: Typically 100-300ms (via HTTPS to crt.sh)
- Subdomain enumeration: Typically 500-2000ms (depends on CT log size and brute-force)
- DNS propagation: Typically 500-3000ms (queries 8 resolvers in parallel)
- Zone transfers: Variable, 15-second timeout
Most operations complete within sub-second timeframes for typical domains.
License
MIT
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
See LICENSE file for full text.
