Revised

Tools

Reference for the nine tools the Revised MCP server exposes — arguments, return shapes and refusal codes.

Nine tools, listed in the order an agent should reach for them. Only reveal_domain can spend; everything else is free within the rate limit.

Tool results are JSON, returned as a single text content block. A tool that ran and refused returns a result with isError: true and this shape:

json
{
  "error": {
    "code": "QUOTA_EXHAUSTED",
    "message": "Your reveals for this month are used up.",
    "resets_at": "2026-10-01T00:00:00.000Z"
  }
}

code is UPPER_SNAKE_CASE and is what to branch on. Transport-level failures — rate_limited, insufficient_scope, invalid_token — arrive instead as an HTTP status with no tool result at all; see MCP authentication.

whoami

Read-only. Free. The right first call in any session: everything else is bounded by these numbers.

Takes no arguments.

planstring
free, pro or business. The owner’s plan, resolved on every request — a lapsed subscription reads as free without anything having revoked the credential.
authstring
oauth if the person signed in through their browser, api_key if a key was configured.
client_idstring | null
The OAuth client, on an OAuth session.
key_prefixstring | null
The key’s public prefix, on a key session.
revealsobject
limit (null means no ceiling), remaining, used_this_month, resets_at, and unlimited — the unambiguous form of limit: null, because null reads as “unknown” to a careful model and as zero to a careless one.
rate_limitobject
per_minute, remaining_this_minute, and resets_at — when the current fixed minute window rolls over.
holdsobject
limit (0 means the plan cannot hold) and window_hours.
sync_feedboolean
Whether the REST since change feed is included on this plan.
Example
json
{
  "plan": "pro",
  "auth": "oauth",
  "client_id": "client_2xK9",
  "key_prefix": null,
  "reveals": {
    "limit": 500,
    "remaining": 483,
    "used_this_month": 17,
    "resets_at": "2026-10-01T00:00:00.000Z",
    "unlimited": false
  },
  "rate_limit": {
    "per_minute": 60,
    "remaining_this_minute": 59,
    "resets_at": "2026-09-22T01:48:00.000Z"
  },
  "holds": { "limit": 3, "window_hours": 48 },
  "sync_feed": false
}

The rate-limit window is fixed, not sliding, so remaining_this_minute can read the same before and after a burst simply because the minute turned over.

list_categories

Read-only. Free, and cached. The right call before the first search.

Takes no arguments.

categoriesarray
One entry per code: code, label, listings (how many you can see in it) and open (how many of those are on the open tier, whose names cost no reveal).
countinteger
Number of codes returned.
Example
json
{
  "count": 20,
  "categories": [
    { "code": "saas", "label": "SaaS", "listings": 412, "open": 138 },
    { "code": "education", "label": "Education", "listings": 297, "open": 96 },
    { "code": "fitness", "label": "Fitness", "listings": 88, "open": 31 }
  ]
}

The vocabulary is not a closed list and the counts move, so call the tool rather than caching what it returned. The codes are Revised’s own and are not guessable from a person’s wording: a task about “marketing” or “software” maps onto codes you have to read off this list. search_domains refuses an unknown code rather than answering with an empty shelf, so a guess costs a round trip and teaches nothing.

Some listings carry no category at all. They are in the directory and every other filter reaches them, but no category search returns them, so they are in none of these counts.

search_domains

Read-only. Free and unlimited within the rate limit. It never spends a reveal, and a listing the caller is not entitled to name comes back fully populated with its metrics and a masked domain.

Arguments

querystringpath

Free text over the masked name hint, keyword tags, category and blurb. Maximum 80 characters. Does not search real domain names — searching for a name you already have in mind will not find it. The tags and blurb it reads are not returned on a row, so a match cannot be explained from the response.

categorystringpath

Category code from list_categories, e.g. saas. Comma-separate for several. An unknown code is refused, not answered empty.

tldstringpath

Exact TLD without the dot — com, org, com.au. Comma-separate for several.

tierstringpath

One of open, regular, featured. Comma-separate for several. open names are published on the Revised website, cost no reveal and may be republished — the cheapest place to start. regular and featured are disclosed under the API terms and may not be republished.

spamstringpath

Spam band ceiling: low or moderate.

min_revised_scoreintegerpath

0 to 100, compared against the low end of each listing’s published range. Every listing has one, so this excludes nothing for being unknown.

min_age_yearsintegerpath

0 to 100. Listings whose age is unknown never match; absence is not a zero.

