Skip to content

Tool Reference

The Adthena MCP server exposes 23 tools organized by domain: the 22 data tools below, plus list_accessible_accounts, which is only registered in the gateway (OAuth/HTTP) deployment - stdio and standalone HTTP expose the 22 data tools alone. All tools are read-only - they query data but never modify anything in your Adthena account, Google Ads campaigns, or any other system.

Tools

Tool Description Report Types
list_accessible_accounts List all Adthena accounts you have access to -
get_market_share Competitor performance: clicks, spend, impressions, position detail, groups_and_locations, summary
get_market_trends Competitor performance trends over time -
get_competitor_trends Unique competitor count trends over time -
get_competitor_overlap Search term overlap between you and competitors -
get_search_terms Search term analysis and opportunity discovery detail, detail_summary, opportunities, opportunities_summary
get_ads Most frequent ad copies and product listing ads Text (ad_format="text") or PLA (ad_format="pla")
get_ai_overview AI Overview appearance metrics and affected search terms overview, search_terms
get_ai_overview_content AI Overview citation analysis: sentiment, themes, competitor citations (premium) content, competitors
get_ai_overview_impact AI Overview CTR/CPC impact with frequency breakdown (premium) impact, search_terms
get_llm_performance LLM domain citation-share trends and per-domain performance scores domain_trends, domain_performance
get_llm_prompts List LLM prompts and prompt groups configured for an account prompt_groups, prompts
get_llm_prompt_metrics LLM prompt-level metrics: citation counts, brand share of citations, brand mention shares, and health status prompt_groups, prompts_v2, prompts
get_llm_ad_prompts List AI Ads prompts and prompt groups configured for an account (AI Ads Intelligence surface) prompt_groups, prompts
get_ai_ads_intelligence AI Ads Intelligence - brand and competitor presence in LLM paid ad placements (ChatGPT, Google AI) performance_trends, advertiser_share_trends, prompts_analysis
get_llm_ad_library The creatives behind AI Ads Intelligence - ad copy, shopping units, and per-creative prompts, trend and landing URLs ads, plas, prompts, trend, destinations
get_ai_ads_prompt_expansion Untracked prompts the brand or its named competitors advertise on - the AI Ads expansion candidates, outside the tracked prompt set -
get_serp_tracker SERP Tracker rule matches (formerly Infringement Tracker) - ads on the SERP that triggered a configured rule. Rule matches, not legal infringements matches, summary, rules
get_auto_takedown Adthena-detected trademark cases - the inputs to Google's Auto-Takedown system. For enforcement outcomes use get_trademark_takedowns matches, summary, rules
get_ad_hijacking Ad hijacking and affiliate fraud detection configurations, incidents, summary
get_brand_activator Automated bid management activity and cost savings (savings data lags 4 days) activity_log, daily_savings, daily_savings_summary
get_trademark_takedowns Google trademark auto-takedown enforcement outcomes detail, summary
get_account_settings Account configuration: locations, groups, metrics locations, search_term_groups, search_term_groups_metrics

Common Parameters

Most tools accept these parameters:

Parameter Description
account_id Required. Your Adthena account ID (from list_accessible_accounts).
start_date / end_date Date range in YYYY-MM-DD format. Data is available up to yesterday.
device List of "desktop" and/or "mobile".
report_type Selects between detail, summary, and other sub-views.
page / page_size Pagination. Default page size is 50, max 1000. Use page_size=0 to return all results.

Common Filters

Filter Description
search_term / excluded_search_term Filter by search term text (substring match).
search_term_group / excluded_search_term_group Filter by user-defined search term group.
competitor / excluded_competitor Filter by competitor domain.
competitor_group / excluded_competitor_group Filter by user-defined competitor group.
location Filter by geographic location.
adwords_campaign / excluded_adwords_campaign Filter by Google Ads campaign name.
ad_type "textad", "pla", or "organic".
segment_by Controls data grouping: ["device"], ["ad_type"], or both.

LLM Parameters

