Reference
Every tool, resource and prompt the Whisper MCP server exposes, one section per tool with its arguments, limits and response fields — plus the evidence model and the three different things `coverage` means.
On this page (33)
- The tool surface
- The seven tools
- query
- explain_indicator
- explain_schema
- read_docs
- list_workflows
- run_workflow
- identify
- Resources
- Prompts
- Evidence and provenance
- coverage means three different things
- What you can ask
- Incident response
- Threat hunting
- Brand protection and typosquatting
- Attack surface
- WHOIS and registrant pivoting
- BGP and routing
- Comparing infrastructure
- Email, SPF, and DMARC
- GeoIP and data residency
- Web links
- DNSSEC
- History
- Host identity and de-cloaking
- Egress, fingerprints, and transparency
- Try these prompts
- indicator-enrichment
- typosquat
- build-takedown-evidence-package
- route-health
Reference Documentation
Reference for everything the Whisper MCP server exposes: seven tools, all read-only, the resources and prompts behind them, the evidence model returned with every result, and example questions agents can answer. The query language — the error envelope, the nine safety rules, self-correction, and the callable procedures — lives on its own page: Query language. For client-by-client install instructions, OAuth scopes and data handling, see the Setup guide.
The graph behind the connector holds over 7.4 billion nodes, 39.4 billion edges, and 10.8 million threat-intel edges (76 feed sources, 31 categories) across 40 node labels and 50 edge types, about two thirds of which are synthesized at query time. The whisper://stats resource returns current totals.
Read
coveragebeforeband. Only known-clean — coverage: known-clean. In coverage, no malicious evidence. licenses the word "clean"; no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. means unknown, which is a different thing again; malicious-evidenced — coverage: malicious-evidenced. In coverage, with positive evidence of malice. and ambiguous — coverage: ambiguous. In coverage, and the evidence points both ways. mean there is evidence, whatever the band says.whisper.explaindoes not returncoverageat all. Full contract: Coverage — what we looked at.
The tool surface
Seven tools, all read-only. Every one of them is annotated readOnlyHint:true, destructiveHint:false. The annotations are uniform, and that uniformity is the honest shape of this surface rather than a shortcut: nothing on this server writes to the graph, so there is no read/write distinction left to draw. A client turns those hints into permissions, so they say exactly what the surface does — reads, against a read-only engine — and nothing more.
The surface does not vary. Every deployment advertises the same seven tools; there is no profile, tier, or setting that adds or removes one. tools/list is the contract, and it is the same contract wherever you connect.
| Tool | Arguments | Batch shape | Returns | Evidence |
|---|---|---|---|---|
query | cypher required; params?, format? (table | graph | compact), page? / pageSize? | one query per call; pageSize pages count-first rather than truncating | columns, rows, statistics{rowCount, executionTimeMs}. compact adds rowFormat:"arrays" and droppedNullColumns?; pageSize adds pagination{page, pageSize, totalCount, totalPages, hasMore} | evidence{cypher, rowCount, executionTimeMs, truncated?} and references on every call, plus layersAvailable on success |
explain_indicator | indicators[] required (indicator, a single string, is the accepted alias); detail? (auto | full | band) | 32 per call at full, 5000 at band; auto takes full at 8 indicators or fewer | {rows[], layersAvailable} — one row per indicator in input order, each echoing the detail it came from | per row: factors[], sources[], a source tag and a coverage{} block |
explain_schema | label?, uppercase [A-Z][A-Z0-9_]{0,63} | one label per call; no argument returns the whole catalogue | no argument → {labels[{label, count, scale}], labelCount, edgeCount, hint}. With a label → {label, exists, count, scale, properties[], outboundEdges[], inboundEdges[], sampleTraversal{intent, cypher}, notes[]} | — the entity card is the evidence |
read_docs | one of path (fetch), query (search), or nothing (list) | index-relative paths only — never a caller-supplied URL | list → the index, each entry carrying path, title, section, summary, mdUrl; search → ranked matches[], top 15; fetch → {path, url, mdUrl, title, section, markdown, fetchedAt, cached} | — |
list_workflows | keyword?, persona?, task?, layer?, kind? | every filter optional and combinable; no argument returns the whole catalogue, uncapped | {workflows[{slug, kind, title, summary, description?, personas, task, layers, useCases?, inputs[], params[], stepCount, requiresCapability?, expectedOutput, outputKind?, icon?, docPath?}], count} | — |
run_workflow | runs[{slug, input?, params?}] required; format?, profile?, output? | one or more slugs, and one or more entities, per call | per run: steps[], evidence[], complete, coverage{}, incompleteSteps[], warnings[], markdown?, truncations[], profileWarnings[], profile, derived, primaryQuery, totalLatencyMs, graph? — plus a top-level references{schema, cypherGuide, apiReference, slugsRun[]} | full trail: one evidence entry per step, with its Cypher, rowCount and executionTimeMs |
identify | hosts[] required; neighbourhood? (default true), depth? 1–6 (default 2), budget_ms? (default 3000, per arm) | ≤256 hosts — a larger batch is rejected, not truncated; 16 neighbourhood walks per call | {rows, layersAvailable, neighbourhoodTruncated?} — host, vendor_id, canonical_name, is_canonical, confidence, category, roles, band, host_class, evidence | per-row evidence, plus arms on any neighbourhood block |
The read-only guarantee is absolute, and it is the headline property of this surface. query is the only place a caller supplies Cypher, and a read-only pre-check runs ahead of the nine safety rules — including under an EXPLAIN prefix — rejecting every write and admin clause (CREATE, MERGE, DELETE, SET, REMOVE, FOREACH, LOAD CSV) and every mutating or admin CALL procedure. run_workflow takes a slug and parameter values, never Cypher, and the gallery behind it carries read steps only. There is no tool here that writes to the graph, under any scope or deployment.
The awkward case is worth stating, because it is what makes the guarantee true rather than merely asserted: whisper.submit and whisper.watch are live procedures on the graph engine. Neither is reachable through this server — no tool calls them, and the pre-check denies them by name. There is no contribution path on this surface at all.
The schema and the docs are discovered on demand rather than dumped into the model's context up front.
The seven tools
query
Runs an arbitrary read-only Cypher query and returns columns, rows, statistics, plus an evidence block and a top-level references object.
| Argument | Type | Notes |
|---|---|---|
cypher | string, required | Validated and possibly auto-corrected before it runs — see Query language |
params | object | Binds to $name placeholders. Bind rather than concatenate: safer, and it keeps the plan cache warm |
format | table | graph | compact | table (default) → columns + rows. graph → nodes + edges, for results that return whole paths. compact → array-of-arrays rows, plus rowFormat:"arrays" and droppedNullColumns?, to minimise tokens |
page / pageSize | int | Count-first pagination: the first page returns the total row count alongside the slice, so an agent knows how many pages exist before walking them |
Every response also carries the self-correction fields where they apply (autoLimited, rewritten, fix, truncated) and layersAvailable, a one-line reminder that WhisperGraph spans eight linked layers — so an agent several tool calls deep keeps the whole surface in view rather than collapsing the graph to whatever the last tool implied.
explain_indicator
Threat assessment for one or more indicators — IPv4, IPv6, hostname, CIDR or ASN, mixed freely in one call.
| Argument | Type | Notes |
|---|---|---|
indicators | string[] | The primary form. indicator (a single string) is the accepted singular alias |
detail | auto | full | band | full scores each indicator and is the only mode that serves IPs, CIDRs and ASNs — 32 per call. band returns a coarse band per hostname for breadth — 5000 per call. auto (default) picks full at 8 indicators or fewer, band above; a non-hostname indicator always takes full |
A full row carries score, level (NONE…CRITICAL), explanation, factors[], sources[], a source tag (live-explain / node-cache / unavailable), and a coverage block. On a hostname it also carries band, plus verdictDisagreement when level and band disagree. An ASN row adds a breakdown{} of composite sub-scores.
A band row carries host, band, label, sub_labels, signals, coverage, evidence[] — and deliberately no score or level. Every row echoes the detail it came from, so a band row is never mistaken for a scored one.
factors[] is the arithmetic, not a summary of it: ["Listed in 6 source(s) with combined weight 6.00", "Base score: 6.00 × log₂(6 + 1) = 16.84", "Recency boost: ×1.2", "Age boost: ×1.05", "Final score: … = 21.32"]. You can check the number rather than trusting it.
Do not read
scoreon a CIDR or an ASN. It is scoped to a single indicator and does not carry a range's value;factors[]does. The row hands you the right fields:scoreUnavailable: true, arecoveredScore, and averdictDisagreementnaming the column to read. A lowscoreon a CIDR or ASN is not a clean network. On an IP or a hostname,scoreis the value.
Keep batches small at
fulldetail. Under load, IP and hostname rows can come backavailable:false, error:"scoring_unavailable"while a CIDR or ASN in the same call scores normally. The row degrades honestly rather than returning a clean-looking empty verdict, but a large mixed batch is the shape that triggers it.
explain_schema
The schema, on demand, cached server-side and returning in milliseconds.
- No argument → the label catalogue:
{labels: [{label, count, scale}], labelCount, edgeCount, hint}. - With a
label(uppercase[A-Z][A-Z0-9_]{0,63}) → the entity card:{label, exists, count, scale, properties[], outboundEdges[], inboundEdges[], sampleTraversal{intent, cypher}, notes[]}.
Call it before writing a query when you are unsure whether the canonical property is h.name or h.fqdn, or whether to anchor on HOSTNAME or DOMAIN (there is no DOMAIN label — only HOSTNAME). It is the cheapest way to avoid the most common query bug: a defensive MATCH (h) WHERE h:HOSTNAME OR h:DOMAIN OR h:FQDN … against a billion-node label, which the validator rejects.
User: What labels does the Whisper graph have?
Agent: [calls explain_schema] (no argument)
→ {labels: [{label: "HOSTNAME", count: 2_728_873_562, scale: "2.7B"},
{label: "IPV4", count: 621_029_424, scale: "621M"},
{label: "EMAIL", count: 237_065_663, scale: "237M"},
... 37 more], labelCount: 40, edgeCount: 50}
Agent: The graph has 40 labels. The biggest are HOSTNAME (2.7B), IPV4 (621M), and
EMAIL (237M). What do you want to look at?
User: Show me the threat properties on a hostname.
Agent: [calls explain_schema {label: "HOSTNAME"}]
→ {label: "HOSTNAME", exists: true, count: 2_728_873_562, scale: "2.7B",
properties: [{name: "name", type: "String"},
{name: "threatScore", type: "Double"},
{name: "threatLevel", type: "String"},
{name: "isThreat", type: "Boolean"},
{name: "isC2", type: "Boolean"}, ...],
outboundEdges: [{type: "RESOLVES_TO", to: ["IPV4", "IPV6"], pattern: "(h:HOSTNAME)-[:RESOLVES_TO]->(:IPV4)"},
{type: "CHILD_OF", to: ["HOSTNAME", "TLD"]}, ...],
inboundEdges: [{type: "NAMESERVER_FOR", from: ["HOSTNAME"]},
{type: "MAIL_FOR", from: ["HOSTNAME"]}, ...],
sampleTraversal: {intent: "...", cypher: 'MATCH (h:HOSTNAME {name: "example.com"}) RETURN h LIMIT 1'}}
read_docs
Pulls the Whisper docs (whisper.security/docs/**) on demand, so the Cypher reference and the cookbook stay out of the always-on context. Three modes:
| Call | Returns |
|---|---|
| no argument | the section map: {sections: [{section, pageCount, pages[]}], count, source} |
{query: "cypher"} | ranked search over path, title, section and summary — top 15. It does not index page bodies, so an empty result means no page is titled that, not that the topic is undocumented |
{path: "whisper-graph/schema"} | that page as markdown: {path, url, mdUrl, title, section, markdown, fetchedAt, cached} |
Paths are index-relative, never a caller-supplied URL — that is the SSRF guard. Every doc page is also served as raw markdown at its URL plus .md, surfaced as mdUrl on each entry. Markdown is cached six hours; the catalogue is rebuilt from the live sitemap, so it always reflects what is actually published. Resolve a path with list or search rather than hardcoding one.
list_workflows
Searches the shared workflow and recipe gallery and returns each item's summary plus its complete parameter space. Filters — all optional, all combinable: keyword, persona, task, layer, kind (workflow | recipe). With no arguments it returns the entire catalogue, uncapped.
Each entry: {slug, kind, title, summary, description?, personas, task, layers, useCases?, inputs[], params[], stepCount, requiresCapability?, expectedOutput, outputKind?, icon?, docPath?}. Because every dial is described (kind / options / min / max / default), an agent can run any variant rather than only the default. See the Workflow gallery.
run_workflow
Runs one or more gallery workflows by slug in a single call — a multi-step investigation collapsed into one tool call.
| Argument | Type | Notes |
|---|---|---|
runs | [{slug, input?, params?}], required | Multiple workflows and multiple entities in one call. An empty array is rejected. Out-of-range params are coerced, never rejected, and the effective values echo back in paramValues |
format | compact | table | graph | compact (default) is token-minimized; table/graph return per-step rows |
profile | console | website | mcp | raw | Default mcp. A top-level sibling of output, never nested inside it |
output | {emit?, slices?} | An override applied on top of profile — sending it at all replaces the profile's slice list and overrides its emit; it does not merge. Omit it entirely on the default path or you lose the profile's markdown |
Under the default profile: "mcp" the result carries a ready, budgeted markdown report — verdict, ## Findings, correlation tables, and a numbered ## Evidence appendix mapping each [n] citation to its fact, step id and exact Cypher — as results[].markdown. Relay it verbatim rather than re-summarizing it.
Alongside it: steps[], evidence[], complete, a coverage map, incompleteSteps[], warnings[], truncations[] (what the budget dropped — never silent), profileWarnings[], derived, primaryQuery and totalLatencyMs.
Two gallery workflows run longer than a client will wait for a tool call and are therefore not advertised as prompts:
indicator(81 steps — the client gives up even on a small domain) andattack-surface(scales with the estate, so the client gives up on a large one at everylevel). Both remain runnable here by slug, where you choose the entity and own the latency.
identify
Who runs a set of hostnames — vendor and role attribution, not a threat verdict. A host on AWS is not malicious because AWS also hosts malware; use explain_indicator for the verdict.
| Argument | Type | Notes |
|---|---|---|
hosts | string[], required | Hostnames, not IPs. ≤256 — a larger batch is rejected, not truncated |
neighbourhood | bool | Default true. Walks the structural neighbourhood of any host the atlas cannot attribute |
depth | int 1–6 | Default 2, clamped server-side |
budget_ms | int | Default 3000, per arm. On expiry the block returns partial data with arms.deadline_hit:true, never an error |
One row per host in input order: host, vendor_id, canonical_name, is_canonical, confidence, category, roles, band, host_class, evidence. Roles are things like DNS_OPERATOR, MAIL_RECEIVER, ORIGIN_AS.
A novel host degrades to band:"UNKNOWN" / confidence:0.0 — it never fails the batch — and that row also gains a neighbourhood{no_atlas_match, nearest_known_vendors, siblings, coverage, arms} block placing it structurally. Only novel hosts are walked, and only the first 16 per call; the rest carry neighbourhood.skipped:"fallback-cap" alongside a top-level neighbourhoodTruncated:true.
Check arms.deadline_hit and arms_truncated before reading an empty siblings list as "no neighbours".
This is the tool for an estate-shaped question — a vendor inventory, an egress log, a third-party-risk CSV — rather than a single-indicator one.
Resources
The schema and the docs are discovered on demand through explain_schema and read_docs rather than always listed — that is what keeps the always-listed surface small. Four lightweight descriptors stay available as resources:
| Resource | Contents |
|---|---|
whisper://schema/full | The full schema reference: node labels with counts, edge types with directions, and the edge-direction landmines — also surfaced inline by explain_schema, so an agent rarely needs the raw resource |
whisper://stats | Live database statistics — nested node and edge counts (physical / virtual / total) plus the threatIntel block |
whisper://quota | The graph engine's own read-only account descriptor for the caller, surfaced verbatim — the MCP server adds nothing of its own to it. Read it at the start of a session so an agent knows what it is working with rather than inferring it |
whisper://server | Server / deployment descriptor: serverVersion, deploymentName, the live readyLayers[] (which capability layers are active here), and a schemaHash for drift detection |
Resource annotations carry MCP audience / priority hints — schema/full at priority 1.0 (assistant), the three dynamic resources at 0.5 (user + assistant).
Prompts
The connector advertises 10 prompts, one per gallery workflow, in the order below — the featured workflows first, then the rest alphabetically. Each wraps a single run_workflow call, embeds that workflow's per-step plan, and ends with an evidence directive: support each finding with the per-step prompts, Cypher and row counts, and treat a coverage gap as a finding rather than a clean result.
Arguments come from the workflow's inputs; the tunable params are listed in the prompt body — call list_workflows for their options and ranges.
| Prompt | Argument | What it does |
|---|---|---|
indicator-enrichment | value | One domain or IP into a full context card — owner, hosting, mail, location, reputation |
infrastructure-mapping | value | Trace one indicator to its true owner and full estate, even behind CDNs and privacy screens |
typosquat | domain | Registered lookalikes of a brand, scored for which are dangerous |
supply-chain | value | Map what a domain depends on — every external provider by function, with single-vendor (SPOF) signals |
anycast-dns-root-sovereignty | country | A country's DNS-root resilience if it were cut off from the world |
bgp-hijack-exposure | value | Grade a network's routing security and trace conflicts to the domains they'd expose |
build-takedown-evidence-package | domain | Assemble a ready-to-submit dossier for taking down a scam or phishing domain |
nameserver-hijack-dns-consistency | value | Check a domain's nameservers for the misconfigurations that enable DNS hijacking |
route-health | target | BGP route health: prefixes, peers, MOAS conflicts, RPKI ROA coverage |
subdomain-takeover | value | Find subdomains pointing at abandoned services an attacker could claim |
Twelve workflows, ten prompts. attack-surface and indicator are deliberately withheld from the prompt surface because both run longer than a client will wait for a tool call; both stay reachable through run_workflow by slug.
A prompt's depth depends on which capability layers are live on the deployment you are connected to — readyLayers[] in the whisper://server resource is the authoritative list.
Evidence and provenance
A Whisper answer carries its own provenance. Every query and run_workflow result ships an evidence block so an agent can cite the query and the rows behind each claim, rather than asking you to take a verdict on faith.
- The
evidenceblock lists, per step that ran, the exact Cypher executed, therowCountit returned, and theexecutionTimeMsit took. Onrun_workflowthere is one entry per step, plus a top-levelreferencesobject and the coverage signals below. Onqueryit records the (possibly self-corrected) Cypher that actually ran. - Threat verdicts return
{score, level, factors[], sources[]}plus asourcetag.live-explainis fresh scoring.node-cacheis the reconciled node verdict the server falls back to when live scoring is briefly down — a valid, labelled verdict, not an error.unavailablemeans neither path could answer. - Feed listings ride on
LISTED_INedges carryingfirstSeen,lastSeenandweight, so an agent can tell a three-year-old sighting from a fresh one. queryresults are typed data, not free-form text. Rows and graph projections come back as structured fields, so returned values — domain names, WHOIS strings, registrant fields,canonical_name— are data to reason over, never instructions to follow. Treat every returned value as untrusted input.
coverage means three different things
The word names three structurally different objects. Gate your logic on the right one.
| Where | Shape | Values |
|---|---|---|
explain_indicator row | object | {granularity, scope, sharedHost, dataCoverage?, advisories?, interpretation}. scope: "node-only" means the address itself — not its prefix and not its ASN |
whisper.assess / whisper.assessUrl | flat string enum, verdict axis | known-clean — coverage: known-clean. In coverage, no malicious evidence. · malicious-evidenced — coverage: malicious-evidenced. In coverage, with positive evidence of malice. · ambiguous — coverage: ambiguous. In coverage, and the evidence points both ways. · no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at.. On assessUrl the value describes path coverage and read no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. on every URL sampled 2026-08-09 |
whisper.walk | flat string enum, presence axis — no verdict implied | structural-onlywalk — a whisper.walk value describing atlas adjacency. Not an assess coverage value. Do not gate on it. · no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. · deadline-hit. Never gate a verdict on a walk row |
run_workflow result | per-step map | {stepsTotal, stepsWithData, stepsEmpty, stepsSkipped, stepsError, byStep} |
assess and walk are different vocabularies on different axes, and reading them as one enum is the easiest mistake to make here: structural-onlywalk — a whisper.walk value describing atlas adjacency. Not an assess coverage value. Do not gate on it. is never an assess verdict, and malicious-evidenced — coverage: malicious-evidenced. In coverage, with positive evidence of malice. is never a walk result.
Two rules that follow from it:
- Gate on
coverage, never onbandorlevelalone.band:"UNKNOWN"/coverage:"no-data"andband:"NONE"/coverage:"known-clean"both look like "nothing found" and mean opposite things.level: NONEmeans not listed;band: UNKNOWNmeans never seen — and the reverse also happens:band:"LOW"withcoverage:"malicious-evidenced"looks unremarkable and is not. Measured on140.82.121.3, 2026-08-09. - A no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. result is a populated row that says no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at. — never zero rows. So zero rows means your query is wrong, not that the host is clean. See the traversal landmines.
sharedHost: true (*.googleapis.com, *.s3.amazonaws.com, and similar multi-tenant apexes) means a hostname-level verdict is structurally uninformative: it cannot clear any one tenant underneath it.
What you can ask
The graph has DNS, BGP routing, IP allocation, GeoIP, WHOIS (237M emails, 60M phone numbers), email infrastructure (MX, full SPF chains, DMARC), DNSSEC, web hyperlinks, certificate-transparency observations, TLS fingerprints, Tor-exit relays, vendor egress, prefix-level RPKI, and 76 threat-intel feeds. All of it is connected, and the assistant walks the edges between them in one conversation.
Incident response
You got an IP or domain from an alert. Start here.
- "Investigate 185.220.101.42 -- who owns it, where is it, is it on any threat feeds, and what else is hosted there?"
- "This domain showed up in our logs: secure-login-update.com. Is it live? Who registered it? Does the registrant own other domains?"
- "We're seeing traffic to 104.16.132.229. Trace it: IP to prefix to ASN to org. Then check if any co-hosted domains are flagged."
- "Here are 20 IPs from our SIEM. Which ones are Tor exits, C2, or on blocklists?"
Threat hunting
Any threat feed can tell you an IP is bad. The graph lets you pivot — follow a bad IP to its ASN, find the other prefixes, check what's hosted there, pull WHOIS on the domains, and see if the registrant has other infrastructure. One conversation. Your first investigation walks one of these end to end.
- "Find every domain registered by the same WHOIS contact as secure-login-update.com. Do any share IPs or nameservers?"
- "Check AS60729 -- how many of its prefixes have threat-listed IPs? What's the threat density?"
- "Are there MOAS conflicts on this prefix? Which ASNs are announcing it?"
- "Find all IPs in 185.220.101.0/24 that appear on threat feeds. Group by category."
- "What domains resolve to IPs on the Tor exit-node feed? Cross-reference with their WHOIS registrants."
Brand protection and typosquatting
Run the typosquat gallery workflow over a domain — it runs 14 mutation algorithms and returns the lookalikes that are actually registered (homoglyphs, bitsquats, TLD swaps, omissions, and more). Pivot the hits through threat intel and WHOIS to see which ones are live attacks.
- "Run the typosquat sweep for paypal.com."
- "Generate lookalike domains for our brand, then check which ones are on threat feeds or resolve to live IPs."
- "Which registered variants of microsoft.com share a registrant email or nameserver with each other?"
- "Run a typosquat sweep on stripe.com -- who registered the lookalikes and is any of their infrastructure flagged?"
Attack surface
Everything an attacker would look for: subdomains, IPs, mail servers, SPF authorization chains, nameservers, WHOIS.
- "Map tesla.com -- subdomains, IPs, ASNs, nameservers, mail servers, SPF includes, and WHOIS registrant."
- "What third-party services can send email as netflix.com? Walk the full SPF include chain."
- "Find every subdomain of example.com, resolve them, and group by ASN. How many hosting providers?"
- "Where does the CNAME chain for www.example.com end up? Who hosts the final target?"
WHOIS and registrant pivoting
This is where investigations get interesting. WHOIS gives you a registrant email or phone number. The graph has 237M emails and 60M phones, so you can follow that contact to every other domain they registered, then check whether those domains share hosting.
- "Find the WHOIS registrant for secure-login-update.com, then every other domain they registered. Do any share infrastructure?"
- "What domains use this contact email? Show their IPs and ASNs, and flag any that are threat-listed."
- "Has google.com changed registrars? Show the history."
- "Find domains registered with the same phone number. Any overlap in hosting?"
- "Compare WHOIS for these five domains -- same registrant? Same email? Same registrar?"
BGP and routing
116K ASNs, 2.5M prefixes, full peering topology.
- "If AS16509 (Amazon) went down, how many prefixes and peers are affected? What domains go dark?"
- "Which ASNs peer with both Cloudflare and Google?"
- "Show the BGP routing history for 8.8.8.0/24. Has the announcing ASN changed?"
- "Find prefixes with MOAS conflicts announced by AS60729. Any of them hosting threat-listed IPs?"
- "Show the signed ROAs for this prefix -- the authorizing ASN, max-length, and trust anchor."
Comparing infrastructure
The thing that's hard to do anywhere else: checking whether two domains share anything. Same IPs, same ASN, same nameservers, same registrant email, same phone number. The graph checks all of it at once.
- "Do pandas-crossing.com and afterlifeevents.com share any infrastructure?"
- "These three phishing domains were reported separately. Any shared nameservers, IPs, ASNs, or WHOIS contacts?"
- "Compare the hosting and email setup of these two competing SaaS products."
- "Find domains that share both the same registrant email and the same IP range as this known-bad domain."
Email, SPF, and DMARC
The graph stores the full SPF record structure — includes, ip4, a, mx, exists, redirect — as separate edges, plus MX and DMARC. So you can walk the authorization chain rather than parsing TXT records by hand. (DKIM is covered at the signing-vendor level via DKIM_SIGNED_BY; it carries small row counts today, so treat it as a spot-check signal, not a broad enrichment layer.)
- "Who can send email as shopify.com? Walk the SPF chain."
- "What domains use the same SPF include targets as this phishing domain?"
- "Does this domain have MX records? SPF? a DMARC policy? Give me the full email setup."
- "Where does this domain send its DMARC aggregate reports?"
GeoIP and data residency
621M IPv4 addresses mapped to cities and countries.
- "Where are all the IPs that example.com resolves to? List by country."
- "Does this company host anything in sanctioned countries? Check all their domain IPs."
- "Find all IPs in this ASN that geolocate to Russia."
Web links
The hyperlink graph between hostnames, from Common Crawl.
- "What external domains does google.com link to? Where are those hosted?"
- "Who links to this suspicious domain? Are any of the linking sites threat-listed?"
- "Do these two domains link to each other?"
DNSSEC
- "Is cloudflare.com signed with DNSSEC? What algorithm?"
- "What percentage of domains under this nameserver use DNSSEC?"
History
WHOIS and BGP changes over time.
- "Show the WHOIS history for google.com -- registrar changes, nameserver updates, ownership."
- "BGP routing history for 8.8.8.8 -- has the announcing ASN or prefix changed?"
- "When was this domain registered? Has it changed hands?"
Host identity and de-cloaking
Whose infrastructure is this, and where does it really live? Identity is answered separately from verdict, and the origin-IP recipe finds the server behind a CDN.
- "Whose infrastructure is github.com and raw.githubusercontent.com? Are either of them dangerous?"
- "Here are 40 hostnames from our egress log. Who runs each one, and flag anything you can't place."
- "What are the candidate true-origin IPs behind www.cloudflare.com? Which can I reach directly, behind the WAF?"
- "Score these 200 hostnames for breadth first, then give me the full evidence on the worst ten."
Egress, fingerprints, and transparency
Who really operates a netblock, what an IP's TLS fingerprint reveals, which subdomains certificate transparency has seen, Tor-exit identity, and DMARC posture.
- "Does 185.220.101.1 run a Tor exit relay? Show the relay fingerprints and its anonymizer flags."
- "Who operates the netblock 104.16.0.0/13 -- the egress vendor, not just the WHOIS owner?"
- "Read the TLS fingerprint of this IP and find every other IP that shares it."
- "What hostnames has certificate transparency seen for this domain, including CT-only names that never resolve?"
- "Where does apple.com send its DMARC reports? Show the rua/ruf recipients and the SPF mechanisms."
Try these prompts
Four that are worth running first. All four are advertised prompts, and all four were run against production on 2026-08-09.
indicator-enrichment
One domain or IP into a full context card — registrant, hosting, mail, location and a reputation read, in one call.
/indicator-enrichment github.com
19 steps. Returns the registration identity, the hosting and mail posture, the network behind it, and a verdict — with the Cypher behind each step in the evidence block. Measured 37.5 s cold, all steps complete.
typosquat
Brand-protection sweep — registered lookalikes of a domain across 14 mutation algorithms, enriched with threat-feed listings and pivoted through WHOIS to identify who registered the suspicious ones.
/typosquat paypal.com
A live run returned 152 registered look-alikes, 3 of them feed-listed, 7 defensive registrations traced back to the brand's own registrant, 5 operator clusters sharing a registrant email or nameserver, and 25 unregistered variants still available. exists means registered or observed, not malicious.
build-takedown-evidence-package
The one that ends in a deliverable rather than an insight: a dossier you can hand to a registrar.
/build-takedown-evidence-package ickaoex.com
7 steps, every one returning data, measured 7.4 s — the fastest and most self-contained of the four.
route-health
A network or address block's routing and reachability health card — announced prefixes, RPKI ROA coverage, peers and upstream transit, MOAS conflicts, and the facilities and exchanges it sits in.
/route-health AS3356
Measured success: true in 1.1 s across 6 steps, 4 of them carrying data. It reports complete: false, and honestly: the asn-reputation step is skipped because that capability is not enabled on this deployment, and the coverage block names the gap rather than passing it off as a clean result. That is the behaviour to expect — read When a workflow returns nothing.