mcp-dns-insights
by luke-nielsen
README.md
# mcp-dns-insights
Capture the DNS queries leaving your Mac and serve them to Claude over the
[Model Context Protocol](https://modelcontextprotocol.io) so Claude can analyse
your traffic patterns and hand back a structured JSON overview.
It answers questions like:
- *Which domains does my machine talk to the most?*
- *How much of my traffic is advertising, analytics, or telemetry?*
- *When am I busiest, and were there any unusual bursts of activity?*
## How it works
```
┌────────────┐ ┌──────────────┐ ┌───────────────┐ ┌────────┐
│ tcpdump │ --> │ capture │ --> │ SQLite db │ <-- │ MCP │ <── Claude
│ (port 53) │ │ daemon │ │ (dns.db) │ │ server │
└────────────┘ └──────────────┘ └───────────────┘ └────────┘
```
1. A **capture daemon** runs `tcpdump`, parses each DNS *question* off the wire,
and appends it to a local SQLite database.
2. An **MCP server** exposes read-only tools over stdio. Claude calls
`analyze_patterns` (and friends) and receives JSON it can summarise.
The two halves are decoupled through the database: capture is a single writer,
the server is a read-only consumer.
## Install
Requires Python 3.10+ and the `tcpdump` that ships with macOS.
```bash
git clone https://github.com/luke-nielsen/mcp-dns-insights.git
cd mcp-dns-insights
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
```
## Usage
### 1. Capture DNS traffic
Packet capture needs root, so run the daemon under `sudo`:
```bash
sudo -E mcp-dns-insights capture
```
Leave it running in the background (or install it as a launchd job — see below).
Use `-i en0` to pin a specific interface; the default `any` captures all of them.
### 2. Inspect from the terminal
```bash
mcp-dns-insights stats --hours 24 # human-readable summary
mcp-dns-insights stats --hours 24 --json
mcp-dns-insights info # database location & span
```
### 3. Connect it to Claude
The server speaks MCP over stdio. Register it with Claude Code:
```bash
claude mcp add dns-insights -- mcp-dns-insights serve
```
or add it to your MCP host config manually:
```json
{
"mcpServers": {
"dns-insights": {
"command": "mcp-dns-insights",
"args": ["serve"]
}
}
}
```
Then ask Claude: *"Analyse my DNS traffic from the last 24 hours and tell me
what's noteworthy."*
## MCP tools
| Tool | Purpose |
| ------------------- | ------------------------------------------------------------- |
| `analyze_patterns` | Full JSON overview: top domains, categories, temporal, notes. |
| `recent_queries` | The most recent queries as a JSON list. |
| `search_domain` | Find queries whose hostname matches a substring. |
| `database_info` | Database path, size, and time span. |
### Shape of `analyze_patterns`
```jsonc
{
"summary": { "total_queries": 4213, "unique_hostnames": 612, "unique_domains": 241, "window": { ... } },
"top_hostnames": [ { "name": "api.github.com", "count": 88 }, ... ],
"top_domains": [ { "name": "github.com", "count": 140 }, ... ],
"query_types": { "A": 3100, "AAAA": 980, "HTTPS": 133 },
"clients": [ { "name": "192.168.1.10", "count": 4100 } ],
"resolvers": [ { "name": "1.1.1.1", "count": 4213 } ],
"categories": { "analytics": 210, "advertising": 95, "cdn": 540 },
"flagged_domains": [ { "domain": "doubleclick.net", "category": "advertising", "count": 60 } ],
"temporal": { "by_hour": { ... }, "busiest_hour": { ... }, "peak_queries_per_minute": 47 },
"observations": [ "github.com accounts for 140 queries (3% of the total).", ... ]
}
```
## Run as a launchd job (optional)
Create `~/Library/LaunchAgents/us.radiusgroup.mcp-dns-insights.plist` (capture
needs root, so a `LaunchDaemon` in `/Library/LaunchDaemons` is the better fit):
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>us.radiusgroup.mcp-dns-insights</string>
<key>ProgramArguments</key>
<array>
<string>/path/to/.venv/bin/mcp-dns-insights</string>
<string>capture</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
</dict>
</plist>
```
```bash
sudo cp us.radiusgroup.mcp-dns-insights.plist /Library/LaunchDaemons/
sudo launchctl load /Library/LaunchDaemons/us.radiusgroup.mcp-dns-insights.plist
```
## Configuration
All settings have sensible defaults and can be overridden via the environment:
| Variable | Default |
| --------------------------------- | --------------------------------------------------------- |
| `MCP_DNS_INSIGHTS_DB` | `~/Library/Application Support/mcp-dns-insights/dns.db` |
| `MCP_DNS_INSIGHTS_HOME` | data directory (overrides the default location) |
| `MCP_DNS_INSIGHTS_IFACE` | `any` |
| `MCP_DNS_INSIGHTS_FILTER` | `udp port 53 or tcp port 53` |
| `MCP_DNS_INSIGHTS_TCPDUMP` | `tcpdump` |
| `MCP_DNS_INSIGHTS_FLUSH_INTERVAL` | `2.0` (seconds) |
| `MCP_DNS_INSIGHTS_FLUSH_BATCH` | `100` (queries) |
## Privacy
The database contains a record of every hostname your Mac looked up — that is
sensitive. It is stored **only on your machine** and is never transmitted
anywhere except to the local MCP server you explicitly connect to Claude. The
`.gitignore` excludes `*.db` so capture data is never committed.
> Note: queries answered by DNS-over-HTTPS/TLS (e.g. some browsers' built-in
> secure DNS) are encrypted and will **not** be visible to a port-53 capture.
## Development
```bash
pip install -e ".[dev]"
pytest # run the test suite
ruff check . # lint
```
## License
MIT — see [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues