recon-mcp
by nekiyRichie
README.md
# recon-mcp
An MCP server that gives an AI agent 15 OSINT tools over free, public sources.
No API keys, no accounts, no signup — every source here answers
unauthenticated.
It is also a worked example of what changes when an MCP server has to survive
real use rather than a demo: response shaping, context budgeting, per-endpoint
retry policy, and composite tools that collapse a predictable ten-call
sequence into one.
```
"Map the attack surface of github.com"
→ recon_domain("github.com") one call
→ 139 subdomains from Certificate Transparency
→ 6 of them still resolve, checked in parallel
→ 12 addresses profiled for open ports and known CVEs
```
That is a real run, not an illustration. It took ~2 minutes, nearly all of it
waiting on crt.sh — certificate transparency is the slow leg on any busy
domain. The win here is call count, not latency: the same picture assembled
tool-by-tool costs twenty-plus round trips with the model deciding the obvious
next step between each one.
## Install
```bash
git clone https://github.com/<you>/recon-mcp && cd recon-mcp
python -m venv .venv && . .venv/bin/activate
pip install -e .
```
Register it with any MCP client. For Claude Desktop / Claude Code:
```json
{
"mcpServers": {
"recon": {
"command": "/absolute/path/to/recon-mcp/.venv/bin/recon-mcp"
}
}
}
```
That is the whole setup. There is no configuration file and nothing to
authenticate.
## Tools
| Tool | Answers |
|---|---|
| `recon_domain` | Full first pass: CT → DNS → host exposure, one call |
| `crt_subdomains` | Subdomains from Certificate Transparency logs |
| `crt_certificates` | Raw CT entries — issuer, validity, SANs |
| `dns_records` | A/AAAA/CNAME/MX/NS/TXT/SOA in one parallel call |
| `dns_lookup` | One specific record type |
| `dns_reverse` | PTR for an IPv4 address |
| `host_profile` | Shodan InternetDB: ports, hostnames, tags, CVEs |
| `host_ports` | Just the open ports |
| `host_vulns` | Just the CVEs, with a false-positive warning |
| `cve_lookup` | One CVE: CVSS score, vector, description |
| `cve_search` | CVEs by keyword, newest first |
| `rdap_domain` | Registration data: dates, registrar, nameservers |
| `rdap_ip` | Netblock owner, range, country |
| `wayback_urls` | Historical URLs archived under a domain |
| `wayback_snapshots` | Snapshots of one URL over time, with digests |
Sources: [crt.sh](https://crt.sh), Cloudflare & Google DNS-over-HTTPS,
[Shodan InternetDB](https://internetdb.shodan.io), [NVD](https://nvd.nist.gov),
[RDAP](https://rdap.org), [Wayback Machine](https://web.archive.org).
## Design notes
The parts that took iteration, and why they ended up this way.
### One envelope, including on failure
Every tool returns the same shape:
```json
{
"ok": true,
"status": 200,
"data": {},
"pivots": {"hosts": [], "ips": [], "emails": [], "urls": []},
"truncated": false,
"hint": "..."
}
```
Tools that each invent their own result format make the model rediscover
structure on every call. Errors keep the shape too — a tool that returns a
bare string on failure forces the agent to branch on type before it can read
anything.
`hint` carries what a status code cannot: that a 404 from Shodan means "never
crawled, probably nothing exposed" rather than "broken", or that CVE lists
from banner matching produce false positives when patches are backported.
### Compaction is the default, `full` is opt-in
Recon endpoints answer big. A CT query on an active domain returns tens of
thousands of rows; handing that to a model ends the session. Lists are cut to
25 items and strings to 6000 characters, recursively, with `truncated` set so
nothing silently disappears. Any tool takes `full: true` when the caller
genuinely wants everything.
The budget is deliberately tight. An agent can always ask for more — it cannot
un-blow its context window.
### `pivots` — the next hop without a parse step
Every response harvests hostnames, IPs, emails and URLs out of the payload.
The identifiers worth querying next live in unpredictable places: a hostname
appears in a certificate subject, a redirect target and a PTR record, none of
which share a key name. Harvesting them centrally means the agent chains
lookups instead of parsing prose to find something to look up.
### Retry budgets per endpoint
One retry policy for every source is wrong in both directions. crt.sh is slow
and gateway-errors under load: long timeout, few retries, patience. NVD
rate-limits unauthenticated callers to roughly five requests per 30 seconds:
back off hard, cache for an hour. DNS is fast and cheap: short timeout, retry
immediately against the spare resolver.
Retrying a known-broken endpoint four times turns one bad call into forty
seconds of an agent sitting still — which the user experiences as the tool
being broken.
### Composite tools
An opening pass over a domain is always the same sequence, and the model's
"reasoning" between the steps adds nothing while the latency is real.
`recon_domain` runs it in-process with the fan-out parallelised: ~15 calls
become 1. The per-source tools stay available for drilling into whatever the
overview surfaces.
Its `host_limit` cap is the important part. Some domains have thousands of
subdomains; resolving all of them would mean thousands of DNS queries and a
result nobody can read. The tool takes the most promising ones, says how many
it skipped, and lets the caller go deeper deliberately.
### Failures stay inside the tool
An unhandled exception in a handler propagates as a protocol error and,
depending on the client, kills the connection or leaves the agent with no idea
what happened. Everything is caught at the boundary and returned as a normal
failure envelope: a broken tool costs one turn, not the session.
Logging goes to stderr, never stdout — stdout carries the MCP protocol, and a
stray log line there corrupts the stream in a way that is unpleasant to debug
from the client side.
## Scope and use
This queries public databases about internet-facing infrastructure. It sends
no traffic to the targets themselves: certificate logs, passive DNS, archived
crawls and an existing scan index. That makes it safe for attack-surface
mapping, asset inventory and pre-engagement research.
It is not a scanner and does not confirm anything. CVEs from Shodan are
inferred from banners and go stale; archived URLs may be long gone. Everything
here is a lead to verify, not a finding to report.
## License
MIT
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues