Skip to contentSkip navigation

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.

MCP
On this page (33)

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 coverage before band. 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.explain does not return coverage at 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.

ToolArgumentsBatch shapeReturnsEvidence
querycypher required; params?, format? (table | graph | compact), page? / pageSize?one query per call; pageSize pages count-first rather than truncatingcolumns, 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_indicatorindicators[] 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 fromper row: factors[], sources[], a source tag and a coverage{} block
explain_schemalabel?, uppercase [A-Z][A-Z0-9_]{0,63}one label per call; no argument returns the whole catalogueno 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_docsone of path (fetch), query (search), or nothing (list)index-relative paths only — never a caller-supplied URLlist → 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_workflowskeyword?, 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_workflowruns[{slug, input?, params?}] required; format?, profile?, output?one or more slugs, and one or more entities, per callper 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
identifyhosts[] 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, evidenceper-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.

ArgumentTypeNotes
cypherstring, requiredValidated and possibly auto-corrected before it runs — see Query language
paramsobjectBinds to $name placeholders. Bind rather than concatenate: safer, and it keeps the plan cache warm
formattable | graph | compacttable (default) → columns + rows. graphnodes + edges, for results that return whole paths. compact → array-of-arrays rows, plus rowFormat:"arrays" and droppedNullColumns?, to minimise tokens
page / pageSizeintCount-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.

ArgumentTypeNotes
indicatorsstring[]The primary form. indicator (a single string) is the accepted singular alias
detailauto | full | bandfull 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 score on 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, a recoveredScore, and a verdictDisagreement naming the column to read. A low score on a CIDR or ASN is not a clean network. On an IP or a hostname, score is the value.

Keep batches small at full detail. Under load, IP and hostname rows can come back available: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.

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

CallReturns
no argumentthe 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.

ArgumentTypeNotes
runs[{slug, input?, params?}], requiredMultiple 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
formatcompact | table | graphcompact (default) is token-minimized; table/graph return per-step rows
profileconsole | website | mcp | rawDefault 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) and attack-surface (scales with the estate, so the client gives up on a large one at every level). 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.

ArgumentTypeNotes
hostsstring[], requiredHostnames, not IPs. ≤256 — a larger batch is rejected, not truncated
neighbourhoodboolDefault true. Walks the structural neighbourhood of any host the atlas cannot attribute
depthint 1–6Default 2, clamped server-side
budget_msintDefault 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:

ResourceContents
whisper://schema/fullThe 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://statsLive database statistics — nested node and edge counts (physical / virtual / total) plus the threatIntel block
whisper://quotaThe 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://serverServer / 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.

PromptArgumentWhat it does
indicator-enrichmentvalueOne domain or IP into a full context card — owner, hosting, mail, location, reputation
infrastructure-mappingvalueTrace one indicator to its true owner and full estate, even behind CDNs and privacy screens
typosquatdomainRegistered lookalikes of a brand, scored for which are dangerous
supply-chainvalueMap what a domain depends on — every external provider by function, with single-vendor (SPOF) signals
anycast-dns-root-sovereigntycountryA country's DNS-root resilience if it were cut off from the world
bgp-hijack-exposurevalueGrade a network's routing security and trace conflicts to the domains they'd expose
build-takedown-evidence-packagedomainAssemble a ready-to-submit dossier for taking down a scam or phishing domain
nameserver-hijack-dns-consistencyvalueCheck a domain's nameservers for the misconfigurations that enable DNS hijacking
route-healthtargetBGP route health: prefixes, peers, MOAS conflicts, RPKI ROA coverage
subdomain-takeovervalueFind 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 evidence block lists, per step that ran, the exact Cypher executed, the rowCount it returned, and the executionTimeMs it took. On run_workflow there is one entry per step, plus a top-level references object and the coverage signals below. On query it records the (possibly self-corrected) Cypher that actually ran.
  • Threat verdicts return {score, level, factors[], sources[]} plus a source tag. live-explain is fresh scoring. node-cache is the reconciled node verdict the server falls back to when live scoring is briefly down — a valid, labelled verdict, not an error. unavailable means neither path could answer.
  • Feed listings ride on LISTED_IN edges carrying firstSeen, lastSeen and weight, so an agent can tell a three-year-old sighting from a fresh one.
  • query results 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.

WhereShapeValues
explain_indicator rowobject{granularity, scope, sharedHost, dataCoverage?, advisories?, interpretation}. scope: "node-only" means the address itself — not its prefix and not its ASN
whisper.assess / whisper.assessUrlflat string enum, verdict axisknown-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.walkflat string enum, presence axis — no verdict impliedstructural-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 resultper-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 on band or level alone. band:"UNKNOWN" / coverage:"no-data" and band:"NONE" / coverage:"known-clean" both look like "nothing found" and mean opposite things. level: NONE means not listed; band: UNKNOWN means never seen — and the reverse also happens: band:"LOW" with coverage:"malicious-evidenced" looks unremarkable and is not. Measured on 140.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."

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.

text
/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.

text
/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.

text
/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.

text
/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.