MCP documentation menu

Conventions shared by every tool

The rules here apply across the DataPulse tools: how names and URLs are put into canonical form, the hashes that key stored results, how list answers page, what an answer that finds nothing looks like, how a bulk receipt accounts for every input, what is cached, and which access each tool needs. Tool topics refer back to these sections instead of restating them.

Names and URLs

What every name goes through

Every domain / query parameter is put into one canonical form before anything is sent:

StepExample
Surrounding whitespace removed" example.com " → example.com
ASCII case foldedExample.COM → example.com
Unicode label separators folded to . (。 . 。)example。com → example.com
Fullwidth and other compatibility characters mapped (UTS-46)example.com → example.com
IDN converted to its A-label (punycode) formbücher.de → xn--bcher-kva.de
Every trailing dot removed, with any whitespace among themexample.com., example.com.., example.com. . → example.com

The U-label and A-label spellings of a name are the same lookup. A run of trailing dots is input noise, not an empty label: example.com.. is example.com. An empty label anywhere else (a..b.com, .example.com) is refused, and so is whitespace inside a name (exa mple.com).

Refused wherever a domain is required: a URL (https://example.com/path), a port (example.com:8080), credentials, an IP literal (except where a tool takes addresses), a label over 63 bytes or a name over 253, a label starting or ending with a hyphen. The refusal names the reason and nothing is sent.

Names that registries sold but IDNA 2008 forbids (emoji and symbol names, raw or as xn-- punycode) pass local validation in every tool except datapulse_disputedb_lookup, which is strict. The Scrape API then refuses them for scrapes, the domain overview, live DNS and domain health (invalid_url or invalid_domain; invalid_input on a bulk item, as the DNS bulk example in datapulse_help(topic="dns") shows for xn--ls8h.la). Live RDAP accepts them.

Three models: how much of the name is kept

ModelToolsWhat is looked up
Registration: reduced to the registrable domaindatapulse_live_rdap, datapulse_live_rdap_bulk, datapulse_dns_rdap_historyHostname labels above the longest public suffix are removed (full Public Suffix List, private suffixes included): WWW.Example.COM. → example.com, www.microsoft.jp.net → microsoft.jp.net. The two live RDAP tools also take IPv4/IPv6 addresses, in canonical form.
Hostname kept: canonical spelling, no labels removeddatapulse_live_dns, datapulse_live_dns_bulk, datapulse_dns_dphistory, datapulse_dns_dptechsim, datapulse_dns_neighborhood, datapulse_live_domain_health, datapulse_domain_overview, datapulse_disputedb_lookup (domain)Exactly the name given, canonicalized. www.example.com and example.com are different names and are looked up separately.
URLdatapulse_scrape_submit, datapulse_scrape_bulkScheme and host are case-folded and the host canonicalized as above; the port is kept as given, and path, query and fragment are sent byte for byte. Only http: and https: are accepted; credentials, scheme-relative URLs, IP-address hosts and other schemes are refused. A URL without a scheme is tried over https, then http.

Two hostname-kept tools add handling downstream without changing what is sent: the domain-health probe checks both the name and its www. sibling, and DisputeDB matches a leading www. away itself, so www.tesla.com and tesla.com find the same decisions (the response’s query shows the name as sent).

Single labels and underscores

InputAccepted byRefused by
A single label (com, example)datapulse_live_dns, datapulse_live_dns_bulk: a TLD or a bare host is a fair DNS question. localhost and names under it are refused (RFC 6761: the resolver answers them itself)Every other tool, before any request: nothing registrable, hosted, scraped or disputed has fewer than two labels
An underscore in a hostname label (_dmarc.example.com)Every tool. The registration tools reduce it to example.com—
An underscore in the registrable domain (exa_mple.com)The hostname-kept tools except domain healthdatapulse_live_rdap, datapulse_live_rdap_bulk, datapulse_dns_rdap_history, datapulse_live_domain_health: no registry registers such a name

submitted_domain / submitted_url

When the name looked up differs from the input by more than ASCII case (an IDN folded to punycode, a trailing dot dropped, a hostname reduced to its registrable domain), the response carries submitted_domain (submitted_url for datapulse_scrape_submit) with the original input. It is absent when nothing changed, and it keeps a homograph such as instagrạm.com from reading as a report about instagram.com.

ToolEcho
datapulse_live_rdap, datapulse_dns_rdap_history, datapulse_dns_dphistory, datapulse_live_dns, datapulse_live_domain_health, datapulse_domain_overview, datapulse_disputedb_lookupsubmitted_domain field
datapulse_scrape_submitsubmitted_url field
datapulse_dns_dptechsim, datapulse_dns_neighborhoodA hint line after the CSV or rows: submitted_domain: <input> (sent as <name>)
Bulk toolsNo echo; each index maps the canonical item back to the input array

Hashes

Stored results are keyed by SHA-256 hashes of canonical forms. Each is returned by the tool that creates the row, and reading a row back by its hash makes no new lookup.

HashHashesReturned byReads the row back
domain_hashThe canonical domain with a leading www. removedScrape, overview, DNS, RDAP and domain-health toolsdatapulse_live_rdap(domain_hash=...) reads a stored RDAP row; it is also the join key between datapulse_domain_overview, datapulse_live_domain_health and scrape rows
url_hashThe URL’s identity form (below)datapulse_scrape_submit, datapulse_scrape_bulk (sent[].url_hash), every scrape rowdatapulse_scrape_result(url_hash=...), datapulse_scrape_bulk_results(url_hashes=[...])
dns_query_hashThe canonical name as sent (www. kept), with the record type folded in when one was asked fordatapulse_live_dns, datapulse_live_dns_bulk (submitted[].dns_query_hash)datapulse_live_dns(dns_query_hash=...)

A root URL’s url_hash equals its domain’s domain_hash: both hash example.com. The hashes are returned as data; computing them outside the server is not needed.

URL identity

The identity form behind url_hash normalizes more than the request does. These are the same stored page: http:// and https://; with and without a leading www.; host case and U-label / A-label spellings; with and without the default port (:80, :443); with and without a #fragment; a bare trailing / on the root; query parameters in any order; ./.. path segments and their resolved form; percent- encoded and literal spellings of the same character. Path case and a trailing / on a non-root path are significant, and a non-default port is part of the identity.

Paging

List answers are bounded. Each list tool’s description states its default and largest page and the size of a row.

FieldMeaning
totalRows in the whole set (absent where the source cannot count them)
returnedRows on this page
offsetRows skipped before this page
truncatedtrue when more rows exist beyond this page
next_offsetThe offset of the next page, present when truncated is true
noteNames the next call (pass offset=N); a truncated page is a SUBSET of the set
countsPer-category breakdowns beside total, where a tool has them
  • limit absent, 0 or negative means the default; above the maximum it is capped, not refused. A negative offset is refused. The same offset returns the same rows.
  • complete: false is a different signal: the source stopped early (a back-end result cap or compute limit), so paging cannot reach the rest. The remedy is a narrower query, as the hint says. CSV tools put it as a hint line, never inside the rows.
  • A nested list that is capped inside a row carries <field>_total and <field>_truncated beside it.
  • Long text comes in parts: part=N, or text_offset / next_text_offset, each part naming the call for the next.

Arguments

  • An integer or boolean sent as a string ("20", "true", "0.9") is read as the value it spells. A fraction where an integer is required, a value outside the 32-bit range, NaN and infinity are refused with the value sent.
  • JSON null is an absent argument. When a tool chooses a mode from “exactly one of” selectors, a blank string (empty or whitespace) selects nothing either.
  • An argument that belongs to the mode not chosen is refused when it selects something; one holding its documented default (offset: 0, force: false) selects nothing and is accepted.
  • An unknown argument is refused with the list of accepted ones. String arguments have a maximum length, counted in characters; a value echoed in an error is cut to 64 characters.

Answers that find nothing

“No data for this input” is an answer, not an error:

Bulk receipts

datapulse_live_dns_bulk, datapulse_live_rdap_bulk and datapulse_scrape_bulk validate every item before the request; one bad item never costs the batch (a batch with nothing usable is an error).

FieldMeaning
accepted, cached, rejectedThe API’s own counts over the items that were sent: queued, answered from cache, refused by the API
rejected_items (rejected_urls for scrape)What the API refused: index, query (url) and the API’s error code. rejected counts these
rejected_localWhat was refused before the request (malformed, blank, a single label or reserved address where not allowed): index, query (url) and the reason. Not counted in rejected
duplicatesItems that normalize to an earlier item and are not sent: index, the item as written, first_index. DNS and RDAP compare the canonical name (and record type); scrape compares url_hash
submitted (sent for scrape)Every item that was sent, in canonical form, with its hashes and the API’s job_id / cached when it reported them. Sent is not accepted: an item the API refused appears here and in rejected_items

Every index is the position in the array passed. Every input is accounted for:

accepted + cached + rejected + len(rejected_local) + len(duplicates) = number of items passed

Finding every failure takes both rejected_items (rejected_urls) and rejected_local. Each tool’s topic names how its results are read back.

Caching

FamilyCache
Web scrapesA URL scraped successfully in the last 90 days, or whose scrape failed in the last 7 days, is served from storage (cached: true); force=true scrapes again
Live DNSNot cached by the application; only the resolver caches. cached is always 0 on a DNS bulk receipt
Live RDAP (domains)Served from the Scrape API’s cache or the DataPulse database when one holds the name, otherwise looked up live; source says which and force=true looks up live. The bulk tool uses the Scrape API’s 90-day cache
Live RDAP (IPs)A recent RIR answer from cache, otherwise the RIR; force=true refreshes
Domain healthEvery call runs a new probe; the latest report for a domain is kept about 24 hours
History, similarity, clusters, search, UDRP, AGB, applicationsServed from their corpora as of their last load

Access and scopes

Sign-in is OAuth 2.1 with PKCE (S256). The server’s /.well-known/oauth-protected-resource document names the authorization server. Clients identify themselves with a Client ID Metadata Document; the server offers no dynamic client registration. The access token goes in the Authorization: Bearer header only (query-string and form tokens are refused), and the server reads the caller’s permissions from it.

Every request needs the datapulse:mcp permission; without it the answer is 403 insufficient_scope. Each tool also needs the scope below, if any:

ScopeTools
datapulse:dnsdatapulse_live_dns, datapulse_live_dns_bulk, datapulse_live_rdap, datapulse_live_rdap_bulk, datapulse_live_domain_health, datapulse_dns_dphistory, datapulse_dns_rdap_history, datapulse_dns_dptechsim, datapulse_dns_neighborhood, datapulse_dns_regclusters, datapulse_dns_registrar, datapulse_dns_searchlabels, datapulse_disputedb_search, datapulse_disputedb_lookup, datapulse_disputedb_stats
datapulse:scrapedatapulse_scrape_submit, datapulse_scrape_bulk, datapulse_scrape_result, datapulse_scrape_bulk_results, datapulse_scrape_list, datapulse_domain_overview
datapulse:mcp onlydatapulse_help, datapulse_health, datapulse_agb, datapulse_agb_search, datapulse_gtld_applications, datapulse_idn_variants
AnswerMeaning
401No token, or one that failed validation (expired, wrong audience or issuer, bad signature). WWW-Authenticate names the metadata document
403 insufficient_scopeA valid token without datapulse:mcp or without the tool’s scope
403 Origin not allowedA browser request from an origin the server does not accept
429Too many requests for this account in a short time

A tool call runs for at most 120 seconds. Each account may have only a few slow calls (scrapes with wait=true, domain overviews, domain-health checks, bulk submissions) running at once; one more is refused as a tool error saying how many are running.

Generated from the live server (DataPulse MCP v0.9-323-g8d4469c) on October 19, 2026. Your AI assistant reads this page by calling datapulse_help(topic="conventions").