The LLM tools fall into two surfaces with different engine sets:

  • Organic citations (get_llm_performance, get_llm_prompts, get_llm_prompt_metrics) - tracks brand citations in LLM responses on ChatGPT, Perplexity and Google AI Mode. AI Mode (googleai) is not in the default engine list, so it has to be asked for.
  • Paid ad placements (get_ai_ads_intelligence, get_llm_ad_library) - tracks paid ad detections in LLM responses on ChatGPT and Google AI. get_ai_ads_intelligence reports the aggregate rates and share; get_llm_ad_library returns the individual creatives behind them. Both describe only the prompts the account already tracks; get_ai_ads_prompt_expansion is the complement, returning the untracked prompts that carried ads.

Both surfaces filter on prompts (prompt / prompt_group and their excluded_ twins) and, on get_llm_performance, get_ai_ads_intelligence and get_llm_ad_library, on domains via competitor / excluded_competitor / competitor_group / excluded_competitor_group. Competitor filtering is literal: the account's own domain is filterable like any other, so a selection that omits it hides the brand row/series. The matchable domains are the LLM-relevant competitors (every domain ever seen cited or advertising on the account's tracked prompts), not the Google relevant competitors. There are no search-term or device filters. The one exception is get_ai_ads_prompt_expansion, which is scoped by the account's own country and takes neither prompt nor prompt_group (its whole result set is prompts the account does not track); it narrows with search (free text over the prompt) and advertiser (a domain that must be among the row's relevant advertisers) instead.

Parameter Description
engine Organic tools: "chatgpt", "perplexity" and/or "googleai" (default is chatgpt + perplexity, so AI Mode must be requested). Paid-ad tools: "chatgpt" and/or "googleai" (default both), except get_llm_ad_library(report_type="plas") where only "googleai" returns anything. An engine the account is not entitled to, or that is switched off for it, is dropped from the request; filters.engine in the response reports which ones answered.
segment_by ["engine"] to split results per LLM engine. Default aggregates engines into a comma-joined label. get_llm_prompt_metrics(report_type="prompts") always segments by engine; get_ai_ads_intelligence(report_type="prompts_analysis") ignores segment_by. get_ai_ads_prompt_expansion does not accept it at all - it is always engine-segmented (see below).
prompt / excluded_prompt Filter by prompt text.
prompt_group / excluded_prompt_group Filter by prompt group name.
location Filter by geographic location.
max_number_of_domains Top domains/competitors per bucket. get_llm_performance(domain_trends) default 10; get_ai_ads_intelligence(advertiser_share_trends) default 5 - brand row always included in addition.
primary_dimension get_llm_performance(domain_trends) only: "frequency" or "average_position".
filtering_options get_llm_performance (both report types) and get_ai_ads_intelligence(advertiser_share_trends): how a competitor / competitor_group selection meets the metrics. "relative" (default) filters before aggregation, so citations_frequency / share_of_ads and performance_score are recomputed over the selected domains and the shares sum to 1. "absolute" computes over the whole market and only filters the returned rows, so shares keep whole-market values. Exclusions apply in both modes. Same vocabulary as get_market_share / get_market_trends.
prompt_status get_ai_ads_intelligence(prompts_analysis) only: "with_brand_ads", "gap", or "all" (default).

LLM tools do NOT support search-term/device filters

These endpoints filter on prompts and (for get_llm_performance, get_ai_ads_intelligence, get_llm_ad_library) competitor domains / groups. Parameters like device, ad_type, search_term, adwords_campaign, and is_whole_market are not available. (get_ai_ads_prompt_expansion is the exception noted above: it takes search and advertiser, and none of the parameters in this table.)

How to read get_ai_ads_prompt_expansion responses

This tool is shaped differently from the rest of the LLM family, so the generic rules above do not all carry over:

  • Always engine-segmented. One row per (prompt, engine); filters.segment_by comes back as ["engine"] and there is no engine-aggregated shape to request. A prompt with ads on both engines returns two rows, each with its own advertisers, share and last_seen - so the row count is not a prompt count. De-duplicate on prompt when you need one.
  • Relevance is per engine. A named competitor advertising on ChatGPT does not pull the prompt into the Google AI rows.
  • top_advertiser_share is a fraction in [0, 1], published to 4 decimal places - not a percentage. Multiply by 100 to display it. It is a share of that row's ad placements, so it never exceeds 1.
  • page_size defaults to 0 (all results), unlike the 50 default elsewhere. Prompt-expansion volumes are small; pass a specific page_size only if you want smaller pages.
  • signal picks the set: "you" (default) for prompts the brand's own ads ran on, "competitors" for prompts where only named competitors ran ads, "all" for both.
  • No nulls. A filter the caller did not set is omitted from filters rather than echoed as null - check key presence.

