npm package: @modular-intelligence/dns-recon
Description: MCP server for DNS & WHOIS reconnaissance
Latest version: 1.0.2

# 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:**
```json
{
  "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:**
```json
{
  "domain": "example.com",
  "record_type": "MX"
}
```

**Example Response:**
```json
{
  "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:**
```json
{
  "ip": "string (required, IPv4 address)"
}
```

**Example Request:**
```json
{
  "ip": "93.184.216.34"
}
```

**Example Response:**
```json
{
  "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:**
```json
{
  "query": "string (required, domain or IP address)"
}
```

**Example Request (Domain):**
```json
{
  "query": "example.com"
}
```

**Example Response (Domain):**
```json
{
  "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):**
```json
{
  "query": "93.184.216.0"
}
```

**Example Response (IP):**
```json
{
  "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:**
```json
{
  "domain": "string (required)",
  "include_expired": "boolean (default: false)"
}
```

**Example Request:**
```json
{
  "domain": "example.com",
  "include_expired": false
}
```

**Example Response:**
```json
{
  "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:**
```typescript
{
  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:**
```json
{
  "domain": "example.com",
  "use_bruteforce": false,
  "max_results": 100
}
```

**Example Output:**
```json
{
  "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:**
```json
{
  "domain": "example.com",
  "use_bruteforce": true,
  "max_results": 50
}
```

**With Brute-Force Example Output:**
```json
{
  "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:

1. **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.

2. **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:**
```typescript
{
  domain: string                                              // Required: Domain to check
  record_type: "A" | "AAAA" | "MX" | "NS" | "TXT" | "CNAME"  // Required: DNS record type (default: A)
}
```

**Example Request:**
```json
{
  "domain": "example.com",
  "record_type": "A"
}
```

**Example Output:**
```json
{
  "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:**
```json
{
  "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:**
```json
{
  "domain": "string (required)",
  "nameserver": "string (required, IP or nameserver domain)"
}
```

**Example Request:**
```json
{
  "domain": "example.com",
  "nameserver": "ns1.example.com"
}
```

**Example Response (Successful Transfer):**
```json
{
  "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):**
```json
{
  "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:

1. **dig** (DNS lookup utility)
   - Included in `bind-tools` or `dnsutils` package
   - macOS: Included by default
   - Linux: `sudo apt-get install dnsutils` (Debian/Ubuntu) or `sudo yum install bind-utils` (RedHat/CentOS)

2. **whois** (WHOIS client)
   - macOS: Included by default
   - Linux: `sudo apt-get install whois` (most distributions)

3. **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](https://bun.sh):

```bash
curl -fsSL https://bun.sh/install | bash
```

### 2. Clone or navigate to the server directory

```bash
cd /path/to/dns-recon
```

### 3. Install dependencies

```bash
bun install
```

### 4. Build the server

```bash
bun run build
```

This creates a compiled binary in the `dist/` directory.

### 5. Verify installation

```bash
# Test that dig and whois are available
dig -v
whois -v

# Test the server startup (will hang until interrupted with Ctrl+C)
bun run start
```

## Usage

### Via Claude Desktop

Add this to your `claude_desktop_config.json` (macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "dns-recon": {
      "command": "bun",
      "args": ["run", "/absolute/path/to/dns-recon/src/index.ts"]
    }
  }
}
```

Or with the built binary:

```json
{
  "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`:

```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:

```bash
# 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 interface
```

## Examples

### Query A Records

Find the IPv4 address of a domain:

```
User: "Get the A records for example.com"
```

Response:
```json
{
  "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:
```json
{
  "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:
```json
{
  "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:
```json
{
  "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:
```json
{
  "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:
```json
{
  "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:
```json
{
  "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 dnsutils` or 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 file
```

### Adding a New Tool

1. Create a new file in `src/tools/` with a schema and function
2. Export the schema and function
3. Import in `src/index.ts`
4. Register with `server.tool()` in main

Example:

```typescript
// 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`:

```typescript
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:
1. Starting the server
2. Sending MCP protocol messages to stdin
3. 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.