Skip to main content
Glama

Server Details

Meta and TikTok advertising analytics with ads, creatives, advertisers, rankings and six workflows.

Ownership verified
Status
Healthy
OAuth
Works in Glama
Last Tested
Transport
Streamable HTTP
URL
Repository
Spytrend/spytrend-mcp
GitHub Stars
0

TDQS

A4.4/5.0

Scored across 21 tools

Disambiguation5/5

Tools are cleanly separated by resource and action: search_* browses/list metadata, get_* fetches full entity detail, find_similar_* handles relationship discovery, and get_media/add_to_favorites/list_favorites cover delivery and saved items. Overlaps are explicitly disambiguated in descriptions (e.g., find_similar_ads vs find_similar_creatives, search_ads vs get_ad).

Naming Consistency5/5

All names use consistent snake_case verb_noun patterns across predictable families: search_*, get_*, find_similar_*, add_to_*/list_*, and get_usage. Minor length variance does not break the convention.

Tool Count4/5

21 tools are slightly above the typical 3-15 band but justified by the breadth of entities (ads, creatives, webmasters, advertisers, shops, hubs) and supporting operations (analytics, trends, favorites, usage). No redundant tool clearly could be dropped.

Completeness4/5

Read/query coverage is strong across ads, creatives, webmasters, advertisers, shops, hubs, trends, and media. Minor gap: favorites support add and list but no removal/delete or update operation, which agents may need for lifecycle management.

Available Tools

21 tools
add_to_favoritesAdd to favouritesA
Idempotent
Inspect

Save a SELECTION of entities to one of the caller's favourites folders so they can review them later on spytrend.com. entity_type is creo (creatives), webmaster, ad, hub (a hub profile from search_hubs) or shop (a shop domain from search_shops); ids is the list of entity ids from search_ads / search_webmasters / search_creatives / search_hubs / search_shops. For entity_type=hub you MUST also pass hub (the hub slug the ids came from, e.g. 'ecommerce'). folder is OPTIONAL — PREFER a short descriptive name from the user's search (e.g. 'Gambling ads US · Jun 2026'), created automatically if absent; if omitted, a stable dated folder is used. Idempotent — items already in the folder are reported as already_saved, never duplicated or re-charged. BILLING: saving an ad (including multilang) costs 1 token and saving a creative costs 10 tokens; saving does not include another ad media opening; saving a webmaster, a hub profile or a shop is FREE. Already-saved items cost nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault
hubNoREQUIRED only when entity_type=hub: the hub slug the ids came from (the same 'hub' you passed to search_hubs, e.g. 'ecommerce', 'facebook', 'amazon')
idsYesthe entity ids to save (from search_ads / search_webmasters / search_creatives / search_shops results; for entity_type=hub these are the hub profile ids/domains from search_hubs; for entity_type=shop these are the shop domains from search_shops)
folderNoOPTIONAL folder name; created if absent. PREFER a short descriptive name from the user's search context (e.g. 'Gambling ads US · Jun 2026'). If omitted, a stable dated folder ('AI saved ads · YYYY-MM-DD') is used
entity_typeYeswhat kind of entity to save: creo (creative), webmaster, ad, hub (a hub profile from search_hubs) or shop (a shop domain from search_shops)

Output Schema

ParametersJSON Schema
NameRequiredDescription
addedYes
failedNo
folderYes
entity_typeYes
already_savedYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotentHint=true and destructiveHint=false, so the description's idempotency statement aligns but adds value by explaining already_saved behavior and billing details. It also discloses that saving incurs costs for ads and creatives but is free for others, which is crucial for agent decisions. However, it does not detail output schema, but since idempotency and cost are covered, a 4 is appropriate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and well-structured, with key information front-loaded (what it saves and what entity types are supported), followed by specific requirements and billing. Every sentence serves a purpose, and the use of bold for critical notes (MUST, OPTIONAL, BILLING) enhances scannability without waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having an output schema, the description still explains return behavior (already_saved) and billing, which are not fully captured in the schema. It covers all necessary details for correct invocation: entity type mapping, source of IDs, special hub requirement, folder naming guidance, and cost implications. This is complete for an agent to use safely.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the description largely repeats parameter info. It adds minimal extra meaning, like clarifying that 'ids' must come from search results and that 'hub' is only required for hub entity type, but this is already in the schema descriptions. The billing details per entity_type add some value but not beyond what the schema implies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool saves a selection of entities to favorites folders, naming the valid entity types and how IDs are sourced. It distinguishes itself from sibling search and get tools by focusing on the save action, and the detailed breakdown of entity types and required parameters makes the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly explains when to use this tool (to save entities for later review) and provides guidance on prerequisite sources (search_* tools), the required hub parameter for hub entities, and folder naming preferences. It also indicates when it is not applicable (e.g., no duplication) and implies alternatives like list_favorites for reviewing saved items.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_similar_adsFind related adsA
Read-only
Inspect

Find ads related to one source ad by an explicit overlap basis: fanpage (same Facebook page_id) or domain (same exact landing_domain). This is entity overlap, NOT visual similarity of the material; use find_similar_creatives for that. The source ad is excluded from data, but pagination.total remains the upstream overlap-candidate count before that exclusion; source_excluded and total_semantics make this explicit instead of fabricating an adjusted exact total. Metadata only, cursor-paginated. QUOTA: 1 token per delivered row (default page 20).

ParametersJSON Schema
NameRequiredDescriptionDefault
ad_idYessource ad UUID from search_ads
basisYesoverlap basis: fanpage (same Facebook page_id) or domain (same exact landing_domain)
limitNomaximum metadata rows (default 20, maximum 200; 1 token per delivered row)
cursorNopagination cursor returned by the previous call

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
paginationYes
basis_valueYes
source_ad_idYes
source_excludedYes
total_semanticsYes
similarity_basisYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation, it reveals the source ad exclusion, the pagination.total semantics, the existence of source_excluded and total_semantics fields, and the quota cost per row. This added context explains edge cases an agent might otherwise misinterpret.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and information-rich, with each sentence serving a purpose (purpose, distinction, output semantics, quota). It is slightly verbose but well-structured and front-loaded with the core action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (pagination, output schema, annotations), the description covers behavioral quirks, quota, and alternative tools. It fully compensates for anything not obvious from the schema or annotations, making it complete for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the description adds little beyond the schema for parameters. It does reinforce the meaning of basis, but the schema already describes all parameters adequately; no new parameter-level insight is provided.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb (find) and resource (ads related to one source ad) with an explicit overlap basis (fanpage or domain). It distinguishes itself from visual similarity tools by directly naming find_similar_creatives, making the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states when to use (entity overlap on fanpage/domain) and when not to (not visual similarity) along with the alternative tool. This gives clear selection guidance relative to siblings without any ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_similar_creativesFind creatives that look the sameA
Read-only
Inspect

Find creatives that look the same as one creative, using the production similarity index. This is visual similarity, not exact creative membership. threshold_status distinguishes an explicitly requested threshold from the production default; result_status=bounded_native_cap means the upstream similarity endpoint exposes at most 20 candidates and has_more is conservative at that cap. Returns metadata without media URLs; use get_media for selected ids. QUOTA: 1 token per delivered row.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNomaximum metadata rows to return (default 20, maximum 20)
thresholdNooptional maximum visual difference between two creatives (0 uses the production default; maximum 128 — lower is stricter)
creative_idYessource creative UUID from search_creatives

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
has_moreYes
thresholdYes
result_statusYes
similarity_basisYes
threshold_statusYes
source_creative_idYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

While readOnlyHint and destructiveHint already indicate a safe read operation, the description still adds meaningful behavior beyond annotations: threshold_status vs production default, result_status=bounded_native_cap meaning the upstream faces at most 20 candidates and has_more is conservative, the absence of media URLs, and QUOTA per delivered row. This is valuable operational context for an agent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description opens with the core behavior, then adds disambiguation, boundary behavior, output-usage guidance, and quota in a compact set of sentences. Each sentence carries information an agent needs; there is no filler or omitted critical nuance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a lightweight read-oriented tool with a strong schema, an output schema present, and helpful annotations, this description fills in exactly the gaps an agent cannot get from structured data: quota cost, upstream candidate cap, default threshold behavior, and which parameter to use. No critical external context is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already has 100% description coverage for the three params, so the baseline is 3. The description improves on that by explaining threshold semantics more concretely and by documenting that result cap is 20 and conservative, which directly makes limit and threshold more useful. It does not belabor the already-documented parameter types/defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action and resource: 'Find creatives that look the same as one creative' using a named mechanism, the production similarity index. It also adds an explicit disambiguation—'This is visual similarity, not exact creative membership'—which helps an agent distinguish this tool from exact-match or metadata-based search tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly establishes the intended context: given one creative, retrieve visually similar creatives. It also gives follow-up guidance ('Returns metadata without media URLs; use get_media for selected ids') and clarifies semantics around threshold and result caps. It stops short of naming sibling tools like search_creatives or find_similar_ads for explicit when-not-to-use conditions, so it is not quite a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_similar_webmastersFind similar webmastersA
Read-only
Inspect

Find other webmasters sharing normalized URL-parameter values with a source webmaster. First call get_webmaster_similarity_facets, then pass one returned param_key; optionally narrow to selected values. similarity_basis is url_parameter_overlap and rarity_count shows how many webmasters share the value. Results are deterministically ordered and bounded by the canonical source cap of 5000; result_status/result_cap/total_status state whether that bounded set is complete. QUOTA: 1 token per delivered row (default page 20).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNomaximum rows to return (default 20, maximum 200; 1 token per delivered row)
offsetNozero-based deterministic result offset
valuesNooptional subset of normalized source values for this param_key
param_keyYesURL parameter key returned by get_webmaster_similarity_facets
webmaster_idYessource webmaster UUID from search_webmasters

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
limitYes
offsetYes
has_moreYes
param_keyYes
result_capYes
total_statusYes
result_statusYes
similarity_basisYes
source_webmaster_idYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnlyHint, openWorldHint, destructiveHint), the description discloses deterministic ordering, a bounded result cap of 5000, status fields (result_status/result_cap/total_status) for completeness, a quota of 1 token per row, and a dependency on a prior facets call. This is rich behavioral context that the annotations alone do not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well-organized, leading with the core purpose, then the workflow, then behavioral details, and finally quota. Every sentence adds value with no filler. The structure supports quick comprehension by an agent.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 5 parameters, 2 required, and an output schema present, the description covers the necessary invocation steps, behavioral constraints, quota, and dependency on another tool. The output schema handles return structure, so nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the baseline is 3. The description adds meaning by explaining that param_key comes from the facets call, webmaster_id comes from search_webmasters, and values is an optional subset of normalized source values. It also clarifies the role of similarity_basis and rarity_count as output concepts, which helps the agent understand the data flow beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific function: finding webmasters that share normalized URL-parameter values with a source webmaster. It explicitly names the mechanism (url_parameter_overlap) and the required dependency on get_webmaster_similarity_facets, distinguishing it from sibling tools like find_similar_ads or search_webmasters.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a clear workflow: first call get_webmaster_similarity_facets, then pass one returned param_key, optionally narrowing to selected values. It gives explicit prerequisites and ordering but does not explicitly compare against alternative tools or state when not to use it, which would make it a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_adGet ad by id (with media)A
Read-only
Inspect