How to read AI Ads Intelligence responses

get_ai_ads_intelligence distinguishes between several "absence" states that look similar but mean different things. Reading them correctly is essential - getting it wrong leads to opposite conclusions.

The API never returns JSON null. Undefined values are omitted from the response (the key is absent from the object), never serialized as null. To detect "undefined", check whether the key is present in the JSON, not whether its value is null.

Not every rate is capped at 1. The brand-side rates (ad_presence_rate, your_ads_detection_rate) and share_of_ads are in [0, 1]. The competitor rates - top_competitor_detection_rate, top_competitor_rate, avg_competitor_detection_rate - are ad placements divided by scrapes, and every ad counts: a competitor showing several ads in one answer counts more than once, so these can exceed 1. Do not clamp them to 100%. you_vs_top_competitor_rate is the brand rate minus the top competitor rate, so it can go below -1.

  • ad_presence_rate is always present and numeric (period-level and per-day in time_series). The DAO zero-fills buckets with no data and substitutes 0 for any undefined value, so a 0 is ambiguous - it can mean "no scrapes occurred" OR "scrapes occurred but the brand was not detected". Use the total_prompts field at the same level to disambiguate (never cross levels):
    • Period level: each segment carries a period-wide total_prompts. total_prompts > 0 ⇒ scrapes occurred during the period ⇒ ad_presence_rate = 0 is a real "brand absent" signal. total_prompts = 0 ⇒ no scrapes ⇒ no signal.
    • Per-day level: each time_series point carries its own total_prompts (distinct prompts scraped that day). Same rule: total_prompts > 0 that day ⇒ rate of 0 means the brand was absent that day; total_prompts = 0 that day ⇒ no scrapes that day, no signal.
    • Never recommend action ("the brand is invisible here, push a campaign") based on ad_presence_rate = 0 alone - always check the matching total_prompts first.
    • prompts_analysis has no such ambiguity - the SQL HAVING clause guarantees every returned row has scrapes. Absent your_ads_detection_rate is a definitive "brand absent" signal there.
  • Period-level rate fields that may be omitted. Absence is a meaningful signal - it tells you which entity is missing from the data, not "data unavailable". The rate would have been 0 had it been emitted.
    • your_ads_detection_rate (prompts_analysis): absent ↔ the brand had zero detections on that prompt.
    • top_competitor_rate, avg_competitor_detection_rate (prompts_analysis), top_competitor_detection_rate (performance_trends): absent ↔ no competitors were detected.
    • you_vs_top_competitor_rate: absent ↔ either the brand or the competitors are absent (or both).
  • share_of_ads is always present (period and daily). Advertisers with zero detections in the period don't appear in the response at all - including the brand. If a brand row is missing from advertiser_share_trends, the brand had no detections in that bucket.
  • top_competitor key omitted → no competitors were detected in that bucket / on that prompt. Interpret as "uncontested", not "missing data".
  • Gap prompt → in prompts_analysis, a row with your_ads_detection_rate absent AND competitors_count > 0. Brand had zero detections; competitors did.
  • Greenfield promptis_greenfield: true is set explicitly, and top_competitor is absent. Brand has detections AND no competitors were detected. Highest-priority targets.
  • is_greenfield is always present (boolean).
  • The advertiser domain is the identity → advertisers are grouped and counted by domain, and placements with no domain are unattributable and dropped before aggregation, so every competitors entry, top_competitor and advertiser_share_trends row carries a non-empty domain. competitors_count / competitors_detected count distinct domains. The name is a display label only - the bucket's most-detected advertiser name, falling back to the domain when no named placement exists. Match, dedupe and join on domain, never on name.
  • Zero-fill is by bucket, not by day → each time_series carries one point per bucket of the resolved time_period: every day when daily, only the Sunday week-starts when weekly, only the month-firsts when monthly. Bucket dates are clamped inward to [start_date, end_date], so a partial bucket at either end is not emitted. Read the date sequence rather than assuming consecutive days, and check filters.time_period for the granularity you actually got.
  • Empty segments → in performance_trends every requested (engine, location) bucket is always emitted, zero-filled when it has no data. advertiser_share_trends is built only from advertisers that had detections, so a bucket with no detections yields no segment at all.
  • engine field shape → with segment_by=[] the engine field is a sorted comma-joined label like "chatgpt, googleai" (the aggregated bucket). With segment_by=["engine"] it is a single engine name.
  • No prior-period deltas are computed server-side - call the tool twice with adjacent date ranges and diff client-side.

