Skip to main content
Glama

Search ads

search_ads
Read-only

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.

Input Schema

TableJSON 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

TableJSON Schema
NameRequiredDescriptionDefault
dataYes
metaNo
sourceNo
analysisNo
paginationYes
tiktok_dataNo
auto_applied_verticalsNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema 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"
      +]
  2. Changed15 schema 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. Changed1 schema 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."
  4. Changed2 schema fields changed
    • changedInput schema / properties / max_body_chars / description
      Previous value: -"only ads whose AD TEXT is at most this many characters long (UTF-8 characters, not bytes). Combine with min_body_chars for a closed length range, e.g. 100..500"New value: +"only 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"
    • changedInput schema / properties / min_body_chars / description
      Previous value: -"only ads whose AD TEXT is at least this many characters long (UTF-8 characters, not bytes). Pairs with the body_chars field returned on every row; the ad text itself is served by get_ad, not by this list"New value: +"only 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"
  5. First observed

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.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.