min_citabilityintegerpath

0 to 100 — how often sources that AI assistants cite link to this domain. Listings with no citability row never match.

recommendedbooleanpath

Only listings that clear Revised’s own heuristic: a category of any kind (including the literal other), at least one recognisable linking site, and a Revised Score floor.

sortstringpathdefault: featured

One of age, availability, backlinks, citability, da, featured, newest, price-asc, price-desc, rd, rs, snapshots, spam, value.

featured is the curated shelf. rs Revised Score, rd referring domains, da Domain Authority, newest most recently listed, availability most recently re-checked, spam cleanest first. value and price-desc are the same sort — estimated value, highest first — and price-asc is its reverse. Rows with a null in the sorted field go last. Estimated value and the metric bands each take few distinct values, so expect wide ties; they break on listing id, which is stable but arbitrary.

fieldsstringpathdefault: summary

summary returns the fields a shortlist is ranked on and costs roughly a third of a full row — use it for every first pass. full returns every field, which at the maximum limit is a five-figure token response.

limitintegerpathdefault: 20

1 to 50. Clamped at both ends rather than refused, so 0 reads as 1 and 500 as 50. Budget roughly 60 tokens a summary row and 230 a full one.

An argument outside the values listed here is refused with INVALID_ARGUMENT, naming the argument and the legal set. Nothing is silently dropped, so a filter that was accepted was applied.

Result

listingsarray
The matching rows, summary or full per fields.
countinteger
How many rows you were handed.
totalinteger
How many matched.
truncatedboolean
count < total. Stated rather than implied, so a short page is not read as “that is everything”.
fieldsstring
Which mode produced these rows.
Example
json
{
  "count": 2,
  "total": 91,
  "truncated": true,
  "fields": "summary",
  "listings": [
    {
      "id": "00aLaXEG",
      "domain": "greenfieldfarms.com",
      "name_disclosed": true,
      "tier": "open",
      "tld": "com",
      "revised_score": "61-70",
      "referring_domains": "100-500",
      "domain_authority": "20-30",
      "citability": 47,
      "age_years": 14,
      "category": "education",
      "spam": "low",
      "availability_checked_at": "2026-09-19T08:02:14.771Z",
      "metrics_missing": []
    },
    {
      "id": "X00w46xl",
      "domain": "t▓▓▓▓▓▓labs",
      "name_disclosed": false,
      "tier": "regular",
      "tld": "com",
      "revised_score": "64-70",
      "referring_domains": "50-100",
      "domain_authority": null,
      "citability": null,
      "age_years": null,
      "category": "saas",
      "spam": "low",
      "availability_checked_at": "2026-09-20T11:40:02.118Z",
      "metrics_missing": ["age_years", "agent_citability", "domain_authority"]
    }
  ]
}

On a summary row, domain carries the public partial mask when name_disclosed is false. name_disclosed is the test, not the presence of a mask: a mask is on every row whether or not anything is masked. A mask is something to show a person, never something to hand a registrar.

get_domain

Read-only. Free. One listing, every field — how you read closely the handful of rows a summary search shortlisted.

idstringpath

A listing id from a search_domains result, e.g. k3mq7x2p. Eight characters, case-sensitive.

namestringpath

A registrable domain name, e.g. example.com. Resolves only for a name you are already entitled to: an open-tier listing, one this account has already revealed, or — on a plan with no reveal ceiling — any listing.

Any other name reports not-found whether or not it is in the directory: Revised will not confirm that a masked name is listed. A masked row’s domain is a mask, so passing one back here will not resolve it.

Returns the full listing — the same field set the REST GET /api/v1/domains/{id} returns, including backlinks, snapshots, linked_by, agent_citability, estimated_value_cents, hold_state, hold_expires_at, mask_hint, discovered_at and updated_at.

reveal_domain

Idempotent: calling it again for the same listing is free and returns the same revealed_at. It also records the reveal, which is what hold_domain requires.

idstringpathrequired

The listing id.

Result

The full listing with its real name, plus:

revealed_atstring
When this account first revealed it.
was_freeboolean
Whether this call spent anything.
reasonstring | null
Present when was_free is true: open_tier (the name is already public), already_revealed (bought earlier) or unlimited_plan (the plan has no reveal ceiling).
remaining_revealsinteger | null
What is left this month. null on a plan with no ceiling.
Example
json
{
  "id": "00aLaXEG",
  "domain": "greenfieldfarms.com",
  "name_disclosed": true,
  "tier": "open",
  "revealed_at": "2026-09-22T01:47:10.334Z",
  "was_free": true,
  "reason": "open_tier",
  "remaining_reveals": 483
}