How to read LLM Ad Library responses

get_llm_ad_library shares the "never returns null, omits the key instead" rule above, but its own absence and time semantics differ from get_ai_ads_intelligence in ways that invert conclusions if missed.

  • Grain → list rows (ads, plas) are one per (creative, engine, advertiser domain) - the domain is the advertiser identity and advertiser is a display name. The same creative appears once per engine it ran on, so summing detections across rows is not a unique-creative count, and rollups should group on advertiser_domain.
  • days_seen is a span, not a tally → inclusive days between the first and last observation. A creative seen once in January and once in June has a days_seen of about 150, not 2. On list rows the span covers the creative's whole observed lifetime; on prompts rows it is measured inside the requested window.
  • first_seen / last_seen / state on list rows describe the creative's lifetime, not your date range → a creative can report a last_seen before your start_date and still return detections inside the range.
  • state is measured against end_date, not todaynew = first observed within 7 days of the range end, quiet = last observed more than 7 days before it, live = neither. Query a historical range and you get the states as of that range.
  • trend is not zero-filled → buckets with no detections are absent from the response. This is the opposite of get_ai_ads_intelligence's zero-filled time_series. Check the date sequence before reading a gap as a zero.
  • destinations counts on a wider basis → a landing URL is recorded against the creative alone with no record of the prompt that produced it, so its detections cover every prompt the creative was answered on, while list rows and prompts / trend count only your tracked prompts. Expect the destinations total to be larger, and never present it as a share of the creative's detections. The prompt filters do not apply there for the same reason.
  • sample_url is a sample, not an identifier → it is the most-detected landing URL over the range, tracking tokens and all. Group on landing_path (scheme, host, query and fragment removed) and use report_type="destinations" for the full set.
  • search narrows → the parameter is repeatable and terms are ANDed, so search=["laptop", "monitor"] returns only creatives matching both. Each single term still matches if any searched field contains it.
  • Empty advertiser / advertiser_domain → the source data carries no advertiser for that row. Treat as "unattributed", not a lookup failure.
  • Data depth varies by time_period → daily holds roughly the last month, weekly the last 13 months, monthly the full history. Weekly and monthly rows are stored on their bucket-start date, so a range containing no bucket start returns no rows at all.

Safety Annotations

Every tool includes MCP safety annotations. All tools use identical annotations because the entire server is read-only:

Annotation Value Meaning
readOnlyHint true The tool only reads data - it does not modify anything.
destructiveHint false The tool cannot delete or destructively modify data.
openWorldHint false The tool operates against a closed, fixed set of Adthena endpoints.

This applies to all 23 tools (the 22 data tools plus the gateway-only list_accessible_accounts). The annotations are enforced in the source code and verified by automated tests.

Resources

The server also provides 5 read-only MCP resources that give the client context about your account and the data model:

Resource URI Description
Quick Reference docs://quick-reference Question-to-tool mapping table - read first to find the right tool.
Concepts docs://concepts Core Adthena concepts and metric definitions (share, position, count metrics).
Workflows docs://workflows Step-by-step workflows for 10 common analysis patterns.
Date Rules docs://date-rules Date handling rules, time period auto-resolution, and data alignment.
Data Access docs://data-access Pagination modes, segmentation (segment_by), and filtering options.

Data Limits

Constraint Details
AI Overview start_date must be on or after 2025-07-31
AI Overview Content / Impact start_date must be within the last 30 days
Brand Activator activity_log Limited to the last 60 days (savings endpoints have no date restriction)
Search Term Opportunities Limited to the last 30 days
LLM Performance / Prompt Metrics Any range, with time_period selecting the grain. Exception: get_llm_prompt_metrics(report_type="prompts") is still capped at the last 30 days
LLM Ad Library history depth Daily data covers roughly the last month, weekly the last 13 months, monthly the full history
LLM Prompts (listing) No date range required - lists account configuration
Pagination Max page_size is 1000. Use page_size=0 for all results (streamed).
Time periods Auto-calculated: daily (last 30 days), weekly (last 13 months), monthly (older).