Fetch a single ad by its id with FULL details including its creative media: the full ad TEXT in body, body_chars (its length in UTF-8 characters), title, creative URL, geos, status, advertiser. body is absent when the ad genuinely has no text; body_chars is absent when the length could not be read — never read an absent field as zero. Media urls on media.spytrend.com are permanent; a media entry with expiring=true is the original signed Facebook CDN link of a not-yet-mirrored fresh ad — it dies within hours/days, NEVER put it into reports or exports (re-fetch the ad later for the permanent link). QUOTA: 50 tokens for a multilang-upload ad opening; 1 token for an ordinary ad. The price includes the available media returned with this card. Each new opening call is charged separately; no subscription to an individual ad is created. A blurred card or a response without usable media is not charged. With source=tiktok: 100 tokens per delivered TikTok row. MULTILANG CONTENT: get_ad and get_media(ad) use the same full detail carousel. primary_creative identifies its selected first creative; primary_creative_selection.status describes selected, fallback or unavailable. carousel_position is the original 1-based carousel position, not the returned array index. Missing/unconfirmed selected primary media is not charged or disclosed; both tools report primary_creative_unavailable. Per-slide title/body/link_url describe that slide; when the API omits a slide override, the ad-level value is supplied as its fallback, consistently in both tools. original_landing_domain describes the original ad, while creative_destination_url/domain describe the primary creative's destination. cloaking_detected is a detected domain/copy mismatch, not a verified redirect or a guarantee that a creative is black. Actual per-call debit is reported in _meta.billing.tokens_charged, in Spytrend quota tokens (not model tokens); admin may be exempt.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesthe ad id to fetch (with source=tiktok: a TikTok ad id from search_ads source=tiktok results)
sourceNoad corpus: meta (default, 1 token — delivers the ad's media) or tiktok (⚠️ 100 tokens per TikTok ad row; Pro plan required)

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
sourceNo
tiktok_dataNo

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavioral context beyond the readOnlyHint/openWorldHint/negative-destructive annotations: it details quota semantics (50/1/100 tokens), the live status of unsigned expiring CDN links (never put in reports), billing debits via `_meta.billing.tokens_charged`, no-charge edge cases (blurred cards, no usable media), no subscription behavior, field-absence semantics (body_index), and primary_creative selection status. This is rich, actionable behavior that far exceeds the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is thorough but long and dense, with many paragraphs and repeated references to the shared carousel used by both tools. It front-loads 'Fetch a single ad by its id' and then layers a large amount of billing and media edge-case detail. Every sentence does add value, yet the volume of information could overwhelm the average agent; there is no pruning or prioritization.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Backed by a high coverage schema and output schema, the description still adds edge cases that are not present in structured data: body-field absence logic, the `expiring` CDN flag and its consequences, billing charge rules, `_meta.billing.tokens_charged`, and also the special behavior when source=tiktok. Considering the complexity of the tool and the provided schemas, this description is highly complete, although it could leave a few niche topics (e.g., error codes for non-existent ad IDs) to inference.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema has 100% description coverage for both parameters: `id` and `source` already have robust descriptions including source default and pricing. The tool description adds pricing side-effects and source-specific price warnings (`source=tiktok` in provenance), but does not add any meaning about parameter syntax, types, or constraints beyond what the schema defines. Baseline 3 is appropriate because the schema carries the weight.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Fetch a single ad by its id with FULL details including its creative media'—clearly distinguishing it from siblings like get_creative or get_media. It also enumerates exact fields returned (text, body_chars, title, creative URL, geo, status, advertiser), making the tool's scope unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The context of use is implied: call this when you need a single ad's full details by ID. However, it does not explicitly state when to choose this tool over get_media or get_creative, aside from a note that get_media(ad) has the same detail carousel. The source=tiktok switch is described, but no alternative pathway or 'do not use when' guidance is given, so the description carries only implied usage direction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_ads_analyticsGet ads selection analyticsA
Read-only
Inspect

Get the bounded analytics overview for the current Meta /ads selection: total and display_total plus statuses, countries, AI categories, landing domains, advertisers and webmasters. This is a Pro-or-higher paid surface; every delivered breakdown row costs 1 token, pending/error responses refund the reservation. The default is 10 rows per section and the absolute maximum is 20; results are flattened in data with a dimension field and include section readiness/truncation metadata. Totals are nullable: null with pending/unavailable status is NOT zero; exact zero is numeric 0 with an exact status. Only the status section removes its own filter; every other section uses the full filtered universe. No pagination, sorting, source, scheduler, force-scrape, TikTok, raw SQL or storage coordinates are accepted. Auto-applied subscription categories are reported in auto_applied_verticals and scope_note. Re-issue the identical call after retry_after_seconds when pending; do not blindly retry paid calls.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryNofree-text filter, at most 100 UTF-8 bytes
savedNosaved scope: all
dedupeNocollapse duplicate creative rows
channelNomessaging shortcut: whatsapp or telegram
countryNolegacy single ISO-2 include country; prefer countries
date_toNoFacebook launch upper bound YYYY-MM-DD
page_idNoFacebook page id or bounded facebook.com page URL
pixel_idNobounded Facebook pixel identifier
countriesNounique uppercase ISO-2 include countries, maximum 200
date_fromNoFacebook launch lower bound YYYY-MM-DD
folder_idNonon-zero favorite folder UUID
languagesNotarget language slugs, maximum 50
platformsNoMeta publisher placements, maximum 6
search_inNoquery scope: all, title, advertiser or text
categoriesNoAI category slugs, maximum 50
cta_buttonsNoCTA labels, maximum 50
hub_domainsNonormalized destination hostnames, maximum 50
media_typesNomedia types: image or video
parsing_geoNoone uppercase ISO-2 parser GEO
resolved_ipNoresolved IPv4/IPv6 address
search_termNohistorical search term, at most 100 UTF-8 bytes
domain_zonesNolowercase landing TLD/zone labels, maximum 50
hub_categoryNoclosed top-level hub category
status_todayNocurrent status: active, inactive or vanished
webmaster_idNonon-zero webmaster UUID
advertiser_idNonon-zero advertiser UUID
country_matchNocountry semantics: any or only
first_seen_toNoSpyTrend discovery upper bound YYYY-MM-DD
max_countriesNomaximum additional/total GEOs, 0 disables, maximum 200
ai_subcategoryNotaxonomy-valid AI subcategory slugs
days_active_toNonon-negative active-days upper bound; null omits the filter, 0 is meaningful
favorites_onlyNorestrict to the token-derived user's favorite webmaster scope
impressions_toNonon-negative impressions bucket upper bound
landing_domainNonormalized landing hostname
max_page_likesNonon-negative page-like upper bound; null omits the filter, 0 is meaningful
media_count_toNonon-negative media-count upper bound
min_page_likesNonon-negative page-like lower bound
platforms_modeNoplacement semantics: any or all
first_seen_fromNoSpyTrend discovery lower bound YYYY-MM-DD
min_days_activeNonon-negative active-days lower bound
ai_enriched_onlyNoonly AI-enriched ads
creative_formatsNocreative formats: video, carousel, single or dynamic
impressions_fromNonon-negative impressions bucket lower bound
media_count_fromNonon-negative media-count lower bound
ai_confidence_minNominimum AI confidence: low, middle or high
contains_in_linksNotracking-link fragment, at most 255 UTF-8 bytes
fan_page_categoriesNovalidated fan-page category groups
landing_domain_exactNorestrict landing domain to exact hostname
max_items_per_sectionNorows per breakdown section, default 10, maximum 20

Output Schema

ParametersJSON Schema
NameRequiredDescription
winNo
dataYes
tierYes
totalYes
domainsYes
pendingYes
statusesYes
countriesYes
ai_labeledYes
from_cacheNo
scope_noteNo
webmastersYes
advertisersYes
computed_atNo
total_statusYes
ai_categoriesYes
display_totalYes
result_statusYes
sections_readyYes
sections_totalYes
display_total_basisNo
retry_after_secondsNo
display_total_statusYes
auto_applied_verticalsNo

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description adds substantial behavioral context beyond that: it is a paid surface with token costs per row, pending/error responses refund the reservation, totals are nullable with null meaning pending/unavailable (not zero), only the status section removes its own filter, and results are flattened with dimension field and truncation metadata. This is rich, non-obvious behavior that an agent needs to know.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well-structured: it front-loads the core purpose, then covers cost, limits, return shape, null semantics, filter behavior, exclusions, and retry guidance. Every sentence carries information. It is long, but the tool is complex (49 parameters, paid surface, nuanced null semantics), so the length is justified. It loses one point for being a wall of text without paragraph breaks, which slightly reduces scannability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (49 parameters, paid surface, output schema present), the description is remarkably complete. It covers cost, limits, null semantics, filter behavior, exclusions, retry guidance, and subscription category reporting. The output schema exists, so return values need not be described in detail. An agent has everything needed to call this tool correctly and avoid costly mistakes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description adds meaningful parameter-level context beyond the schema: it explains the default and maximum rows per section (10/20), which maps to max_items_per_section; it clarifies that totals are nullable and the distinction between null and numeric 0; and it notes that auto-applied subscription categories are reported in auto_applied_verticals and scope_note. It doesn't enumerate every parameter, but the schema already covers them, and the description adds the critical semantic nuances.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Get the bounded analytics overview for the current Meta /ads selection' and enumerates the exact breakdown dimensions (statuses, countries, AI categories, landing domains, advertisers, webmasters). It clearly distinguishes this from sibling search tools by emphasizing it is an analytics overview for the current selection, not a search or retrieval tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use this tool: for bounded analytics on the current /ads selection, and it names exclusions: 'No pagination, sorting, source, scheduler, force-scrape, TikTok, raw SQL or storage coordinates are accepted.' It also provides operational guidance: re-issue after retry_after_seconds when pending, do not blindly retry paid calls. This is strong usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_advertiserGet advertiser by idA
Read-only
Inspect

Fetch a single advertiser's FULL card by id — the same data as the spytrend.com/advertisers page: name, external_id (FB page id), avatar_url, page_url, total_ads and active_ads (EXACT precomputed counts — THIS is the cheap way to answer 'how many ads / how many are active does this advertiser run', NOT paginating search_ads, whose total is estimated for advertiser_id), launched_14d, top_countries (geo breakdown), platforms, top_landing (destination domains), page_like_count (followers), born (founded date), categories and recent creatives. The card also embeds top_creatives — the advertiser's MOST RE-UPLOADED creatives (a creative's total_ads = how many ads reuse the same material, ordered desc, media stripped/free); present these as the headline at the end and download with get_media (entity_type=creo). The id is an advertiser UUID (from an ad's advertiser_id / get_trends dimension=advertisers) OR a Facebook page id — a fanpage id from get_creative's fanpages, or an ad's page_id: a page id is resolved to its advertiser automatically, so a fanpage you found in a creative resolves straight to its card. A pasted facebook.com page link (any form — vanity name, profile 100…-id, profile.php, Ads Library) is likewise resolved to the page automatically. To list the advertiser's ads, call search_ads with advertiser_id. CATEGORY COUNTERS CONTRACT category_total_ads / subcategory_total_ads and every top_categories[].ads_count / top_subcategories[].ads_count count ONLY the advertiser's AI-LABELED ads - they are a share of the labeled subset, NOT of the page's ad universe. The labeling share is ai_coverage (labeled / total_ads). Read them as: 'N of total_ads ads are labeled (ai_coverage), and X% of THOSE are '. Never compare category_total_ads against total_ads/active_ads directly, and never report a category share as the advertiser's overall vertical mix when ai_coverage is low. QUOTA: 1 token (one entity card). TOP_CREATIVES CONTRACT each top_creatives entry's total_ads counts the creative's FULL family of matching material across the whole serving universe as the market-wide reuse of that creative; note the family may span MORE advertisers than this page — it is the creative's market-wide reuse, not this advertiser's share.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesthe resource id to fetch

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true and openWorldHint=true, but the description goes far beyond: it discloses that the returned card includes exact precomputed counts, that top_creatives are the most re-uploaded creatives with media stripped, and that category counts are only for AI-labeled ads. It also discloses quota (1 token) and the top_creatives contract regarding market-wide reuse. No contradiction with annotations; the description adds rich behavioral context that annotations alone do not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but most content is essential given the tool's complexity (many fields, nested contracts, interpretation rules). It is front-loaded with the core purpose and a list of fields, then procedural nuances. Some redundancy (e.g., repeating 'top_creatives' explanations) could be trimmed, but overall it is packed with actionable detail and avoids fluff. Not as succinct as possible, but justified.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema existing (indicated by context), the description explains return contents thoroughly: the list of fields, the special semantics of counts (exact vs labeled), the top_creatives contract, and quota. It covers all practical aspects an agent needs to call the tool correctly, including id resolution and interpretation of metrics. No missing information is apparent for a correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema describes 'id' only as 'the resource id to fetch' (generic). The description vastly enhances meaning: id can be an advertiser UUID or a Facebook page id, and provides multiple sources (ad's advertiser_id, get_trends dimension, get_creative's fanpages, page_id, or pasted Facebook link). It also explains automatic resolution of page ids and links. This far exceeds schema coverage and gives an agent concrete guidance on constructing the id value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states the tool fetches a single advertiser's full card by id and enumerates all contained fields (name, external_id, avatar_url, page_url, total_ads, active_ads, etc.). It distinguishes itself from search_ads by positioning itself as the exact-count source and mentions alternatives like get_media and search_ads for other purposes. The verb 'Fetch' and resource 'advertiser's full card' make the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit usage directives: it is the cheap way to get exact ad counts, and warns against paginating search_ads for that. It also instructs to call search_ads when listing an advertiser's ads, explains how to resolve IDs (UUID, page id, Facebook link), and details how to interpret category counters and ai_coverage. It includes a clear exclusion (do not compare category counts to total_ads directly) and naming of alternatives, satisfying the 'when-not' criterion.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_creativeGet creative details and breakdown by idA
Read-only
Inspect

Fetch ONE creative's metadata plus its canonical bounded breakdown by id: activity period/quality, max_days_active with max_days_active_source/max_days_active_quality, delivery_languages with explicit legacy provenance, aggregate counts, advertisers, fanpages, landing domains, webmasters and geos. The ambiguous legacy languages alias is intentionally omitted. When a speech transcript has already been generated for a video, copy_languages is returned separately with copy_language_source=cached_asr_transcript and copy_language_scope=spoken_audio; it describes spoken audio only, not title/body or visual OCR. copy_language_status is available for measured confidence >=0.8, available_low_confidence below that, available_unscored when the provider supplied no probability, and unavailable when there is no valid cached result. This read never starts transcription. Breakdown lists are sorted by ad count desc and capped at 1000 rows; each dimension has its own *_status, _returned and (where a snapshot cardinality exists) _count/_truncated/_count_status. breakdown_status is available_bounded only when every dimension query completed, partial when at least one dimension is unavailable, and unavailable when the breakdown endpoint itself failed. The id is a creative UUID from search_creatives. Media URLs are intentionally excluded; download with get_media (entity_type=creo, same id). Fanpage ids feed the search_creatives fanpages filter and search_ads page_id. QUOTA: 1 token (one entity card).

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesthe resource id to fetch

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint and openWorldHint annotations, the description discloses extensive behavioral specifics: it never starts transcription, breakdown lists are sorted and capped at 1000, status values are explained (available_bounded, partial, unavailable), copy_language statuses are detailed, and media URLs are intentionally excluded. There is no contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Though lengthy, the description is densely packed with essential details and every sentence serves a purpose. It is logically ordered: core fields, language specifics, breakdown behavior, id source, media exclusion, and quota. No fluff or repetition, and the most critical purpose is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with this many status codes, edge cases, and output nuances, the description leaves nothing critical uncovered. It explains all breakdown statuses, language copy statuses, sorting/capping behavior, and the quota, making it sufficient for an agent to call correctly without opening the output schema. Complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema describes the id as 'the resource id to fetch' with 100% coverage. The description adds crucial semantics: the id is a creative UUID from search_creatives and the same id is used for get_media, providing provenance and cross-tool linkage that the schema alone lacks. This elevates it above the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool fetches one creative's metadata and its bounded breakdown by id, listing specific fields like activity period, languages, and aggregates. It differentiates itself from siblings by noting the id comes from search_creatives and that media URLs are handled by get_media, making its purpose distinct and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: when you need detailed creative metadata by UUID, especially from search_creatives. It also points to get_media for downloading media and mentions that fanpage ids feed other search filters, giving practical guidance. However, it doesn't explicitly state scenarios where one should NOT use this tool over alternatives, leaving some inference to the agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_mediaGet creative media (download URLs)A
Read-only
Inspect

Fetch downloadable creative MEDIA (image/video URL + thumbnail) for 1-500 ad or creative UUIDs returned by search_ads / search_creatives. This is the paid delivery step. entity_type is 'ad' or 'creo'. Existing clients keep the {entity_type,items:[{id,media:[{media_type,url,thumbnail_url,fallback_urls}]}]} fields; additive counts, partial and failures explain malformed, quota-limited and unavailable items, plus interrupted items when at least one peer was delivered. Malformed/zero UUIDs never reach the API or consume quota; valid peers in a mixed batch are still processed. duplicate_count reports canonical duplicates, which are fetched and billed once. IMPORTANT: a media URL can become unavailable, so if url returns an HTTP error (e.g. 416/404), retry fallback_urls in order before treating it as unavailable. Typical flow: search_ads (browse metadata, 1 token per row) → pick ids → get_media. QUOTA: 50 tokens per delivered multilang-upload ad, 1 per ordinary ad, 10 per creative-catalogue item (free starter: 500 tokens total; paid plans: 40,000/month). The ad price is per returned ad, not per media file. Actual ad membership determines the price even without a preceding filtered search. Every new call is billed; get_ad already includes media, so do not call get_media again for files you already received. Invalid, missing or undelivered items are not charged. Mixed batches examine a quota-bounded prefix and return affordable items with explicit failures for the rest; an unexamined tail may contain affordable ordinary ads, which can be requested separately. get_usage is free. MULTILANG CONTENT: get_ad and get_media(ad) use the same full detail carousel. primary_creative identifies its selected first creative; primary_creative_selection.status describes selected, fallback or unavailable. carousel_position is the original 1-based carousel position, not the returned array index. Missing/unconfirmed selected primary media is not charged or disclosed; both tools report primary_creative_unavailable. Per-slide title/body/link_url describe that slide; when the API omits a slide override, the ad-level value is supplied as its fallback, consistently in both tools. original_landing_domain describes the original ad, while creative_destination_url/domain describe the primary creative's destination. cloaking_detected is a detected domain/copy mismatch, not a verified redirect or a guarantee that a creative is black. Actual per-call debit is reported in _meta.billing.tokens_charged, in Spytrend quota tokens (not model tokens); admin may be exempt.

ParametersJSON Schema
NameRequiredDescriptionDefault
idsYes1 to 500 ad or creative UUIDs to resolve (from search_ads / search_creatives results); malformed ids are reported per item and never consume quota
entity_typeYeswhat kind of media to fetch: 'ad' (creative media of ads from search_ads) or 'creo' (media of creatives from search_creatives)

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
partialYes
failuresNo
entity_typeYes
valid_countYes
attempted_countYes
delivered_countYes
duplicate_countYes
requested_countYes

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial behavior beyond the annotations: quota token costs, per-item failure handling, mixed-batch prefix processing, duplicate handling, fallback_urls retry on HTTP errors, and multilang content behavior. It even explains what happens to malformed/zero UUIDs. No contradiction with the readOnlyHint/destructiveHint annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is thorough but extremely long and dense, with many details that duplicate the output schema, such as the response fields block. It is front-loaded with the core purpose, but it would benefit from bullets or sectioning to improve scanability. While much of the content is valuable, it is not concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers an unusually complete set of edge cases: quota billing, partial failures, mixed batches, fallback URLs, duplicate items, multilang selection, and pricing rules. Given the output schema exists, nothing critical appears missing for an agent to correctly select, invoke, and interpret the results of this paid endpoint.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already documents both parameters with 100% coverage, including the entity_type enum and the ids array limits. The description adds operational context such as billing and malformed-id handling, but it does not meaningfully enrich the semantic meaning of the parameters beyond what the schema already provides, so the baseline score of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action and resource: 'Fetch downloadable creative MEDIA (image/video URL + thumbnail) for 1-500 ad or creative UUIDs returned by search_ads / search_creatives.' It also says it is the 'paid delivery step,' which gives an immediate sense of why this tool exists and how it differs from free browsing tools. It distinguishes itself from get_ad by warning against duplicate fetching.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides an explicit typical flow: 'search_ads ... → pick ids → get_media.' It also gives clear exclusion guidance: 'get_ad already includes media, so do not call get_media again for files you already received,' and notes 'get_usage is free.' This is strong when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_shopGet shop by domainA
Read-only
Inspect

Fetch one domain surface's FULL profile. Primary visits is the monthly estimate for traffic_as_of; fetched_at is ingestion time. traffic_sources is typed, while a separate legacy snapshot is kept alongside, and its similarly named traffic fields are not interchangeable with primary visits. the estimate's page title is not a canonical company/brand name; a missing rank on a subdomain is not evidence that the parent domain has no rank. domain_created is the best available registrable-root registration date, not product launch; its per-row RDAP/WHOIS-vs-legacy-fallback provenance is not retained in ClickHouse. ads_monthly/ads_burn use first_parsed_date and mark the open month is_complete=false. fb_signal is correlation_only. The domain/subdomain may be a funnel, runtime, blog or redirect rather than a company/product; inspect registrable_domain and surface_type. Includes AI-ad-category breakdown, recent ads and products. To save it use add_to_favorites (entity_type=shop, ids=[domain]). QUOTA: 1 token (one entity card).

ParametersJSON Schema
NameRequiredDescriptionDefault
domainYesthe shop domain to fetch (e.g. 'example.com'), as returned by search_shops

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses important data-quality caveats beyond the annotations: traffic estimates, legacy snapshots, non-canonical page titles, correlation-only AI signals, missing rank behavior, and quota consumption. These are exactly the non-obvious behaviors an agent needs to interpret results correctly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and long, but nearly every sentence carries a distinct warning or clarification that prevents misuse. The core purpose is front-loaded, and the additional caveats are organized around the returned fields rather than random trivia.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists, the description focuses on field semantics, entity-type caveats, quota cost, and the follow-up save action. It covers the important interpretation pitfalls and operational constraints without needing to restate the full return shape.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already describes the domain parameter well, and the description adds context about domain surfaces and the correct ID for saving. However, the added value over the schema is moderate; most parameter meaning comes from the schema itself.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly identifies the action ('Fetch') and resource ('one domain surface's FULL profile') with a specific domain parameter. The description also clarifies what the profile does and does not represent, which prevents misclassification of the entity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context: use it to fetch a single domain surface, and explicitly redirects saving to add_to_favorites with the correct entity type and parameter shape. It also tells the agent to inspect registrable_domain and domain surface type to avoid misreading the entity, though it does not contrast directly with the sibling search tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_usageGet usage / quotaA
Read-onlyIdempotent
Inspect

Return the caller's current MCP quota: plan, tokens used, remaining and limit (free starter = 500 tokens total forever; paid plans = 40,000/month ≈ 2,000 default-page searches; Enterprise = personal limit via support). Token costs: 1 per delivered result (an ad/webmaster/advertiser row, a trends row, an entity card), ordinary ad media = 1, multilang-upload ad opening = 50, creative media = 10, TikTok row = 100. Each opening call is billed separately. You pay only for results actually delivered (short pages auto-refund). This call is FREE — it consumes no quota.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNo
planYes
usedYes
limitYes
windowYes
reset_atNo
remainingYes
unlimitedNo
server_versionNo
multilang_ad_open_tokensYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, openWorldHint=true, idempotentHint=true, and destructiveHint=false. The description adds genuinely non-obvious behavior: 'This call is FREE — it consumes no quota,' plus the auto-refund billing nuance. No contradiction with the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The main purpose is front-loaded in the first sentence, and the token-cost tariff is genuinely useful context for cost-aware calling. It loses a point because ~100 words of billing detail appear as one dense unformatted paragraph for a tool with no parameters; light structure (bullets or separation of quota semantics from tariffs) would improve digestibility.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 0-parameter, read-only tool with a full annotations set and an output schema available, the description is complete: it names the returned fields (plan, tokens used, remaining, limit), explains the plan tiers, and discloses that the call itself costs nothing. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters and schema_description_coverage is 100% (it's an empty object), so the baseline of 4 for 0-parameter tools applies. The description appropriately does not fabricate parameter details; there is nothing more to add beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb+resource: 'Return the caller's current MCP quota: plan, tokens used, remaining and limit.' The quota resource is clearly distinct from all ~20 sibling tools, which target ads, webmasters, creatives, shops, trends, or favorites, so an agent can tell this tool apart without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to call it — to see the current plan, token count, and limits — and it emphasizes the call is free, which is exactly the information an agent needs before making costly searches. There is no sibling quota tool, so explicit 'when-not-to-use' instructions or alternative names would add little; a small deduction for not explicitly stating when to prefer it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_webmasterGet webmaster by idA
Read-only
Inspect

Fetch a single webmaster (affiliate NETWORK) by UUID: aggregate stats PLUS top_creatives — the creatives this webmaster re-uploads the MOST, ordered by the webmaster's OWN in-slice ad count (slice.ads_in_slice desc — the deliberate slice order, matching what the profile page shows), media stripped/free. Each entry's total_ads is the creative's market-wide family size, folded best-effort from family redirects and floored at ads_in_slice — total_ads == ads_in_slice therefore often means 'family cards not yet built', not 'this webmaster owns the whole market'; it is context, not the sort key. analytics_pending=true means the canonical PostgreSQL identity exists but its ClickHouse aggregate is not published yet, so zero counters are not analytical zeroes. fanpages_status explicitly reports advertiser-aligned lifecycle enrichment as available, partial, unavailable or not_applicable; an omitted fanpages array is therefore never evidence that a page is alive. The id MUST be the canonical UUID returned by search_webmasters; domain names and display names are rejected instead of silently widening to the whole database. Present top_creatives as the headline final step; for the rest of the network use search_creatives?webmaster_id / search_ads?webmaster_id, and download media with get_media (entity_type=creo). identifier_inventory_semantics explains why historical page/domain/pixel inventory counts are not comparable to total_ads. attribution_link_stats.merge_edges answers WHY these identifiers sit in one network: each entry is a {page_id, page_name, domain, ads} pair — that fanpage ran exactly that many ads on that landing domain, and such a pair is what merges two networks into one (an ad whose domain belongs to network A and whose fanpage belongs to network B fuses them permanently). Weigh the edges before claiming a single operator: a 1-3 ad edge next to 100+ ad edges is a thin bridge, typically a catalog/feed ad, and is weak evidence of shared ownership; identifiers with no edge at all are inherited from earlier merges and prove nothing today. QUOTA: 1 token (one entity card). TIKTOK: with source=tiktok this fetches the TikTok cluster card instead (business-id rollup, same UUID space as search_webmasters source=tiktok results) — ⚠️ costs 100 tokens and requires a Pro-or-higher plan; the Meta-only embeds (top_creatives, attribution link-stats) are omitted on the TikTok card.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesthe webmaster UUID (from search_webmasters — same id space for both corpora)
sourceNowebmaster corpus: meta (default, FREE) or tiktok (⚠️ 100 tokens for the TikTok cluster card; Pro plan required)

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnly/openWorld/non-destructive, but the description adds substantial behavioral context: top_creatives ordering semantics, total_ads interpretation as market-wide family size, analytics_pending meaning, fanpages_status nuance, strict UUID rejection, TikTok token cost and Pro-plan requirement, and edge-weighting caveats for attribution merge edges. No contradiction with annotations exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but densely packed, with every sentence carrying a distinct operational warning or semantic clarification. It is front-loaded with the core purpose and uses recognizable labels like QUOTA and TIKTOK to structure auxiliary details. Nothing reads as filler or tautology.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with intricate output semantics, the description is remarkably complete: it explains ambiguous fields, quota costs, plan requirements, source variants, and interpretation pitfalls. The presence of an output schema covers the raw return shape, while the description covers the semantics that the schema cannot express.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds value beyond the schema by explaining that id must be the canonical UUID from search_webmasters and that domain names/display names are rejected. Source semantics are already in the schema enum description, so the added parameter insight is limited but meaningful.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Fetch a single webmaster (affiliate NETWORK) by UUID: aggregate stats PLUS top_creatives'. It clearly identifies what the tool returns and distinguishes it from sibling search tools by emphasizing single-entity retrieval by canonical UUID. The TikTok variant is also explicitly differentiated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit routing guidance: use this tool for a single webmaster card, use search_creatives/search_ads for the rest of the network, and get_media for downloading creatives. It also states a hard precondition: the id must be the canonical UUID from search_webmasters, with domain/display names rejected. This leaves no ambiguity about when to invoke this tool versus alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_webmaster_similarity_facetsGet webmaster similarity facetsA
Read-onlyIdempotent
Inspect

List the URL-parameter keys and normalized values that can be used to find related webmasters. Similarity here means shared affiliate/tracking parameter values, not name or domain similarity. Returns only facets that have at least one other webmaster match. FREE.

ParametersJSON Schema
NameRequiredDescriptionDefault
webmaster_idYessource webmaster UUID from search_webmasters

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
webmaster_idYes
similarity_basisYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only, idempotent, non-destructive behavior, and the description adds meaningful specifics: normalized values, only facets with at least one other match, and FREE. This goes beyond what annotations communicate without contradicting them.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three concise sentences with the core purpose front-loaded and no filler. Every sentence adds information: what is returned, what similarity means, and the inclusion filter.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter, read-only tool with a rich output schema and strong annotations, the description covers purpose, scope, filtering behavior, and constraints. Nothing critical is missing for invoking it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the only parameter's description already says it is the source webmaster UUID from search_webmasters. The tool description adds no additional parameter semantics, matching the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('List') and a concrete resource ('URL-parameter keys and normalized values') and clarifies that similarity means shared affiliate/tracking parameter values, not name or domain similarity. This distinguishes the tool from similarity-oriented siblings such as find_similar_webmasters.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context: use it to get URL-parameter facets for related webmasters, and explicitly excludes name/domain similarity. It doesn't name a sibling alternative like find_similar_webmasters or state a when-not condition beyond the similarity definition, so it falls short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_favoritesList favouritesA
Read-onlyIdempotent
Inspect

List the caller's favourites folders (name, entity_type, item_count). Pass entity_type (creo/webmaster/ad/hub/shop) to filter; omit it to list folders across all types. Pass folder (a folder name) to instead return the ITEMS inside that folder: entity ids for creo/webmaster/ad (usable with get_creative / get_webmaster / get_ad), resolved hub profiles (hub + id + label) for hub folders, and domains for shop folders. Use this to confirm what add_to_favorites saved and to read a folder back. FREE — does not consume quota.

ParametersJSON Schema
NameRequiredDescriptionDefault
folderNoOPTIONAL folder name; when set, returns the ITEMS inside that folder (ids for creo/webmaster/ad — usable with get_creative/get_webmaster; resolved hub profiles for hub folders; domains for shop folders) instead of the folder list. If a name matches folders of several types, pass entity_type to disambiguate
entity_typeNooptional filter: creo, webmaster, ad, hub or shop; omit to list folders of all types

Output Schema

ParametersJSON Schema
NameRequiredDescription
foldersNo
folder_contentsNo

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and nondestructive behavior; the description adds quota info ('FREE — does not consume quota') and explains the different item representations returned per folder type (ids, hub profiles, domains). No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but not bloated: it states the return shape, both parameter modes, the recommended use, and the quota effect in about four sentences. Every sentence carries operational value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema and rich annotations, the description still adds enough to call the tool confidently: return fields for the folder list, exact item-return behavior for the folder parameter, how to disambiguate duplicate names, and quota impact. No important operational gap remains.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents both parameters fully; the description largely restates the same mode information and even the disambiguation caveat ('pass entity_type to disambiguate') that appears in the schema. It adds a little value by tying ids to get_creative/get_webmaster/get_ad, but does not substantially extend the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource, 'List the caller's favourites folders (name, entity_type, item_count)', and then clarifies the two modes: folder listing and folder contents. It also names the related tool add_to_favorites, so an agent can see how this read operation fits.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit instructions about when to omit entity_type (all folders), when to pass it (filter), and when to pass folder (return items). It also states the purpose: 'Use this to confirm what add_to_favorites saved and to read a folder back.' It does not mention explicit exclusions, but no sibling tool overlaps directly with favourites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_adsSearch adsA
Read-only
Inspect

Search the spytrend.com ad database and return ad METADATA: title, body_chars (the LENGTH of the ad text in UTF-8 characters), landing domain, status, geos, activity, advertiser, ai_enrichment (ai_category/media_type), media_count and creative-format metadata. The ad TEXT ITSELF is deliberately NOT in list rows — an average body is ~1.1k characters and would bloat a 20-row page 20-80x; fetch the text for a specific ad with get_ad, and use body_chars plus min_body_chars/max_body_chars to find the ads worth opening. The visible /ads Format filter targets creative_formats (video/carousel/single/dynamic); publisher placements are filtered separately via platforms. The downloadable creative media is NOT included here — fetch it with get_media using the returned ids. Filters: keyword (query), country/countries (multi-geo), platforms, categories (ai_category slug), ai_subcategory, status_today (active/inactive/vanished), advertiser_id, webmaster_id, landing_domain, media_type; languages, formats (creative_formats: video/carousel/single/dynamic), cta_buttons, domain_zones, search_in (which field query matches: all/title/advertiser/text), platforms_mode (platforms any/all); point lookups pixel_id / page_id / resolved_ip and contains_in_links (tracking fragments like pixel_id=/sub1=/utm); ranges min_days_active/days_active_to, min_page_likes/max_page_likes, min_body_chars/max_body_chars (ad-text length in characters; both directions cover only ads with known non-empty text), date_from/date_to (Facebook launch date — THE axis for 'new ads in a window': new = launched on Facebook then; first_seen_from/to is the date we first indexed the ad, which also catches late-indexed OLD ads — never use it for market newness); max_countries (with selected countries: additional GEOs outside them; without selected GEO: total GEOs), dedupe (unique creatives only), and saved/folder scopes (saved=all, folder_id). Sort with sort_by + sort_order. Use sort_by=most_reused_creative to rank the selected results by how many ads share the same creative; rows include same_creative_ads_in_selection and other_ads_with_same_creative for the selected filters, plus same_creative_ads_lifetime and advertisers_using_same_creative for the lifetime catalog. creative_match_type=exact identifies the matching contract and creative_reuse_status=exact|unavailable qualifies the counts. For most_reused_creative the absolute number of distinct creative groups is intentionally unavailable/null; page with has_more and next_cursor instead of retrying for a total. To find ads on a domain use landing_domain — NOT query. Cursor pagination via next_cursor; pagination always includes total and total_status (exact/estimated/unavailable), plus counted_at/count_cached for exact analytical totals. Any closed launch OR discovery window of at most 31 calendar days completes a raw exact unique-ad count in-call. A discovery request with exactly one country plus optional AI category/subcategory filters can instead use the canonical daily cube for an exact count across up to 90 inclusive days, or from first_seen_from through today; no other filters may be present on that cube path. Other wider/open combinations use the normal estimated/unavailable contract, and malformed/reversed dates are rejected. An exact count that includes today is exact for ads ingested so far, while analysis.includes_open_utc_day and data_complete_through make the incomplete tail explicit. status_today always means CURRENT state: with a date window, active is the currently-active survivors of that selected cohort, not historical activity on each date. Except for the intentional most_reused_creative group-total omission described above, unavailable means the async count did not settle inside this call: the number is PENDING, not zero and not a measurement; re-issue the identical call in a few seconds to obtain it (analysis.count_note repeats this warning in-band). NEVER present an unavailable count as 0. With categories set, matches and totals cover AI-LABELED ads only — a labeled SUBSET of the market (analysis.category_semantics=ai_labeled_ads_only_not_comparable_to_extrapolated_trends); get_trends aggregates for the same category×geo are extrapolated market estimates and will always be larger — never cross-compare the two. For an advertiser's or webmaster's EXACT ad count (total AND active), do NOT paginate search_ads — call get_advertiser / get_webmaster. To download the creatives, pass the ids to get_media; to SAVE them, pass the ids to add_to_favorites. Respects the caller's plan/verticals. For aggregate rankings use get_trends. MULTILANG UPLOAD: formats=[carousel_multilang] selects the same detected carousel pattern as the website; carousel_multilang_categorized selects its AI-categorized subset. This is independent of the languages filter. Formats combine with OR, so do not combine the base and categorized variants when requesting only categorized results. Search remains 1 token per row; opening a matching ad with get_ad or get_media costs 50 tokens. QUOTA: 1 token per DELIVERED result (default page 20 = 20 tokens; short pages auto-refund). Results carry metadata only; get_ad/get_media charge 50 tokens per multilang-upload ad opening, 1 per ordinary ad, and get_media charges 10 per creative-catalogue item. Each new opening call is billed separately. Meta search_ads rows include is_multilang and opening_price (Spytrend tokens per ad per call); unavailable/null means the price could not be verified, not zero. Opening quotes are not a debit or a price lock. Request small limits and narrow filters. TIKTOK SOURCE: pass source="tiktok" to query the TIKTOK ad corpus instead of Meta. (The platforms filter does NOT do this — platforms are Meta publisher placements.) ⚠️ TIKTOK IS PAID PER ROW at a premium: every DELIVERED TikTok ad row costs 100 tokens and every TikTok webmaster row/card costs 100 tokens (Meta rows cost 1), deducted from the same token balance (paid plans: 40,000/month = up to 400 TikTok rows). Request small limits and narrow filters; you are charged only for rows actually delivered (short pages auto-refund; if the balance covers only part of the request, that part is delivered — a 3-row request on a 150-token balance returns 1 row and charges 100). TikTok requires a Pro-or-higher plan: free/starter callers and unlinked agents get an actionable upgrade refusal, never data and never a charge. TikTok rows have their OWN shape, returned under tiktok_data (verified live 2026-07-30): id/external_id (TikTok ad id), advertiser{id,external_id,name} plus advertiser_id (TikTok BUSINESS id), start_date/end_date (the ad's delivery window) and first_seen_date/last_seen_date (SpyTrend indexing), days_active, is_active + status_today, ai_category/ai_subcategory, countries + targeting_geos + targeting_details (OS/age/gender/regions), audience_size, objective, sponsor (the 'paid for by' funder) and registry_location, landing_domain + link_url, body/title/call_to_action, creative_format, creative_id, creative_ad_count (how many ads reuse that creative), is_blurred/is_cloaked, and media[] with media_type + thumbnail_url on media-tt.spytrend.com. Media comes WITH the row — do NOT call get_media for TikTok ids (it serves Meta entities only). There are no TikTok engagement counters (plays/likes/comments/shares) on this surface. The TikTok feed serves the ARCHIVED TikTok corpus — exactly what the spytrend.com /ads TikTok tab shows — and pagination carries has_more/next_cursor plus total with total_status (exact, estimated or unavailable; unavailable is not zero). With source=tiktok: Supported TikTok filters: query/search_in, country/countries, country_match, categories, ai_subcategory, languages, formats (single|carousel|video), landing_domain, advertiser_id (TikTok business id), webmaster_id, contains_in_links, media_type, cta_buttons, domain_zones, status_today (active|inactive), min_days_active/days_active_to, max_countries, dedupe, date_from/date_to (delivery-window overlap), sort_by=date|days_active, sort_order, limit, cursor. Countries overrides country. Categories and ai_subcategory combine with OR on TikTok. title and text both search the ad text; advertiser searches the advertiser name. date_from/date_to selects ads whose delivery window overlaps the requested inclusive period, not ads launched in that period. Active means shown within the last 3 calendar days. Unsupported filters (including hub_domains, folder_id, saved and landing_domain_exact) are REJECTED before charging; no filter is silently ignored. Default TikTok limit is 10; each delivered row costs 100 tokens.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNomax ad rows to return (maximum 200). Meta defaults to 20 at 1 token per delivered row; TikTok defaults to 10 at 100 tokens per delivered row.
queryNofree-text keyword to match in ad title, body or link
savedNosaved scope selector. Use saved=all to restrict results to ads saved in ANY favorites folder, matching the saved-ads view on /ads.
cursorNopagination cursor from a previous response's next_cursor
dedupeNowhen true, collapse duplicates so each unique creative appears once
sourceNoad corpus to search: meta (default — the Facebook/Meta library, 1 token per delivered row) or tiktok (the TikTok corpus — ⚠️ PAID: 100 tokens per DELIVERED TikTok ad row, embedded media links included; Pro plan required; default limit drops to 10). platforms=[tiktok] does NOT do this.
channelNomessaging channel the ad sends traffic to: whatsapp or telegram. Filters to ads landing on that channel's chat domains (whatsapp: api.whatsapp.com/wa.me/chat.whatsapp.com; telegram: t.me). Use for 'ads/bundles going to WhatsApp/Telegram'.
countryNosingle ISO country code filter (legacy form, e.g. US, BR, DE). Prefer countries[] for UI parity and multi-country requests.
date_toNoMeta: only ads whose Facebook launch date is on or before this date (YYYY-MM-DD); combine with date_from in a closed window of at most 31 calendar days for an exact in-call total. TikTok: delivery-window overlap; the first delivery date must be on or before date_to
formatsNocreative formats: video, carousel, single, dynamic, carousel_multilang, carousel_multilang_categorized. Multilang upload detection is independent of languages; the categorized variant additionally requires an AI category. Values combine with OR. Search costs 1 token per row; opening a multilang ad costs 50 tokens.
page_idNopoint lookup: only ads from this Facebook page id; also accepts a pasted facebook.com page link in any form (vanity, profile id, profile.php, Ads Library view_all_page_id) — resolved to the canonical page id automatically
sort_byNoTikTok: date or days_active only. Meta: order results by: date (default, newest first), most_popular, folder_added or most_reused_creative. most_reused_creative ranks ads by how many ads share the same exact creative within the selected filters and dates; default/desc gives most reused first, asc gives least reused first. It requires a specific advertiser/page/pixel/webmaster/query/landing-domain/creative anchor or a launch/discovery window of at most 31 days. Rows include semantic same-creative reuse counts and creative_reuse_status. folder_added is only meaningful on folder-scoped or saved=all views; most_popular is the Trending preset ranking
pixel_idNopoint lookup: only ads carrying this Facebook pixel id
countriesNoISO country codes to filter by. Mirrors the /ads UI multi-country picker. With country_match=any (default) an ad matches when at least one selected geo is present; with country_match=only every known geo must belong to this set.
date_fromNoMeta: only ads whose Facebook launch/delivery start date is on or after this date (YYYY-MM-DD). THE canonical date axis for 'new ads in a window' questions — new means LAUNCHED ON FACEBOOK in that window, not indexed by spytrend. Combine with date_to in a closed window of at most 31 calendar days for an exact in-call total. TikTok: delivery-window overlap; the last delivery date must be on or after date_from, not necessarily the launch date
folder_idNorestrict results to ads saved in this favorites folder UUID. Mirrors the /ads favorites page scope.
languagesNoISO language codes the ad targets (e.g. en, pt, es). The /ads Language filter.
platformsNoplatform names to include (e.g. facebook, instagram)
search_inNowhich field the free-text query matches: all (default), title, advertiser or text. The /ads search-scope toggle.
categoriesNoAI category slugs to include. Use the underscore slug form, e.g. gambling_and_betting, ecommerce_and_retail, finance_and_banking, dating_and_relationships, healthcare_and_medical, impersonation_funnels, crypto_and_trading (NOT short words like 'gambling')
media_typeNofilter by creative media type: image or video
sort_orderNosort direction: asc or desc (default desc)
cta_buttonsNocall-to-action button labels (e.g. Shop Now, Learn More, Sign Up, Download). The /ads CTA filter.
hub_domainsNoexact hub/destination domains to filter landings by (e.g. linktr.ee, wa.me). The visible /ads Hub filter sends these; hub_category stays the coarse category form. When channel is also set, the explicit domains and channel domains are combined deterministically into one OR-list.
resolved_ipNopoint lookup: only ads whose landing domain resolves to this IP
domain_zonesNolanding-domain TLD/zone without the dot (e.g. com, shop, online, xyz). The /ads domain-zone filter.
hub_categoryNofilter to ads whose landing destination is in this TOP-LEVEL hub category. Valid slugs: social, app_stores, shortlinks, amazon, ecommerce, popular, platforms (NOT 'social_media' — the slug is 'social'). For a specific messaging channel use the channel param instead - hub_category does NOT accept whatsapp/telegram sub-slugs.
status_todayNocurrent status: active, inactive or vanished
webmaster_idNoreturn only ads from this webmaster id (from search_webmasters)
advertiser_idNoreturn only ads from this advertiser id (from search_advertisers)
country_matchNohow the countries filter matches: any (default, overlap semantics) or only (strict subset semantics). The /ads UI sends any explicitly when countries are selected.
first_seen_toNoonly ads spytrend first INDEXED on or before this date (YYYY-MM-DD) — internal discovery date, not the Facebook launch date; for 'new ads' questions use date_from/date_to. See first_seen_from for exact-total windows
max_countriesNowith countries or country selected, allow at most this many additional GEOs outside that selected set; without a selected GEO, allow at most this many total GEOs
ai_subcategoryNoAI subcategory slugs to include under the chosen ai_category set. Mirrors the visible /ads subcategory drill-down.
days_active_toNoupper bound of the days-active range — only ads running at most this many days
landing_domainNolanding domain filter. By default it preserves the historical /ads behavior: match this hostname AND its subdomains. Set landing_domain_exact=true to restrict to the normalized hostname itself only.
max_body_charsNoonly ads whose AD TEXT is at most this many characters long (UTF-8 characters, not bytes). Ads with no text are NOT returned as length 0 — the length filters cover only ads with known non-empty text. Combine with min_body_chars for a closed length range, e.g. 100..500
max_page_likesNoonly ads from pages with at most this many likes
min_body_charsNoonly ads whose AD TEXT is at least this many characters long (UTF-8 characters, not bytes). Both length filters match only ads whose text length is KNOWN and non-zero: ads with no text at all are outside the length axis entirely and are returned by neither direction. Pairs with the body_chars field returned on every row; the ad text itself is served by get_ad, not by this list
min_page_likesNoonly ads from pages with at least this many likes
platforms_modeNohow the platforms filter combines: any (OR, default) or all (AND — the ad must run on EVERY selected platform). The /ads platform match-mode toggle.
first_seen_fromNoonly ads spytrend first INDEXED on or after this date (YYYY-MM-DD) — an internal discovery date, NOT the ad's Facebook launch date. Do NOT use it for 'new ads recently' questions: spytrend also indexes OLD ads late, so late-indexed old ads would pollute the answer — use date_from/date_to (Facebook launch) for market newness. Exact totals: any closed window up to 31 days; a single-country request with only AI-category filters can use the canonical daily cube for up to 90 days or from this date through today
min_days_activeNoonly ads running at least this many days (e.g. 30 → long-running 'winning' ads). Lower bound of the days-active range
contains_in_linksNomatch a fragment inside the ad's tracking links - e.g. a pixel id, sub id or UTM fragment like 'pixel_id=123', 'sub1=', 'utm_campaign=xyz'
landing_domain_exactNowhen true, restrict landing_domain to the normalized hostname itself and exclude subdomains. Mirrors the /ads UI exact-host toggle.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
metaNo
sourceNo
analysisNo
paginationYes
tiktok_dataNo
auto_applied_verticalsNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover read-only/open-world safety, but the description adds extensive behavior beyond them: per-row token billing (1 vs 100 for TikTok), the 40,000/month cap, Pro-plan gating with refund/partial-delivery semantics, exact vs estimated vs unavailable count contracts, the 'unavailable is not zero, re-issue' rule, and the most_reused_creative group-total omission.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded with the return-shape constraint and routing, but it is extremely long and repetitive — the token/quota model and the TikTok premium are re-explained multiple times, and the filter list duplicates the schema. For a 45-parameter tool some length is warranted, but the verbosity costs readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 45 parameters, no required params, an existing output schema, and a complex billing/counting contract, the description covers everything an agent needs: filters, sorting, pagination, exact-count windows, plan restrictions, and TikTok-specific shape and cost. Nothing essential is omitted.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3; the description still adds meaning such as 'use landing_domain — NOT query' for domain lookups and the category-vs-trends semantics. However, much of the per-filter detail (keyword, status_today, ranges) merely restates schema-documented parameters, so it does not rise far above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (search) and resource (the spytrend.com ad database) and immediately scopes what is returned (ad METADATA, not ad text). It distinguishes itself from siblings by naming get_ad for text, get_media for creative download, get_trends for aggregates, and get_advertiser/get_webmaster for entity counts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing rules are given for nearly every alternative: use get_ad for ad text, get_media for downloadable creative, add_to_favorites to save, get_trends for rankings, and do NOT paginate search_ads for advertiser totals. It also warns which date axis to use (date_from/date_to vs first_seen_from) and when not to cross-compare category totals with get_trends.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_advertisersSearch advertisersA
Read-only
Inspect

Search advertisers by NAME, numeric Facebook page id, or a pasted facebook.com page link (typeahead; query ≥2 chars). A link in any form (vanity name, profile 100…-id, profile.php, Ads Library view_all_page_id) and either id namespace resolve to the canonical fanpage with the exact match first. Returns advertisers with external_id and ad_count. To fetch ONE advertiser's full card by id use get_advertiser; to see an advertiser's ads, call search_ads with advertiser_id. For advertiser RANKINGS, ordering and filters (category/country/followers/founded-date/life_status/hubs), use get_trends with dimension=advertisers. FREE PLAN COUNTS: when the plan's archive window narrows a request, pagination.total_status is "restricted" and meta.plan_window_cutoff names the boundary — the count then describes the window actually searched, NOT the one requested, so a zero means "nothing in the archive window" and never "nothing exists". QUOTA: 1 token per DELIVERED result from your plan balance (free starter: 500 tokens lifetime; paid plans: 40,000/month; short pages auto-refund — you pay only for results you receive). Default page is 20 results = 20 tokens; pass limit (1–200) to size it. get_usage is free. Autonomous agents must be linked to a spytrend account to access data — an unlinked agent gets an actionable connect-your-account refusal (create agent credentials at spytrend.com/settings?tab=ai, or a human claims it by client_id), NOT a server error. Calls are rate-limited per authenticated user (deployment defaults: 60/minute and 1000/hour); a rate-limit refusal is an MCP tool error with structured error.code=rate_limit_exceeded, scope, window and retry_after_seconds. CONCURRENCY: heavy analytical calls (get_trends, search_ads, search_creatives) are admitted ONE AT A TIME per account — fanning out 5-10 of them in parallel does not go faster, it returns admission refusals for all but one. Issue heavy calls sequentially; light lookups (get_ad, get_advertiser, get_usage) are not gated.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNomax results, 1-50 (default 20 — this typeahead is capped at 50 upstream; a larger value is clamped, not rejected). Each delivered result costs 1 token.
queryNoadvertiser name (at least 2 characters), a numeric Facebook page id (either the Ads Library page id or the direct-page profile 100…-id), OR a pasted facebook.com page link in any form (vanity, profile.php, Ads Library) — links and ids resolve to the canonical fanpage with the exact match first

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNo
itemsYes
totalNo

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond the minimal readOnlyHint=true and destructiveHint=false. It discloses quotas, rate limits (60/min, 1000/hr), concurrency gating for 'heavy' calls, free-plan archive window restrictions, and the meaning of pagination.total_status='restricted'. It even explains that a zero means 'nothing in the archive window', preventing misinterpretation. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but deliberately front-loaded: first sentence states the core purpose, then immediately differentiates alternatives, then dives into quota/rate-limit/concurrency details. Every section serves a real decision the agent faces. While dense, it avoids redundancy and earns its length given the tool's operational complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with quota, rate limits, concurrency gates, and a free-plan special case, the description covers every conceivable decision point: how to size pages, what errors look like, how to connect an unlinked agent, and what happens when the archive window shrinks. The existence of an output schema means return-value details need not be spelled out. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both parameters are already described in schema. The description adds actionable details beyond schema: query must be ≥2 chars, a link in any form resolves to canonical fanpage with exact match first, limit defaults to 20 but is clamped to 50 upstream (not rejected). These are value-add semantics, not just repetition.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb+resource ('Search advertisers') and specifies exactly the three input forms accepted (name, numeric page id, or pasted link). It explicitly distinguishes itself from siblings: get_advertiser for one full card, search_ads for ads, get_trends for rankings. No ambiguity remains about what this tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use versus alternatives is given: 'To fetch ONE advertiser's full card by id use get_advertiser; to see an advertiser's ads, call search_ads with advertiser_id. For advertiser RANKINGS, ordering and filters ... use get_trends with dimension=advertisers.' It also explains when to expect restricted results and how to handle them. This is textbook usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_creativesSearch creativesA
Read-only
Inspect

Browse and filter Meta creative families (source=meta only; TikTok callers must use search_ads with source=tiktok and dedupe=true) and return metadata only. Filters include country/countries, exclude_countries, categories, ai_subcategory, media_type/media_types, domain_zone, advertiser_id/advertiser_ids, webmaster_id, fanpages, hub_domains/channel, active_ads_today_from, last_seen_from/to, period_from/to, max_countries, min_geo_share, folder_id and saved=all. last_seen_from/to is creative activity eligibility; period_from/to (date_from/to aliases) is the independent in-period window for ads_in_period. Sort by relevance, total_ads, ads_in_period/reuploads, active_ads, last_seen or fb_created. With an advertiser/webmaster slice, pagination.sort_semantics=slice_ordered_by_webmaster|slice_ordered_by_advertiser and slice.ads_in_slice is the ordering key. total_ads remains the lifetime whole-family count; ads_in_period is the count for the selected period on the backend-reported date axis. Always read pagination.period_axis: first_seen means first discovery by SpyTrend; facebook_start_date means launch on Facebook after the verified launch-generation cutover. query/search_in searches the texts of the creative family's ads; all query words must match the family. Cursor-paginated. Download with get_media and save with add_to_favorites. QUOTA: 1 token per DELIVERED result (default page 20 = 20 tokens; short pages auto-refund). Results carry metadata only; get_ad/get_media charge 50 tokens per multilang-upload ad opening, 1 per ordinary ad, and get_media charges 10 per creative-catalogue item. Each new opening call is billed separately. Meta search_ads rows include is_multilang and opening_price (Spytrend tokens per ad per call); unavailable/null means the price could not be verified, not zero. Opening quotes are not a debit or a price lock. Request small limits and narrow filters. PERIOD PARITY CONTRACT: the /creo web filters ai_subcategory, hub_domains[] and active_ads_today_from are available here too. last_seen_from/to filters the creative's LAST recorded activity and does not change count semantics. period_from/period_to is the independent inclusive window used for ads_in_period; date_from/date_to are compatibility aliases. A closed explicit period enables ads_in_period automatically. sort_by=ads_in_period or reuploads ranks by that measured in-period count, while total_ads remains lifetime family reuse. The legacy period_metric=ad_debuts plus closed last_seen bounds remains accepted temporarily. Empty pages do not fabricate a count. Invalid/open/reversed periods are rejected before quota or upstream work, and a backend response missing ads_in_period is rejected rather than presented as zero. AXIS CONTRACT: read pagination.period_axis on every period response. "first_seen" means the ad was first discovered by SpyTrend; "facebook_start_date" means the ad was launched on Facebook, and is emitted only after the verified launch-generation cutover. Never assume an axis from the request or description.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNomax metadata rows (default 20, max 200; each delivered row costs 1 token) — fetch media with get_media (entity_type=creo, 10 tokens per creative).
queryNofree-text keyword search over the creative FAMILY: every word must appear in the texts of the creative's ads (all of them, not one representative ad). Combine with any other filter; use search_in to narrow the area.
savedNosaved scope selector. Use saved=all to restrict results to creatives saved in ANY favourites folder.
cursorNopagination cursor
sourceNocreative catalogue source: meta (default). TikTok is not supported by this tool; use search_ads with source=tiktok and dedupe=true for TikTok ad representatives. Unsupported sources are rejected before charging.
channelNomessaging channel the creative sends traffic to: whatsapp or telegram. Filters to creatives landing on that channel's chat domains. Use for 'bundles going to WhatsApp/Telegram'.
countryNoISO-2 country code to filter creatives shown in that geo (e.g. US, BR). Country may be combined with categories, ai_subcategory, media_type/media_types, max_countries, advertiser_id/advertiser_ids, webmaster_id, fanpages, hub_domains, domain_zone, active_ads_today_from, last_seen dates, min_geo_share and supported sorting filters. Do not combine a country scope with hub_category or channel.
date_toNocompatibility alias of period_to for the in-period window; read pagination.period_axis to learn which date axis was used
sort_byNoorder by: relevance (needs country), total_ads (lifetime), ads_in_period/reuploads (count in a closed period; read pagination.period_axis for its date axis), active_ads, last_seen or fb_created
fanpagesNothe /creo fanpages filter: keep only creatives that ran on ANY of these fanpage ids (advertiser external_ids — the Facebook page ids; OR-semantic). Entries may also be pasted facebook.com page links in any form (vanity, profile id, Ads Library) — each is resolved to its canonical page id. Get page ids from get_creative's fanpages, an ad's page_id (search_ads), or get_advertiser's external_id. Max 50.
countriesNoISO country codes to INCLUDE. The visible /creo geo picker is a multi-select — pass several markets in one call instead of one call per country.
date_fromNocompatibility alias of period_from for the in-period window; read pagination.period_axis to learn which date axis was used
folder_idNorestrict results to creatives saved in this favourites folder UUID. Mirrors the /creo folder view.
period_toNoin-period window end (YYYY-MM-DD), independent from creative last activity; requires period_from; read pagination.period_axis to learn which date axis was used
search_inNowhere to search when query is set: all (default - ad headline/link text/CTA, fan page names, landing domains AND ad body text), title (headline/link description/CTA), text (ad body text), advertiser (fan page names). Ignored without query.
categoriesNoAI category slugs to filter by (e.g. gambling_and_betting, impersonation_funnels, crypto_and_trading). Multiple = OR.
media_typeNomedia type filter: image or video
sort_orderNosort direction: asc or desc
domain_zoneNolanding-domain zones/TLDs without the dot (e.g. com, shop, online). Mirrors the /creo domain-zone filter.
hub_domainsNoexact destination hostnames to include (the web Hub filter). Use domains as a compatibility alias if needed; values are normalized hostnames, maximum 50.
media_typesNomedia types to include (image, video) — the visible /creo media multi-select. Prefer this over the singular media_type.
period_fromNoin-period window start (YYYY-MM-DD), independent from creative last activity; requires period_to; read pagination.period_axis to learn which date axis was used
hub_categoryNofilter to creatives whose destination is in this TOP-LEVEL hub category. Valid slugs: social, app_stores, shortlinks, amazon, ecommerce, popular, platforms (NOT 'social_media' — the slug is 'social'). For a specific messaging channel use channel - hub_category does NOT accept whatsapp/telegram sub-slugs.
last_seen_toNodate range end (YYYY-MM-DD): only creatives whose LAST recorded activity is on or before this date. Combine with last_seen_from for a closed activity window.
webmaster_idNoonly creatives used by this webmaster id (from search_webmasters)
advertiser_idNoonly creatives run by this advertiser id (from an ad's advertiser_id in search_ads, or get_trends dimension=advertisers)
max_countriesNoonly creatives shown in at most this many countries
min_geo_shareNoD1 geo-relevance FILTER (0-1): keep only creatives where 'country' is at least this share of the creative's ads — i.e. that geo is the creative's dominant / #1 country (e.g. 0.5 = the country is >=50% of its ads). Requires country. Combine with sort_by=relevance to rank by ad-volume IN that country.
period_metricNoderived in-period metric: ad_debuts counts ads in the inclusive period_from/period_to window on the backend-reported date axis; pagination.period_axis explains the result (first_seen = first discovery by SpyTrend, facebook_start_date = Facebook launch after the verified cutover)
advertiser_idsNomulti-select advertiser filter: creatives run by ANY of these advertiser UUIDs (OR). Each returned card then carries slice.ads_in_slice / slice.active_in_slice = the EXACT summed ad counts of exactly these advertisers inside the creative's family (additive — an ad belongs to one advertiser). Supersedes advertiser_id when both are sent.
ai_subcategoryNoAI subcategory slugs to filter by. Multiple = OR; combine with categories when needed.
last_seen_fromNodate range start (YYYY-MM-DD): only creatives whose LAST recorded activity/fixation is on or after this date. This activity filter is independent from period_from/period_to; it is not an interval-overlap or first-seen filter.
exclude_countriesNoISO country codes to EXCLUDE: a creative targeting ANY of them is hidden. Mirrors the /creo geo EXCLUDE column.
active_ads_today_fromNominimum number of ads active today for the creative family; 0 or omitted disables this filter

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
metaNo
paginationYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, and destructiveHint=false, so the safety profile is covered. The description goes substantially further: full quota model (1 token per delivered result, short pages refunded, 50 tokens per multilang ad opening, 10 per catalogue item, billed separately), period parity contract, axis contract, rejection-before-charge guarantees, and empty-page semantics. This is rich beyond what annotations provide, though the density borders on documentation-level rather than concise disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense and largely front-loaded with the meta-only scoping and sibling routing first, which is good. However, it is extremely long for a tool description, with duplicated contract material (PERIOD PARITY CONTRACT and AXIS CONTRACT restate much of what is already in the schema descriptions for period_from/period_to, sort_by, and last_seen fields). Several sentences repeat concepts already covered by the schema, reducing signal density.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 34 parameters, 100% schema coverage, an output schema, and rich annotations, the description is more than complete—it covers quota semantics, period parity, axis semantics, and rejection behavior that the structured fields alone would not convey. It arguably over-delivers on completeness at the expense of conciseness, but nothing an agent needs to invoke correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all 34 parameters in depth, establishing a baseline of 3. The description adds meaning beyond the schema by grouping filters, clarifying cross-parameter interactions (country cannot combine with hub_category or channel; advertiser_ids supersedes advertiser_id; period_from requires period_to), and explaining sort_semantics for slices—all of which exceed the schema's per-field descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (search/browse creative families), scopes it to source=meta, and explicitly differentiates from the sibling search_ads for TikTok callers. An agent can distinguish this tool from all siblings without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names when to use this tool vs search_ads (TikTok callers must use search_ads with dedupe=true), names get_media for downloading and add_to_favorites for saving. It also states when NOT to combine filters (country + hub_category or channel) and gives routing guidance for related tasks.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_hubsSearch hubs (destinations)A
Read-only
Inspect

Explore HUBS — where ads send traffic, grouped by destination (Social Media: Facebook/Instagram/Telegram/WhatsApp; App Stores; Amazon; E-commerce; Popular; Platforms). Call WITHOUT hub to get the catalog (the list of hub slugs + labels) — that is FREE. Call WITH hub set to a slug to drill into that hub's destination profiles, filtered by query (free-text profile name/id search), ai_category, min_total/min_active/min_sticky ads, date_from/date_to, window (7d/30d/90d; NOTE: lifetime counters on the default snapshot path — window is a no-op there, prefer date_from/date_to or sort=active_desc for recency), country (ISO alpha-2 — keep only profiles with ads in that geo) and exclude_cloaking (drop multi-geo redirect/cloaking domains), ordered by sort (ad_count_desc default = LIFETIME volume, ad_count_asc, last_seen_desc, sticky_desc, sticky_asc, active_desc/active_asc = CURRENTLY-active 'hot now', or relevance = ad volume IN the selected country — needs country). For a per-geo ranking of real storefronts (e.g. top e-commerce in BR), combine country + sort=relevance + exclude_cloaking. The catalog call (no hub) is FREE; profile rows cost 1 token each. FREE PLAN COUNTS: when the plan's archive window narrows a request, pagination.total_status is "restricted" and meta.plan_window_cutoff names the boundary — the count then describes the window actually searched, NOT the one requested, so a zero means "nothing in the archive window" and never "nothing exists". QUOTA: 1 token per DELIVERED result from your plan balance (free starter: 500 tokens lifetime; paid plans: 40,000/month; short pages auto-refund — you pay only for results you receive). Default page is 20 results = 20 tokens; pass limit (1–200) to size it. get_usage is free. Autonomous agents must be linked to a spytrend account to access data — an unlinked agent gets an actionable connect-your-account refusal (create agent credentials at spytrend.com/settings?tab=ai, or a human claims it by client_id), NOT a server error. Calls are rate-limited per authenticated user (deployment defaults: 60/minute and 1000/hour); a rate-limit refusal is an MCP tool error with structured error.code=rate_limit_exceeded, scope, window and retry_after_seconds. CONCURRENCY: heavy analytical calls (get_trends, search_ads, search_creatives) are admitted ONE AT A TIME per account — fanning out 5-10 of them in parallel does not go faster, it returns admission refusals for all but one. Issue heavy calls sequentially; light lookups (get_ad, get_advertiser, get_usage) are not gated.

ParametersJSON Schema
NameRequiredDescriptionDefault
hubNohub slug to drill into. IT IS THE NESTED ONE: the catalog (returned when hub is omitted) is TWO levels — each row is a CATEGORY with its own slug (social_media, app_stores, …) and a hubs[] array whose entries carry the drill-in slugs (facebook, instagram, google_play, …). Pass hubs[].slug, NOT the category slug — a category slug is rejected. Leave empty to list the hub catalog (free).
sortNoprofiles only: ad_count_desc (default, LIFETIME volume), ad_count_asc, last_seen_desc, sticky_desc, sticky_asc, active_desc/active_asc (CURRENTLY-active ads — 'what's hot now', avoids the dead-domain top), or relevance (rank by ad volume in the selected country — REQUIRES country)
limitNoprofiles only: max results (default 20; each delivered profile costs 1 token). The catalog call (no hub) is free.
queryNoprofiles only: free-text search by profile id/name within the hub (the same box as the profile search on the /hubs page). Requires hub.
windowNoprofiles only: lookback window 7d, 30d (default) or 90d. NOTE: on the default snapshot read path counters are LIFETIME and window is a no-op — for recency use date_from/date_to (profile activity dates) or sort=active_desc instead
countryNoprofiles only: ISO-3166 alpha-2 country code (e.g. US, BR). Keeps only profiles with ads in that country and enables sort=relevance (rank by ad volume IN that country) — turns the global lifetime top into a real per-geo ranking.
date_toNoprofiles only: active on or before this date (YYYY-MM-DD)
date_fromNoprofiles only: active on or after this date (YYYY-MM-DD)
min_totalNoprofiles only: minimum total ads
min_activeNoprofiles only: minimum active ads
min_stickyNoprofiles only: minimum sticky (long-running) ads
ai_categoryNoprofiles only: AI category slug filter
exclude_cloakingNoprofiles only: drop multi-geo redirect / cloaking domains (a real storefront targets a few countries; a cloaking redirect runs in 90+). Use with country+relevance to surface genuine storefronts instead of infrastructure domains.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
metaNo
paginationYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only state readOnly/open/destructive hints, and the description goes far beyond: token pricing (catalog free, 1 token per delivered profile), free-plan restricted totals with meta.plan_window_cutoff semantics, quota tiers (500 lifetime / 40k monthly with auto-refund), rate limits with structured error.code=rate_limit_exceeded, concurrency admission (one heavy analytical call at a time), and autonomous-agent auth requirements with refusal behavior. An agent literally knows the failure modes and costs before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is genuinely long (a dense wall of text), but it is front-loaded — the first two sentences carry purpose and call modal, and sections are clearly marked with caps headers. The tool is complex (13 optional params, two modes, auth, billing, rate-limit, concurrency, free-plan constraints), so the length is mostly earned. It loses a point for writing style: the crammed prose would read better as bullets; the token-cost and quota paragraphs are best with tight formatting.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 13-parameter, 0-required, complex tool, the description covers everything an agent needs: both modes, which params apply to which mode, free/paid quotas, restricted-window semantics, rate limits, concurrency policy, auth refusal behavior, paging defaults, and even examples. The output schema exists, so not delineating return fields is acceptable. There is almost nothing left for an agent to discover through costly trial-and-error.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema itself is unusually detailed, so the baseline is 3. The description adds strategic meaning beyond the schema: it connects parameters into usage recipes (country+relevance+exclude_cloaking to surface storefronts), explains the catalog-vs-profile split that determines which parameter groups apply, clarifies sort=active 'hot now' semantics, and explains the pricing consequence of limit. This is real additive value rather than schema restatement.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb+resource: 'Explore HUBS where ads send traffic, grouped by destination', enumerates the categories (Social Media, App Stores, Amazon, E-commerce, Popular, Platforms), and distinguishes the two call modes (catalog vs hub drill-in). It clearly separates this tool from sibling search tools like search_ads and search_advertisers by anchoring on destination grouping rather than ad/campaign or individual objects.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-call scenarios: 'Call WITHOUT hub to get the catalog', 'Call WITH hub set to a slug to drill into', an example recipe ('combine country + sort=relevance + exclude_cloaking for a per-geo ranking of real storefronts'), and clear when-not guidance ('window is a no-op', 'a category slug is rejected'). It stops short of naming sibling tools as alternatives or explicitly stating 'use search_ads instead when...', so it gets a 4 rather than 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_shopsSearch domains and their trafficA
Read-only
Inspect

Search domain-level traffic surfaces with commerce and advertising intelligence. A row is a DOMAIN/SUBDOMAIN surface, not necessarily a company or product. visits is a MONTHLY estimate for traffic_as_of (not live traffic); fetched_at is ingestion time. Judge every estimate using traffic_quality, traffic_confidence, traffic_is_small, traffic_is_data_from_ga, traffic_data_status and history. traffic_paid_share is display + paid-search + paid-social share; trust it only when traffic_sources_available=true. visits_growth_pct is latest-vs-previous month PERCENT; min_growth and sort_by=growth only return growth_qualified rows (current cohort, contiguous 3-month window, previous month >=10k, non-small estimate, confidence >=0.60). category is an estimated SITE category and may be missing/wrong; ai_category is SpyTrend's AD category and is preferred for ad-market discovery. created_from/to filter domain_created: best available registration date of the REGISTRABLE ROOT, not product/subdomain launch or SpyTrend first-seen. The ClickHouse row does not retain whether that date came from the preferred registry lookup or the legacy fallback. traffic_start_max compares the current estimate with the MAXIMUM of both preceding complete months and excludes stale/low-quality windows; combine with traffic_end_min. ads_monthly counts ads first observed by SpyTrend (first_parsed_date), and each point has is_complete=false for the open current month. fb_signal is correlation_only, not causal attribution; honest statuses are correlated_growth, ad_growth_ahead, ad_growth_flat_traffic, ad_growth_declining_traffic, traffic_growth_without_fb_growth, stable_or_mixed and insufficient_signal. sort_by=relevance REQUIRES ai_category and is rejected otherwise. Sorts: visits/revenue/growth/ads/rank/backlinks/ai_traffic/products/fb_score/per_ad/relevance. a separate legacy snapshot is kept alongside; never substitute its similarly named traffic fields for the primary visits/traffic_as_of contract. Returns total, has_more and offset. Use get_shop for the full source payload. Saving shops is free. FREE PLAN COUNTS: when the plan's archive window narrows a request, pagination.total_status is "restricted" and meta.plan_window_cutoff names the boundary — the count then describes the window actually searched, NOT the one requested, so a zero means "nothing in the archive window" and never "nothing exists". QUOTA: 1 token per DELIVERED result from your plan balance (free starter: 500 tokens lifetime; paid plans: 40,000/month; short pages auto-refund — you pay only for results you receive). Default page is 20 results = 20 tokens; pass limit (1–200) to size it. get_usage is free. Autonomous agents must be linked to a spytrend account to access data — an unlinked agent gets an actionable connect-your-account refusal (create agent credentials at spytrend.com/settings?tab=ai, or a human claims it by client_id), NOT a server error. Calls are rate-limited per authenticated user (deployment defaults: 60/minute and 1000/hour); a rate-limit refusal is an MCP tool error with structured error.code=rate_limit_exceeded, scope, window and retry_after_seconds. CONCURRENCY: heavy analytical calls (get_trends, search_ads, search_creatives) are admitted ONE AT A TIME per account — fanning out 5-10 of them in parallel does not go faster, it returns admission refusals for all but one. Issue heavy calls sequentially; light lookups (get_ad, get_advertiser, get_usage) are not gated.

ParametersJSON Schema
NameRequiredDescriptionDefault
qNosubstring search on the normalized domain; URLs are normalized to their host
limitNomax results (default 20; each delivered result costs 1 token).
savedNosaved scope selector. Use saved=all to restrict results to shops saved in ANY favourites folder.
offsetNopagination offset (0-based)
pixelsNocomma-separated pixel identifiers to filter by
countryNoISO-2 country code — keep only shops with traffic in this country
has_adsNotrue = only shops with at least one ad in the database
min_adsNominimum number of ads
socialsNocomma-separated social-media handle filters
sort_byNoorder by: visits (default), revenue, growth, ads, rank, backlinks, ai_traffic, products, fb_score, per_ad or relevance; relevance REQUIRES ai_category and is rejected without it
categoryNoestimated site-category filter; may be missing or misclassified, so prefer ai_category for ad-market discovery
platformNocommerce platform the site runs on: Shopify, WooCommerce, WordPress, Wix, Squarespace, Magento, PrestaShop or BigCommerce
fb_statusNoobserved ads/traffic relationship: correlated_growth, ad_growth_ahead, ad_growth_flat_traffic, ad_growth_declining_traffic, traffic_growth_without_fb_growth, stable_or_mixed or insufficient_signal; correlation only
folder_idNorestrict results to shops saved in this favourites folder UUID. Mirrors the /shops folder view.
created_toNoregistrable-root registration date on/before YYYY-MM-DD; NOT product/subdomain launch; per-row RDAP/WHOIS-vs-legacy provenance is unavailable
max_bounceNomaximum bounce rate in PERCENT (0-100) — max_bounce=30 keeps only sticky sites, the reason this control exists. The server converts it to the fraction the column stores.
max_growthNoupper end of the traffic-growth range (percent). The /shops panel has BOTH ends; pair it with min_growth for a band such as 10..50.
max_per_adNomaximum visits-per-ad efficiency
max_visitsNomaximum monthly visits
min_bounceNominimum bounce rate in PERCENT (0-100), matching the visible /shops bounce slider — min_bounce=70 keeps only high-bounce sites. The server converts it to the fraction the column stores.
min_growthNominimum latest-vs-previous monthly visits growth PERCENT; only current-cohort growth_qualified rows pass (contiguous 3 months, previous >=10k, non-small, confidence >=0.60)
min_per_adNominimum visits-per-ad efficiency (traffic / active ads)
min_visitsNominimum monthly visits
sort_orderNosort direction: asc or desc (default desc)
ai_categoryNoAI category slug the shop's ads belong to (e.g. ecommerce_and_retail)
min_revenueNominimum estimated monthly revenue (USD)
shopify_appNoShopify app slug filter (shops using this app)
created_fromNoregistrable-root registration date on/after YYYY-MM-DD; NOT product/subdomain launch or SpyTrend first-seen; per-row RDAP/WHOIS-vs-legacy provenance is unavailable
has_productsNotrue = only shops with a product catalog in our database
min_productsNominimum number of catalogued products
shopify_planNoShopify plan name filter (e.g. Basic, Shopify, Advanced)
min_backlinksNominimum total backlinks
shopify_themeNoShopify theme slug filter
has_ai_trafficNotrue = only shops receiving AI-referred traffic (ai_traffic_share > 0)
has_trustpilotNotrue = only shops with Trustpilot reviews
country_excludeNoISO-2 country code to exclude from results
traffic_end_minNolatest monthly estimate at traffic_as_of is at least this value; combine with traffic_start_max
traffic_start_maxNomaximum allowed baseline traffic, where baseline=max(two complete months before traffic_as_of); stale, low-quality, incomplete and non-contiguous windows are excluded; combine with traffic_end_min
min_trustpilot_ratingNominimum Trustpilot rating (0-5)
exclude_infrastructureNodrop rows that are transit rather than an offer — link shorteners / link-in-bio, app stores and marketplaces, social networks and messengers, ad servers. Every row also carries surface_role (destination | redirect | store | social | adserver; absent for an ordinary merchant site) so you can filter yourself instead. NOTE: rows are dropped after the page is fetched, so an excluded page can return fewer than limit rows — page on has_more/offset, not on row count.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
metaNo
totalYes
offsetYes
has_moreYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (readOnlyHint=true, destructiveHint=false), the description discloses many behavioral nuances: visits is a monthly estimate not live, traffic_paid_share is only trustworthy under a condition, growth filtering has precise qualification rules, created_from/to refer to registrable root not first-seen, fb_signal is correlation-only, sort_by=relevance requires ai_category, pagination total_status can be 'restricted', quota per delivered result, concurrency gating, and autonomous-agent linking requirements. This far exceeds the annotation baseline.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but tightly packed with critical information. It is front-loaded with the core definition, then details, then operational constraints (quota, rate limits, concurrency). Every section earns its place; the length is justified by the tool's complexity (40 parameters, multiple data-quality caveats). Minor redundancy (e.g., some parameter semantics repeated in the schema) means it could be trimmed slightly, but it remains well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity, the description covers all essential aspects for correct invocation: output pagination (total, has_more, offset), free-plan behavior, quota accounting, rate limit details, concurrency admission, and relationship to related tools. The output schema presumably handles field-level documentation, and the description complements it with interpretive guidance. Nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 100% parameter description coverage, yet the description adds essential global semantics not fully captured by individual parameter descriptions: e.g., the interpretation of visits_growth_pct as percent and its qualification rules, the meaning of traffic_start_max as max of preceding two complete months, the caveat about category vs ai_category, and the trust condition for traffic_paid_share. It also explains the interaction between parameters (e.g., min_growth and sort_by=growth). This adds significant value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states precisely that the tool searches domain-level traffic surfaces with commerce and advertising intelligence, and clarifies the unit of analysis (domain/subdomain, not necessarily company/product). It clearly distinguishes from siblings like get_shop (full payload) and search_ads/search_creatives. The core purpose is unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance: use get_shop for the full source payload, and notes that heavy analytical tools (get_trends, search_ads, search_creatives) are concurrency-gated while this tool is not heavy. It also explains quota semantics, rate limits, and when free-plan restrictions apply. This gives clear selection and operational context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_webmastersSearch webmastersA
Read-only
Inspect

Search webmasters (affiliates) — a webmaster is a whole ad NETWORK (landing domains, pixels, pages and geos grouped as one). Copy workflow: search by domain, take the canonical UUID, then search_creatives/search_ads with webmaster_id. Finish with the most reused material: get_webmaster.top_creatives or search_creatives sort_by=total_ads; total_ads is how many ads reuse the same material over its lifetime, not a weekly debut count. Returns total/active counts, top countries and geo counts. Find by name or pixel_id/domain/page_id/resolved_ip. Filter by category, AI category/subcategory, countries, languages, platforms, format, current status, dates and count ranges. For a geo ranking combine countries + min_geo_share + sort_by=relevance. Save returned UUIDs with add_to_favorites. Exact pixel_id/domain/page_id/resolved_ip lookups use the webmaster's CURRENT canonical identifier membership; historical identifiers removed from a webmaster do not count as matches. Exact page_id results report fanpages_status as available, partial, unavailable or not_applicable. When available, the selected page is included in fanpages[] with life_status from the same page-lifetime source as /advertisers (alive/deleted/banned, or unknown when lifetime coverage has no row); when unavailable, an omitted fanpages[] is not evidence that the page is alive. FREE PLAN COUNTS: when the plan's archive window narrows a request, pagination.total_status is "restricted" and meta.plan_window_cutoff names the boundary — the count then describes the window actually searched, NOT the one requested, so a zero means "nothing in the archive window" and never "nothing exists". QUOTA: 1 token per DELIVERED result from your plan balance (free starter: 500 tokens lifetime; paid plans: 40,000/month; short pages auto-refund — you pay only for results you receive). Default page is 20 results = 20 tokens; pass limit (1–200) to size it. get_usage is free. Autonomous agents must be linked to a spytrend account to access data — an unlinked agent gets an actionable connect-your-account refusal (create agent credentials at spytrend.com/settings?tab=ai, or a human claims it by client_id), NOT a server error. Calls are rate-limited per authenticated user (deployment defaults: 60/minute and 1000/hour); a rate-limit refusal is an MCP tool error with structured error.code=rate_limit_exceeded, scope, window and retry_after_seconds. CONCURRENCY: heavy analytical calls (get_trends, search_ads, search_creatives) are admitted ONE AT A TIME per account — fanning out 5-10 of them in parallel does not go faster, it returns admission refusals for all but one. Issue heavy calls sequentially; light lookups (get_ad, get_advertiser, get_usage) are not gated. TIKTOK SOURCE: pass source="tiktok" to query the TIKTOK ad corpus instead of Meta. (The platforms filter does NOT do this — platforms are Meta publisher placements.) ⚠️ TIKTOK IS PAID PER ROW at a premium: every DELIVERED TikTok ad row costs 100 tokens and every TikTok webmaster row/card costs 100 tokens (Meta rows cost 1), deducted from the same token balance (paid plans: 40,000/month = up to 400 TikTok rows). Request small limits and narrow filters; you are charged only for rows actually delivered (short pages auto-refund; if the balance covers only part of the request, that part is delivered — a 3-row request on a 150-token balance returns 1 row and charges 100). TikTok requires a Pro-or-higher plan: free/starter callers and unlinked agents get an actionable upgrade refusal, never data and never a charge. TikTok rows have their OWN shape, returned under tiktok_data (verified live 2026-07-30): id/external_id (TikTok ad id), advertiser{id,external_id,name} plus advertiser_id (TikTok BUSINESS id), start_date/end_date (the ad's delivery window) and first_seen_date/last_seen_date (SpyTrend indexing), days_active, is_active + status_today, ai_category/ai_subcategory, countries + targeting_geos + targeting_details (OS/age/gender/regions), audience_size, objective, sponsor (the 'paid for by' funder) and registry_location, landing_domain + link_url, body/title/call_to_action, creative_format, creative_id, creative_ad_count (how many ads reuse that creative), is_blurred/is_cloaked, and media[] with media_type + thumbnail_url on media-tt.spytrend.com. Media comes WITH the row — do NOT call get_media for TikTok ids (it serves Meta entities only). There are no TikTok engagement counters (plays/likes/comments/shares) on this surface. The TikTok feed serves the ARCHIVED TikTok corpus — exactly what the spytrend.com /ads TikTok tab shows — and pagination carries has_more/next_cursor plus total with total_status (exact, estimated or unavailable; unavailable is not zero). With source=tiktok rows are TikTok webmaster clusters. Supported TikTok webmaster filters: query, domain, countries (+min_geo_share), exclude_countries, ai_category (dominant), min_total_ads, min_active_ads, date_from/date_to, has_funder, sort_by=total_ads|active_ads|created_at|relevance, sort_order, offset (0-5000), limit (server caps TikTok at 100). Date filters select clusters whose activity window overlaps the requested period. Active means shown within the last 3 calendar days. Meta-only lookups, languages/platforms/creative_format(s), status_today, ai_subcategory, folder_id and saved are REJECTED before charging. Default TikTok limit is 10; each delivered row costs 100 tokens.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNomax results (default 20; each delivered result costs 1 token).
queryNofree-text webmaster (affiliate) name to search for
savedNosaved scope selector. Use saved=all to restrict results to webmasters saved in ANY favourites folder.
domainNopoint lookup: webmasters on this landing domain
offsetNopagination offset — skip the first N rows. The /webmasters ranking pages by offset (not a cursor), so this is how a caller reaches page two and beyond. Max 5000.
sourceNowebmaster corpus: meta (default — Facebook/Meta networks, 1 token per delivered row) or tiktok (TikTok business-id clusters — ⚠️ PAID: 100 tokens per DELIVERED row; Pro plan required; default limit drops to 10, server caps TikTok at 100)
date_toNoonly webmasters active on or before this date (YYYY-MM-DD)
page_idNoexact current-ownership lookup by Facebook page id (a pasted facebook.com page link in any form is also accepted and resolved to the canonical page id); fanpages_status reports lifecycle coverage and available results include alive/deleted/banned/unknown lifecycle
sort_byNoorder by: total_ads (default), active_ads or relevance (relevance ranks by ad-VOLUME in the selected countries — geo-relevance; needs countries)
categoryNovertical filter: gambling or other
pixel_idNopoint lookup: webmasters using this Facebook pixel id
countriesNoISO country codes the webmaster's ads ran in
date_fromNoonly webmasters active on or after this date (YYYY-MM-DD)
folder_idNorestrict results to webmasters saved in this favourites folder UUID. Mirrors the /webmasters folder view.
languagesNolanguage codes filter
platformsNoplatform names filter (e.g. facebook, instagram)
has_funderNoTikTok only (source=tiktok): keep only clusters with an EXTERNAL 'paid for by' sponsor (the funded-by filter). Rejected for the Meta corpus.
sort_orderNosort direction: asc or desc (default desc)
ai_categoryNoAI category slug filter (e.g. gambling_and_betting)
resolved_ipNopoint lookup: webmasters whose domain resolves to this IP
status_todayNocurrent status: active, inactive or vanished
min_geo_shareNoGEO-RELEVANCE gate (0-1, the relevant-only toggle): keep only webmasters where the 'countries' you pass are at least this fraction of their ads — i.e. that geo is their DOMINANT geo (e.g. 0.5 = country >=50% of their ads). Without it, countries is a mere 'present-in' match and a webmaster with 0.5% of ads in BR ranks as a 'BR webmaster'. Requires countries. Each returned row's geo field carries the per-country ad-count breakdown so you can read the real exposure.
min_total_adsNoonly webmasters with at least this many total ads
ai_subcategoryNoAI subcategory slug filter
min_active_adsNoonly webmasters with at least this many ACTIVE ads
creative_formatNosingle creative format filter (legacy form). Prefer creative_formats[] — the visible /webmasters control is a multi-select.
creative_formatsNocreative formats to include (video, carousel, single, dynamic). Mirrors the visible /webmasters format multi-select.
exclude_countriesNoISO country codes to EXCLUDE — drops webmasters whose ads run in ANY of them. Mirrors the /webmasters geo EXCLUDE column; combine with countries to keep one market while removing noise markets.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
metaNo
sourceNo
paginationYes
tiktok_dataNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover the safety profile (readOnly/openWorld/non-destructive); the description adds the operationally decisive facts an agent cannot get elsewhere — per-row token cost, 100x TikTok premium, auto-refunds, plan window cutoffs (total_status=restricted), rate-limit error codes, per-account concurrency admission for heavy calls, and the linked-account auth requirement with its refusal shape. This is exactly the beyond-annotations context the dimension rewards.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded correctly (definition, then workflow, then cost/auth), but the TikTok block is heavily verbose and repeats cost/plan/refund mechanics already implied earlier, and the message runs very long for a search tool. Much is justified by the paid TikTok corpus and 28 params, but there is clear redundancy that dilutes signal.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 28-parameter open-world search with a complex paid corpus and output schema present, the description covers selection, cost, auth, concurrency, plan-window semantics and lifecycle caveats. An output schema exists so return-value detail is not required, and the description still flags what the row payload contains. Nothing an agent needs to call it safely is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so the baseline is 3, but the description adds cross-cutting meaning: min_geo_share as a dominance gate rather than a presence match, sort_by=relevance requiring countries, and source=tiktok rejecting Meta-only filters before charging. It does not, however, touch many of the 28 params (folder_id, saved, languages, platforms) beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource and immediately disambiguates the domain concept ('a webmaster is a whole ad NETWORK — landing domains, pixels, pages and geos grouped as one'), which is essential since 'webmaster' is not self-evident. It also names the sibling workflow steps (search_creatives/search_ads, get_webmaster) so an agent can place it among alternatives without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit workflow ('search by domain, take the canonical UUID, then search_creatives/search_ads with webmaster_id'), names alternatives for reuse analysis (get_webmaster.top_creatives or search_creatives sort_by=total_ads), and states the conditional recipe for geo ranking (countries + min_geo_share + sort_by=relevance). TikTok-vs-Meta routing is spelled out with what is accepted and rejected in each corpus.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updates
    • Changedsearch_ads5 fields changed
      • changedInput schema / properties / date_from / description
        Previous value: -"only ads whose Facebook launch/delivery start date is on or after this date (YYYY-MM-DD). THE canonical date axis for 'new ads in a window' questions — new means LAUNCHED ON FACEBOOK in that window, not indexed by spytrend. Combine with date_to in a closed window of at most 31 calendar days for an exact in-call total"New value: +"Meta: only ads whose Facebook launch/delivery start date is on or after this date (YYYY-MM-DD). THE canonical date axis for 'new ads in a window' questions — new means LAUNCHED ON FACEBOOK in that window, not indexed by spytrend. Combine with date_to in a closed window of at most 31 calendar days for an exact in-call total. TikTok: delivery-window overlap; the last delivery date must be on or after date_from, not necessarily the launch date"
      • changedInput schema / properties / date_to / description
        Previous value: -"only ads whose Facebook launch date is on or before this date (YYYY-MM-DD); combine with date_from in a closed window of at most 31 calendar days for an exact in-call total"New value: +"Meta: only ads whose Facebook launch date is on or before this date (YYYY-MM-DD); combine with date_from in a closed window of at most 31 calendar days for an exact in-call total. TikTok: delivery-window overlap; the first delivery date must be on or before date_to"
      • changedInput schema / properties / limit / description
        Previous value: -"max rows to return (default 20; each delivered row costs 1 token). IGNORED on geo and geo_timeline — both return their complete set (geo: the whole per-country stock table, ~194 rows; geo_timeline: every populated date×country point) while charging only the page size you asked (a flat 20 by default). Those responses can be large: pass verbosity=compact to drop the heavy per-row nested structures."New value: +"max ad rows to return (maximum 200). Meta defaults to 20 at 1 token per delivered row; TikTok defaults to 10 at 100 tokens per delivered row."
      • changedInput schema / properties / sort_by / description
        Previous value: -"order results by: date (default, newest first), most_popular, folder_added or most_reused_creative. most_reused_creative ranks ads by how many ads share the same exact creative within the selected filters and dates; default/desc gives most reused first, asc gives least reused first. It requires a specific advertiser/page/pixel/webmaster/query/landing-domain/creative anchor or a launch/discovery window of at most 31 days. Rows include semantic same-creative reuse counts and creative_reuse_status. folder_added is only meaningful on folder-scoped or saved=all views; most_popular is the Trending preset ranking"New value: +"TikTok: date or days_active only. Meta: order results by: date (default, newest first), most_popular, folder_added or most_reused_creative. most_reused_creative ranks ads by how many ads share the same exact creative within the selected filters and dates; default/desc gives most reused first, asc gives least reused first. It requires a specific advertiser/page/pixel/webmaster/query/landing-domain/creative anchor or a launch/discovery window of at most 31 days. Rows include semantic same-creative reuse counts and creative_reuse_status. folder_added is only meaningful on folder-scoped or saved=all views; most_popular is the Trending preset ranking"
      • changedInput schema / properties / sort_by / enum
        Previous value: -[
        -  "date",
        -  "most_popular",
        -  "folder_added",
        -  "most_reused_creative"
        -]New value: +[
        +  "date",
        +  "most_popular",
        +  "folder_added",
        +  "most_reused_creative",
        +  "days_active"
        +]
    • Changedsearch_creatives2 fields changed
      • changedInput schema / properties / last_seen_from / description
        Previous value: -"date range start (YYYY-MM-DD): only creatives whose LAST recorded activity/fixation is on or after this date. This is the ONLY date filter; it is not an interval-overlap or first-seen filter."New value: +"date range start (YYYY-MM-DD): only creatives whose LAST recorded activity/fixation is on or after this date. This activity filter is independent from period_from/period_to; it is not an interval-overlap or first-seen filter."
      • addedInput schema / properties / source
        Added value: +{
        +  "description": "creative catalogue source: meta (default). TikTok is not supported by this tool; use search_ads with source=tiktok and dedupe=true for TikTok ad representatives. Unsupported sources are rejected before charging.",
        +  "enum": [
        +    "meta",
        +    "tiktok"
        +  ],
        +  "type": "string"
        +}
  2. 4 tool updates
    • Changedfind_similar_ads15 fields changed
      • addedOutput schema / properties / data / items / properties / creative_destination_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / creative_destination_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / is_multilang
        Added value: +{
        +  "type": [
        +    "null",
        +    "boolean"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / body
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / carousel_position
        Added value: +{
        +  "type": [
        +    "null",
        +    "integer"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / claimed_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / cloaking_detected
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / fallback_urls
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": [
        +    "null",
        +    "array"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / is_alive
        Added value: +{
        +  "type": [
        +    "null",
        +    "boolean"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / link_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / title
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / opening_price
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "billing_basis": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    },
        +    "tokens": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "unit": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "status",
        +    "tokens",
        +    "unit",
        +    "billing_basis"
        +  ],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / original_landing_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / primary_creative
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "body": {
        +      "type": "string"
        +    },
        +    "carousel_position": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "claimed_domain": {
        +      "type": "string"
        +    },
        +    "cloaking_detected": {
        +      "type": "boolean"
        +    },
        +    "expiring": {
        +      "type": "boolean"
        +    },
        +    "fallback_urls": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": [
        +        "null",
        +        "array"
        +      ]
        +    },
        +    "is_alive": {
        +      "type": [
        +        "null",
        +        "boolean"
        +      ]
        +    },
        +    "link_url": {
        +      "type": "string"
        +    },
        +    "media_type": {
        +      "type": "string"
        +    },
        +    "snapshot_url": {
        +      "type": "string"
        +    },
        +    "thumbnail_url": {
        +      "type": "string"
        +    },
        +    "title": {
        +      "type": "string"
        +    },
        +    "url": {
        +      "type": "string"
        +    }
        +  },
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / primary_creative_selection
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "carousel_position": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "reason": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "status"
        +  ],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
    • Changedget_ad15 fields changed
      • addedOutput schema / properties / data / properties / creative_destination_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / properties / creative_destination_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / properties / is_multilang
        Added value: +{
        +  "type": [
        +    "null",
        +    "boolean"
        +  ]
        +}
      • addedOutput schema / properties / data / properties / media / items / properties / body
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / properties / media / items / properties / carousel_position
        Added value: +{
        +  "type": [
        +    "null",
        +    "integer"
        +  ]
        +}
      • addedOutput schema / properties / data / properties / media / items / properties / claimed_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / properties / media / items / properties / cloaking_detected
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / data / properties / media / items / properties / fallback_urls
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": [
        +    "null",
        +    "array"
        +  ]
        +}
      • addedOutput schema / properties / data / properties / media / items / properties / is_alive
        Added value: +{
        +  "type": [
        +    "null",
        +    "boolean"
        +  ]
        +}
      • addedOutput schema / properties / data / properties / media / items / properties / link_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / properties / media / items / properties / title
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / properties / opening_price
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "billing_basis": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    },
        +    "tokens": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "unit": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "status",
        +    "tokens",
        +    "unit",
        +    "billing_basis"
        +  ],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / data / properties / original_landing_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / properties / primary_creative
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "body": {
        +      "type": "string"
        +    },
        +    "carousel_position": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "claimed_domain": {
        +      "type": "string"
        +    },
        +    "cloaking_detected": {
        +      "type": "boolean"
        +    },
        +    "expiring": {
        +      "type": "boolean"
        +    },
        +    "fallback_urls": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": [
        +        "null",
        +        "array"
        +      ]
        +    },
        +    "is_alive": {
        +      "type": [
        +        "null",
        +        "boolean"
        +      ]
        +    },
        +    "link_url": {
        +      "type": "string"
        +    },
        +    "media_type": {
        +      "type": "string"
        +    },
        +    "snapshot_url": {
        +      "type": "string"
        +    },
        +    "thumbnail_url": {
        +      "type": "string"
        +    },
        +    "title": {
        +      "type": "string"
        +    },
        +    "url": {
        +      "type": "string"
        +    }
        +  },
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / data / properties / primary_creative_selection
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "carousel_position": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "reason": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "status"
        +  ],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
    • Changedget_media16 fields changed
      • addedOutput schema / properties / items / items / properties / creative_destination_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / creative_destination_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / is_multilang
        Added value: +{
        +  "type": [
        +    "null",
        +    "boolean"
        +  ]
        +}
      • addedOutput schema / properties / items / items / properties / media / items / properties / body
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / media / items / properties / carousel_position
        Added value: +{
        +  "type": [
        +    "null",
        +    "integer"
        +  ]
        +}
      • addedOutput schema / properties / items / items / properties / media / items / properties / claimed_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / media / items / properties / cloaking_detected
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / items / items / properties / media / items / properties / expiring
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / items / items / properties / media / items / properties / is_alive
        Added value: +{
        +  "type": [
        +    "null",
        +    "boolean"
        +  ]
        +}
      • addedOutput schema / properties / items / items / properties / media / items / properties / link_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / media / items / properties / snapshot_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / media / items / properties / title
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / opening_price
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "billing_basis": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    },
        +    "tokens": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "unit": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "status",
        +    "tokens",
        +    "unit",
        +    "billing_basis"
        +  ],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / items / items / properties / original_landing_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / primary_creative
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "body": {
        +      "type": "string"
        +    },
        +    "carousel_position": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "claimed_domain": {
        +      "type": "string"
        +    },
        +    "cloaking_detected": {
        +      "type": "boolean"
        +    },
        +    "expiring": {
        +      "type": "boolean"
        +    },
        +    "fallback_urls": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": [
        +        "null",
        +        "array"
        +      ]
        +    },
        +    "is_alive": {
        +      "type": [
        +        "null",
        +        "boolean"
        +      ]
        +    },
        +    "link_url": {
        +      "type": "string"
        +    },
        +    "media_type": {
        +      "type": "string"
        +    },
        +    "snapshot_url": {
        +      "type": "string"
        +    },
        +    "thumbnail_url": {
        +      "type": "string"
        +    },
        +    "title": {
        +      "type": "string"
        +    },
        +    "url": {
        +      "type": "string"
        +    }
        +  },
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / items / items / properties / primary_creative_selection
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "carousel_position": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "reason": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "status"
        +  ],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
    • Changedsearch_ads15 fields changed
      • addedOutput schema / properties / data / items / properties / creative_destination_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / creative_destination_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / is_multilang
        Added value: +{
        +  "type": [
        +    "null",
        +    "boolean"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / body
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / carousel_position
        Added value: +{
        +  "type": [
        +    "null",
        +    "integer"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / claimed_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / cloaking_detected
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / fallback_urls
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": [
        +    "null",
        +    "array"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / is_alive
        Added value: +{
        +  "type": [
        +    "null",
        +    "boolean"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / link_url
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / media / items / properties / title
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / opening_price
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "billing_basis": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    },
        +    "tokens": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "unit": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "status",
        +    "tokens",
        +    "unit",
        +    "billing_basis"
        +  ],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / original_landing_domain
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / data / items / properties / primary_creative
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "body": {
        +      "type": "string"
        +    },
        +    "carousel_position": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "claimed_domain": {
        +      "type": "string"
        +    },
        +    "cloaking_detected": {
        +      "type": "boolean"
        +    },
        +    "expiring": {
        +      "type": "boolean"
        +    },
        +    "fallback_urls": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": [
        +        "null",
        +        "array"
        +      ]
        +    },
        +    "is_alive": {
        +      "type": [
        +        "null",
        +        "boolean"
        +      ]
        +    },
        +    "link_url": {
        +      "type": "string"
        +    },
        +    "media_type": {
        +      "type": "string"
        +    },
        +    "snapshot_url": {
        +      "type": "string"
        +    },
        +    "thumbnail_url": {
        +      "type": "string"
        +    },
        +    "title": {
        +      "type": "string"
        +    },
        +    "url": {
        +      "type": "string"
        +    }
        +  },
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / data / items / properties / primary_creative_selection
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "carousel_position": {
        +      "type": [
        +        "null",
        +        "integer"
        +      ]
        +    },
        +    "reason": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "status"
        +  ],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
  3. 2 tool updates
    • Changedget_usage2 fields changed
      • addedOutput schema / properties / multilang_ad_open_tokens
        Added value: +{
        +  "type": "integer"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "plan",
        -  "used",
        -  "remaining",
        -  "limit",
        -  "window"
        -]New value: +[
        +  "plan",
        +  "used",
        +  "remaining",
        +  "limit",
        +  "window",
        +  "multilang_ad_open_tokens"
        +]
    • Changedsearch_ads1 field changed
      • changedInput schema / properties / formats / description
        Previous value: -"creative format filter from the visible /ads Format control: video, carousel, single or dynamic. Distinct from platforms, which filters publisher placements like facebook/instagram."New value: +"creative formats: video, carousel, single, dynamic, carousel_multilang, carousel_multilang_categorized. Multilang upload detection is independent of languages; the categorized variant additionally requires an AI category. Values combine with OR. Search costs 1 token per row; opening a multilang ad costs 50 tokens."

Related MCP Connectors

Related MCP Servers

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.