The response reports the cost rather than leaving it to be inferred. The REST equivalent does not: POST /api/v1/domains/{id}/reveal returns the listing plus revealed_at only.

Refusals

codeMeaning
QUOTA_EXHAUSTEDThe month’s allowance is gone. The refusal carries resets_at; retrying before then will not work.
FEATURED_REQUIRES_PROA free plan against a curated listing. Search with tier: "open" instead.
HELD_BY_OTHERAnother account holds it. The refusal carries no timestamp — read hold_expires_at off the listing for when it frees up. Who holds it is never disclosed.
NOT_FOUNDNo such listing, or one that has left the directory.

hold_domain

Reserve a listing inside Revised so no other account can reveal or take it while someone decides. Costs no reveal, but requires that this account has already revealed the listing — a name disclosed by an unlimited plan is not a reveal on record.

idstringpathrequired

The listing id.

Returns hold (id, listing_id, held_at, expires_at, can_extend, extend_hours) and holds (active, limit, hold_hours, plan).

Example
json
{
  "hold": {
    "id": "h_01K6M2QX",
    "listing_id": "00aLaXEG",
    "held_at": "2026-09-22T01:50:00.000Z",
    "expires_at": "2026-09-24T01:50:00.000Z",
    "can_extend": true,
    "extend_hours": 24
  },
  "holds": { "active": 1, "limit": 3, "hold_hours": 48, "plan": "pro" }
}

Use it when shortlisting for someone else to approve: it is cheaper than revealing repeatedly, and it is the only way to keep a candidate from under another account.

Refusals

HOLDS_REQUIRE_PRO (the plan allows no holds), REVEAL_REQUIRED (reveal it first), HELD_BY_OTHER, HOLD_CAP_REACHED (release one first), HOLD_COOLDOWN (your own hold on this listing ended in the last 30 days; available_at says when — anybody else may hold it now), NOT_FOUND.

list_holds

Read-only. Free. This account’s holds, never anybody else’s.

Takes no arguments.

activearray
Holds running now. Each carries its domain, because holding a listing required revealing it first.
endedarray
The most recent holds that have ended, each with ended_at and an outcome of expired, released or registered.
holdsobject | null
active, limit, hold_hours, plan.

Holds are account-scoped, not credential-scoped: every key and every OAuth session on the account sees, extends and can end the same holds.

extend_hold

Push one of your holds’ expiry back by extend_hours, the window the plan allows. Free, and it takes no slot against the cap — the hold is already yours.

hold_idstringpathrequired

A hold id from list_holds or hold_domain.

Returns hold and holds, as hold_domain does.

Once per hold. can_extend says whether the extension is still on the table; once taken it is false and ALREADY_EXTENDED is the answer to asking again. The time is added to expires_at, not to now, so an extension taken early loses nothing.

Refusals: ALREADY_EXTENDED, HOLD_OVER, HOLD_NOT_FOUND, HOLDS_REQUIRE_PRO.

release_hold

Destructive. End one of your holds early and give the listing back. Free, and it frees a slot against the cap immediately.

hold_idstringpathrequired

A hold id from list_holds or hold_domain.

outcomestringpathdefault: released

released if you are giving it back, registered if you have registered the name yourself. expired is not accepted — that outcome belongs to the clock.

ended_atstring
When the hold ended.
outcomestring
released or registered, as passed.
registrationstring | null
Only on a registered release, and only when the re-check answered: available, taken or unknown. unknown is not the same as available.
holdsobject
The quota after the release.

Say registered when you have: it triggers a fresh availability check and retires the listing if the name now resolves, which keeps it from being offered to anybody else.

Argument refusals

Every tool refuses an out-of-range or out-of-enum argument with INVALID_ARGUMENT, naming the argument and listing the legal values, and INVALID_REQUEST when a required argument is missing.

json
{
  "error": {
    "code": "INVALID_ARGUMENT",
    "message": "`tier` must be one of: featured, open, regular.",
    "argument": "tier"
  }
}

Nothing is filtered, guessed or silently dropped, so fix the value and call again. A filter that was accepted was applied — which is the point: a wrong answer indistinguishable from a right one is the worst shape a tool result can take.

Type to search…

↑↓ navigate openesc close