Tool reference
118 tools, read live from the MCP server. Every call is permission-checked per user, per client and per marketplace, and logged. READ tools only look at data; WRITE tools can change live ads and need edit access.
Clients & discovery 3
READ
get_clients
List all active clients with their client_id and marketplace.
Call this first if you don't know the client_id.
Covers all ad programs (SP, SB, SD).
Empty result = no matching data, not an outage.
No inputs — call it directly.
READ
get_monthly_clients
List clients & marketplaces available in the Monthly_searchterm historical reports.
Use this to discover which clients have monthly data (not all 61 clients do — only 28).
Empty result = no matching data, not an outage.
No inputs — call it directly.
READ
get_portfolios
Performance rollup per PORTFOLIO across all campaigns/ASINs/keywords.
Returns one row per portfolio with:
- portfolioid, portfolioname
- campaigns (count in this portfolio)
- asins (count of unique ASINs)
- impressions, clicks, ad_spend, ad_sales, ad_orders
- acos, roas, cpc, ctr, cvr (computed)
Also includes "unassigned" bucket for campaigns without a portfolio.
Data source: keyword_data UNION product_data. Portfolio names looked up via
dictionary CTE (since fetcher stores names in some rows but nulls in others).
ROUTING: Use for "portfolio performance", "which portfolio is best/worst",
"spend by portfolio", "compare portfolios", "portfolio ROAS", "portfolio audit".
IMPORTANT - Empty results = client has no portfolios assigned or no ads ran.
NOT a data source outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
date_from: YYYY-MM-DD (default: 30 days ago)
date_to: YYYY-MM-DD (default: today)
ad_program: SP, SB, SD, or None for all
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| ad_programoptional | str | None |
Search terms 5
READ
campaign_diagnostic_search_term
Deep-dive search term analysis for ONE specific campaign, comparing recent vs prior periods.
Companion tool to campaign_diagnostic - when the main diagnostic shows a campaign is
causing spend/sales changes, this tool shows exactly what happened at the search-term level.
Identifies:
- new_terms: Search terms that appeared in recent, not in prior (fresh queries)
- disappeared_terms: Search terms with spend in prior, gone in recent (paused or dropped)
- spend_increased_terms: Same terms with big spend increases recent vs prior
- spend_decreased_terms: Terms with big spend decreases
- waste_candidates: Terms with spend but 0 orders in recent (potential negatives)
- new_converters: Terms with 0 orders prior, hitting min_orders in recent (positive opportunities)
- lost_converters: Terms that had orders in prior but 0 in recent (lost performers)
REQUIRES campaign_id from the user (not optional). If missing, tool returns error.
ROUTING: Use when user asks to drill into search term changes for a specific campaign,
or when they want to understand why a campaign's spend/orders shifted at the search term
level. Typical trigger after campaign_diagnostic identifies a top-mover campaign.
IMPORTANT - Empty results in any section = no search terms matched criteria, NOT a data
source outage.
Args:
client_id: Client identifier
campaign_id: REQUIRED. The specific campaign to analyze
recent_start: YYYY-MM-DD start of recent period
recent_end: YYYY-MM-DD end of recent period
prior_start: YYYY-MM-DD start of prior period
prior_end: YYYY-MM-DD end of prior period
marketplace: US, CA, UK, IN, etc.
min_spend_change: Min $ change to flag as spend increased/decreased (default $5)
waste_min_spend: Min $ spend with 0 orders to flag as waste candidate (default $10)
min_orders_for_converter: Min orders to be a "converter" (default 2)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| campaign_idrequired | str | — |
| recent_startrequired | str | — |
| recent_endrequired | str | — |
| prior_startrequired | str | — |
| prior_endrequired | str | — |
| marketplaceoptional | str | 'US' |
| min_spend_changeoptional | float | 5.0 |
| waste_min_spendoptional | float | 10.0 |
| min_orders_for_converteroptional | int | 2 |
READ
find_search_term_opportunities
Find converting search terms -- harvest candidates for exact-match targeting.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: Marketplace code
ad_program: "SP" or "SB" (default: both)
min_orders: Minimum orders to qualify (default: 2)
days: Lookback window
limit: Max rows (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| ad_programoptional | str | None |
| min_ordersoptional | int | 2 |
| daysoptional | int | 30 |
| limitoptional | int | None |
READ
get_monthly_search_terms
Historical monthly search-term performance from the Monthly_searchterm S3 reports.
Sponsored Products data — 28 clients across IN/US/CA, going back to Oct-2024.
Each source row is one day, but files are bundled monthly. ~2.5M rows total.
Use this for retrospective month-over-month or year-over-year search-term analysis
(e.g. "compare 'organic tea' performance Aug-2025 vs Aug-2024").
For recent (last ~30 days) data prefer get_search_terms — it queries the daily tables and is faster.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier, case-insensitive (e.g. 'LIBERTYZENO', 'American Textile Industries LLC')
marketplace: 2-letter code (US, CA, IN)
date_from: Start date YYYY-MM-DD (default: 180 days ago)
date_to: End date YYYY-MM-DD (default: today)
min_spend: Minimum spend filter
min_clicks: Minimum clicks filter
aggregate: If True (default), group rows by customer_search_term across the date range.
If False, return raw daily rows.
include_duplicates: If True, include re-export files like '_(1).parquet'.
Default False excludes them to avoid double-counting.
limit: Max rows (default: no limit — relies on aggregate=True to keep response small)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| min_spendoptional | float | 0 |
| min_clicksoptional | int | 0 |
| aggregateoptional | bool | True |
| include_duplicatesoptional | bool | False |
| limitoptional | int | None |
READ
get_search_terms
LAST resort for ad performance. Only use when:
1. User SPECIFICALLY asks for search term data, OR
2. get_campaign, get_keywords, and get_products all returned empty.
Priority order: get_campaign (1st) → get_keywords (2nd) → get_products (3rd) → get_search_terms (last).
Returns what customers searched and how those searches performed. Covers SP and SB only.
This is the most granular and largest dataset — prefer higher-level tools first.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: US, CA, UK, AE, SA, IN, AU etc.
ad_program: "SP" or "SB" (default: both)
min_clicks: Minimum clicks to filter noise (default: 5)
limit: Max rows to return (default: no limit — Athena returns the full result set)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| ad_programoptional | str | None |
| min_clicksoptional | int | 1 |
| limitoptional | int | None |
READ
search_term_analysis
Analyze search terms to find:
1. NEGATIVE candidates (wasted spend, no orders)
2. POSITIVE keyword opportunities (high-converting search terms) with best campaign to add them to
3. Top n-gram patterns by spend
REQUIRES all 4 thresholds from user. If missing, returns error. Ask user for their
specific thresholds before calling (spend/sales/orders/ACOS). Do not guess defaults.
AFTER receiving results, generate an Excel file (.xlsx) locally with 2 sheets:
Sheet 1 "Negatives to Add" - columns: search_term, campaignid, adgroupid,
campaignname, wasted_spend, clicks, recommended_match_type
Sheet 2 "Keyword Opportunities" - columns: search_term, converting_campaign,
recommended_target_campaign, recommended_matchtype, ad_product_asin,
sales, orders, acos, reason
Save file, share it with user for review. User edits and uses it as reference to
add negatives / create keywords manually (or via create_entities tools).
Positive keyword recommendation logic:
- Search term converted with >= min_orders and ACOS <= max_acos and sales >= min_sales
- Recommends adding as EXACT match in the campaign where it converted
- CHECKS: is this exact keyword+matchtype already targeting the SAME advertised ASIN
in ANY campaign? If yes, that entry is SKIPPED (no duplicate targeting).
ROUTING: Use for "search term analysis", "find negatives", "wasted spend on search terms",
"which search terms to negate", "find keyword opportunities", "search term opportunities",
"n-gram analysis".
Rows are capped for context; `summary` totals are exact over ALL rows.
IMPORTANT - Empty results mean no search terms matched user criteria, NOT that data
source is down. Report honestly.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
date_from: YYYY-MM-DD (default: 30 days ago)
date_to: YYYY-MM-DD (default: today)
ad_program: SP or SB, None for both (SD has no search terms)
min_wasted_spend: REQUIRED. Min $ spent with 0 orders to flag as negative
min_sales: REQUIRED. Min $ sales for a search term to be a positive opportunity
min_orders: REQUIRED. Min orders for positive opportunity
max_acos: REQUIRED. Max ACOS (as decimal 0.30 for 30%) for positive opportunity
top_n_ngrams: N-grams to return (default 20)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| ad_programoptional | str | None |
| min_wasted_spendoptional | float | None |
| min_salesoptional | float | None |
| min_ordersoptional | int | None |
| max_acosoptional | float | None |
| top_n_ngramsoptional | int | 20 |
| min_clicksoptional | int | 0 |
Keywords & targeting 8
WRITE
add_keywords_targets
ADD new keywords, targets, or themes to an EXISTING campaign/ad group.
Use when the user wants to add keyword targeting, ASIN/category targeting, or theme targeting.
For adding product ads (ASINs to advertise), use add_product_ads instead.
Supported entity_types per ad_program:
SP: keywords, targets
SB: keywords, targets, themes
SD: targets
Required fields:
SP keywords: adGroupId, campaignId, keywordText, matchType (BROAD/EXACT/PHRASE), state (ENABLED/PAUSED)
SP targets: adGroupId, campaignId, expression [{type,value}], expressionType (MANUAL), state
SB keywords: adGroupId, campaignId, keywordText, matchType (broad/exact/phrase), bid
SB targets: adGroupId, campaignId, expressions [{type,value}], bid
SB themes: adGroupId, themeType (KEYWORDS_RELATED_TO_YOUR_BRAND / KEYWORDS_RELATED_TO_YOUR_LANDING_PAGES), bid
SD targets: adGroupId, expression [{type,value}], expressionType (manual), state
Optional: bid (overrides ad group default bid)
Max per call: SP 1000, SB 100, SD 200.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
ad_program: SP, SB, or SD
entity_type: keywords, targets, or themes (SB only)
entities: JSON string — array of entity dicts with required fields per type
confirmed: Must be True to execute. First call returns a preview.
updates_ref: OPTIONAL. Id of a changeset uploaded earlier
(upload_changeset / mcp_push.py --upload). When given, the
rows come from storage and `entities` must be left empty.
This is how a bulk file is pushed without putting the whole
payload in the conversation.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| ad_programrequired | str | — |
| entity_typerequired | str | — |
| entitiesoptional | str | None |
| confirmedoptional | bool | False |
| updates_refoptional | str | None |
WRITE
add_negatives
ADD negative keywords or negative targets to an EXISTING campaign/ad group.
Use when the user wants to block specific search terms, ASINs, or brands from triggering ads.
Supported entity_types per ad_program:
SP: negativeKeywords, negativeTargets
SB: negativeKeywords, negativeTargets
SD: negativeTargets
Required fields:
SP negativeKeywords: adGroupId, campaignId, keywordText, matchType (NEGATIVE_EXACT/NEGATIVE_PHRASE/NEGATIVE_BROAD), state (ENABLED)
SP negativeTargets: adGroupId, campaignId, expression [{type,value}] (ASIN_SAME_AS/ASIN_BRAND_SAME_AS), state (ENABLED)
SB negativeKeywords: adGroupId, campaignId, keywordText, matchType (negativeExact/negativePhrase)
SB negativeTargets: adGroupId, campaignId, expressions [{type,value}] (asinSameAs/asinBrandSameAs)
SD negativeTargets: adGroupId, expression [{type,value}] (asinSameAs/asinBrandSameAs), expressionType (manual), state (enabled)
Note: SB negatives do NOT accept state or bid — Amazon sets them automatically.
Max per call: SP 1000, SB 100, SD 100.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
ad_program: SP, SB, or SD
entity_type: negativeKeywords or negativeTargets
entities: JSON string — array of negative entity dicts
confirmed: Must be True to execute. First call returns a preview.
updates_ref: OPTIONAL. Id of a changeset uploaded earlier
(upload_changeset / mcp_push.py --upload). When given, the
rows come from storage and `entities` must be left empty.
This is how a bulk file is pushed without putting the whole
payload in the conversation.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| ad_programrequired | str | — |
| entity_typerequired | str | — |
| entitiesoptional | str | None |
| confirmedoptional | bool | False |
| updates_refoptional | str | None |
READ
get_keyword_entities
Get ALL keywords/targets with their current bid and status — includes 0-impression keywords.
Data is from the latest daily snapshot, not aggregated performance.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: US, CA, UK, AE, SA, IN, AU etc. (required)
state: Filter by ENABLED, PAUSED, or ARCHIVED (optional)
entity_type: Filter by "keyword" or "target" (optional)
campaign_id: Filter by specific campaign ID (optional)
ad_program: Filter by "SP", "SB", or "SD" (optional)
limit: Max rows to return (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| stateoptional | str | None |
| entity_typeoptional | str | None |
| campaign_idoptional | str | None |
| ad_programoptional | str | None |
| limitoptional | int | None |
READ
get_keyword_hourly
Hourly impressions, clicks, cost per keyword from AMS traffic stream.
Each row = one keyword x one hour.
Best when filtered by campaign_id or keyword_text. SP/SB have keyword_text;
SD does not (shows as campaign/adgroup level).
Use when user asks: "keyword hourly data", "hourly for keyword X",
"which keywords got clicks this morning".
For campaign-level hourly, use get_campaign_hourly.
Rows are capped for context; summary totals are exact over ALL rows.
Empty result = no matching data, not an outage.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| hours_backoptional | int | 24 |
| ad_programoptional | str | None |
| campaign_idoptional | str | None |
| keyword_textoptional | str | None |
| limitoptional | int | 50 |
READ
get_keywords
Use when user SPECIFICALLY asks for keyword-level data, or as FALLBACK when get_campaign returns empty.
Priority order for ad performance: get_campaign (1st) -> get_keywords (2nd) -> get_products (3rd) -> get_search_terms (last).
Returns ALL keyword AND target types (text keywords + auto-targets close/loose/substitutes/complements + product/ASIN targets)
from the keyword performance table. Keywords/targets that are ENABLED but had ZERO impressions (absent from the
performance report) are merged in from the entity snapshot, showing their bid + status. Covers SP, SB, SD.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: 2-letter country code (US, CA, UK, IN, MX, AE, SA, AU)
date_from: Start date YYYY-MM-DD (default: 30 days ago)
date_to: End date YYYY-MM-DD (default: today)
ad_program: "SP", "SB", "SD", or None for all
min_spend: Only keywords with cost above this (default: 0)
max_acos: Only keywords with ACOS below this (optional)
limit: Max rows (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| ad_programoptional | str | None |
| min_spendoptional | float | 0 |
| max_acosoptional | float | None |
| statusoptional | str | None |
| limitoptional | int | None |
READ
get_targeting_breakdown
Hierarchical performance breakdown for structural targeting analysis:
Level 1: Ad program (SP / SB / SD)
Level 2: Campaign type (Auto / Manual)
Level 3: Targeting type (Keyword-Broad, Keyword-Phrase, Keyword-Exact,
close-match, loose-match, substitutes, complements, Product Target, Category Target)
Shows where money is going structurally + which targeting strategy is best/worst.
Returns:
- summary: totals, overall ACOS/ROAS, best_targeting, worst_targeting
- by_ad_program: SP/SB/SD rollup with ROAS/ACOS each
- by_ad_program_and_type: SP-Auto, SP-Manual, SB-Manual, SD-Manual rollups
- by_targeting_type: full hierarchy (ad_program, campaign_type, targeting_type) with metrics
- recommendations: automatic best-vs-worst callout ("Shift budget from X to Y")
Data source: keyword_data (keywords, auto targets and product/category targets all live there).
v76: product_data is NOT added any more - it is the advertised-product report, the same spend seen per ASIN,
so the old UNION counted every dollar twice and showed ~49% "Product Target" that did not exist.
ROUTING: Use for "auto vs manual", "targeting type performance",
"which targeting works best", "SP vs SB vs SD split", "keyword vs product targets".
Replaces the campaign-targeting-performance skill.
IMPORTANT - Empty results = no ads ran with matching filters. NOT a data source outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
date_from: YYYY-MM-DD (default: 30 days ago)
date_to: YYYY-MM-DD (default: today)
ad_program: SP, SB, SD, or None for all
campaign_id: Filter to one campaign
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| ad_programoptional | str | None |
| campaign_idoptional | str | None |
WRITE
update_keyword_status
Update a SINGLE keyword's status and/or bid via Amazon Ads API. Supports SP and SB.
For updating MULTIPLE keywords at once, use batch_update_entities instead — it sends all updates in one API call.
Set confirmed=True only after user has explicitly said yes.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
keyword_id: Amazon Ads keyword ID
new_status: "PAUSED" or "ENABLED" (optional if only changing bid)
new_bid: New bid amount (optional if only changing status)
ad_program: "SP" or "SB" (default: SP)
campaign_id: Campaign ID (from get_keywords)
adgroup_id: Ad group ID (from get_keywords)
match_type: Match type (EXACT, PHRASE, BROAD)
campaign_name: Campaign name (for logging)
keyword_text: The keyword text (for logging)
current_status: Current status before change
current_bid: Current bid before change
confirmed: Must be True to execute
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| keyword_idrequired | str | — |
| new_statusoptional | str | None |
| new_bidoptional | float | None |
| ad_programoptional | str | 'SP' |
| campaign_idoptional | str | '' |
| adgroup_idoptional | str | '' |
| match_typeoptional | str | '' |
| campaign_nameoptional | str | '' |
| keyword_textoptional | str | '' |
| current_statusoptional | str | '' |
| current_bidoptional | float | None |
| confirmedoptional | bool | False |
WRITE
update_target_status
Update a SINGLE target's status and/or bid via Amazon Ads API. Supports SP and SB.
For updating MULTIPLE targets at once, use batch_update_entities instead — it sends all updates in one API call.
Set confirmed=True only after user has explicitly said yes.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
target_id: Amazon Ads target ID
new_status: "PAUSED" or "ENABLED" (optional if only changing bid)
new_bid: New bid amount (optional if only changing status)
ad_program: "SP" or "SB" (default: SP)
campaign_id: Campaign ID (required by Amazon Ads API)
adgroup_id: Ad group ID (required by Amazon Ads API)
campaign_name: Campaign name (for logging)
target_expression: Target expression (for logging)
current_status: Current status before change
current_bid: Current bid before change
confirmed: Must be True to execute
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| target_idrequired | str | — |
| new_statusoptional | str | None |
| new_bidoptional | float | None |
| ad_programoptional | str | 'SP' |
| campaign_idoptional | str | '' |
| adgroup_idoptional | str | '' |
| campaign_nameoptional | str | '' |
| target_expressionoptional | str | '' |
| current_statusoptional | str | '' |
| current_bidoptional | float | None |
| confirmedoptional | bool | False |
Campaigns & placements 9
READ
analyze_campaign_health
Overall health check for a client's ad account.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: Marketplace code
ad_program: "SP", "SB", or "SD" (default: all)
days: Lookback window (default: 14)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| ad_programoptional | str | None |
| daysoptional | int | 14 |
READ
campaign_diagnostic
7-layer root-cause diagnostic for account performance changes. Auto-escalates
comparison window (7v7 -> 14v14 -> 30v30) if no significant change is found.
Use when user asks: "diagnose this account", "what changed", "why did X drop",
"campaign health check", "root cause", "find problems".
Layers analyzed:
1. Account summary (totals + % change)
2. Campaign breakdown (top spend-impact campaigns flagged with health checks)
3. Ad group drill-down (for top flagged campaigns)
4. Keyword/target drill-down (for top flagged ad groups)
6. Placement shifts (Top of Search / Product Pages / Rest of Search)
7. Cross-campaign pattern (MARKET_WIDE / ISOLATED / MIXED)
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
recent_start/recent_end: Custom recent period (YYYY-MM-DD). If omitted, auto-escalates.
prior_start/prior_end: Custom prior period. If omitted, auto-escalates.
ad_program: SP, SB, SD, or None for all
significance_threshold: % change to consider significant for auto-escalation (default 0.15 = 15%)
enable_deep: If False, only runs Layers 1-2 (faster)
max_flagged_deep: Max campaigns to deep-dive into (default 5)
top_keywords_per_adgroup: Top N keywords to surface per flagged ad group (default 10)
min_prior_spend: Skip campaigns with prior spend below this (default $5)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| min_spendoptional | float | None |
| recent_startoptional | str | None |
| recent_endoptional | str | None |
| prior_startoptional | str | None |
| prior_endoptional | str | None |
| ad_programoptional | str | None |
| significance_thresholdoptional | float | 0.15 |
| enable_deepoptional | bool | True |
| max_flagged_deepoptional | int | 5 |
| top_keywords_per_adgroupoptional | int | 10 |
| min_prior_spendoptional | float | 5.0 |
WRITE
create_campaign
CREATE a full campaign structure in ONE call — campaign → ad group → product ads → keywords/targets.
Supports SP and SD; SB (incl. video ads) since v76 behind the admin switch "create_campaign for SB" - the
preview always works, confirmed=True needs the switch. Does the entire chain sequentially, returning all created IDs.
SB campaign_data (v76): campaign {name, budget, budgetType DAILY|LIFETIME, brandEntityId (sellers), portfolioId?,
startDate?}, adGroup {name}, ad {type: "video" | "product_collection" | "brand_video", name, asins [..],
videoAssetIds [..] (video), brandLogoAssetID + brandName + headline (product collection), landingPage {pageType
STORE|PRODUCT_LIST|DETAIL_PAGE, url? asins?}}, keywords [{keywordText, matchType broad|phrase|exact, bid}] or
targets. Asset ids come from the creative assets library in the Ads console.
The campaign_data parameter is a JSON object with these sections:
campaign (required):
name (required): Campaign name. User should specify their naming convention.
budget (required): Daily budget amount.
SP-only: targetingType (AUTO/MANUAL), strategy (LEGACY_FOR_SALES/AUTO_FOR_SALES/MANUAL)
SD-only: tactic (T00020/T00030), costType (cpc/vcpm)
Optional: portfolioId (assigns campaign to a portfolio; use get_portfolios to find IDs)
adGroup (required):
name (required): Ad group name.
defaultBid (required): Default bid for the ad group.
productAds (required): Array of products to advertise.
Each needs: sku (sellers) or asin (vendors)
keywords (SP MANUAL only): Array of keywords. Mutually exclusive with targets.
Each needs: keywordText, matchType (BROAD/EXACT/PHRASE), bid
targets (SP MANUAL or SD): Array of targeting expressions.
SP: Each needs expression [{type, value}], bid
SD: Each needs expression [{type, value}], bid
Example SP keyword campaign:
{"campaign":{"name":"SPM | KW | PHR | Shoes","budget":5.0,"targetingType":"MANUAL"},
"adGroup":{"name":"Shoes - Phrase","defaultBid":0.70},
"productAds":[{"sku":"SHOE-001"}],
"keywords":[{"keywordText":"running shoes","matchType":"PHRASE","bid":0.70}]}
Example SD campaign:
{"campaign":{"name":"SD | Contextual | Shoes","budget":3.0,"tactic":"T00030"},
"adGroup":{"name":"Shoes Targeting","defaultBid":1.0},
"productAds":[{"asin":"B08XXXXXX"}],
"targets":[{"expression":[{"type":"similarProduct"}],"bid":1.25}]}
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
ad_program: SP or SD
campaign_data: JSON string with campaign, adGroup, productAds, and keywords/targets
confirmed: Must be True to execute. First call returns a preview.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| ad_programrequired | str | — |
| campaign_datarequired | str | — |
| confirmedoptional | bool | False |
READ
get_campaign
Campaign-level ad performance data AGGREGATED across the date range,
joined with the latest campaign metadata (budget, state, targeting type).
Returns ONE row per campaign covering ALL ad types in a single call:
- SP (Sponsored Products) — from campaign_placement_data (placements aggregated to campaign level)
- SB (Sponsored Brands) — from campaign_data
- SD (Sponsored Display) — from campaign_data
Both source tables UNIONed so SP + SB + SD show up together.
Metadata joined from entity_campaigns snapshot (budget, state, targeting).
ROUTING: Use for "campaign list", "campaign performance", "campaign budgets",
"campaign status", "ACOS", "ad spend", "PPC metrics" for a PERIOD (not day-by-day).
Metrics per campaign: impressions, clicks, cost (ad spend), sales (ad_sales),
orders, acos, plus status/budget/targeting from entity snapshot, and (v39)
bidding_strategy (SP: LEGACY_FOR_SALES / AUTO_FOR_SALES / MANUAL, i.e.
down-only / up-and-down / fixed; SB: bidOptimization) with
placement_adjustments (JSON list of {placement, percentage}) so bid math
can derate correctly. NULL = the snapshot has no bidding data for it.
DO NOT USE for:
- Day-by-day / weekly / monthly trends -> use get_performance_data
- Total store sales (organic + ad) -> use get_sales_data or get_adproduct_performance
- Placement breakdown (Top of Search / Product Page / Rest of Search) -> use get_placements
- Keyword-level detail -> use get_keywords or get_targeting_breakdown
- ASIN-level detail -> use get_products or get_adproduct_performance
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: US, CA, UK, AE, SA, IN, AU etc.
date_from: Start date YYYY-MM-DD (default: 30 days ago)
date_to: End date YYYY-MM-DD (default: today)
ad_program: "SP", "SB", "SD", or None for all
status: Entity status filter — ENABLED (default), PAUSED, or ARCHIVED
limit: Max rows (default: no limit)
min_clicks: only campaigns with at least this many clicks in the window (default 0 = all)
min_spend: only campaigns with at least this much spend in the window (default 0 = all)
max_acos: only campaigns with ACOS <= this ratio (e.g. 0.35). Campaigns with
spend but NO sales are kept (their ACOS is undefined, not low).
Filters are applied in SQL, so a filtered call is smaller AND faster.
`summary` totals are over the FILTERED rows.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| ad_programoptional | str | None |
| statusoptional | str | None |
| limitoptional | int | None |
| min_clicksoptional | int | 0 |
| min_spendoptional | float | 0 |
| max_acosoptional | float | None |
READ
get_campaign_hourly
Hourly impressions, clicks, cost per campaign from AMS traffic stream.
Each row = one campaign x one hour.
Use when user asks: "campaign hourly data", "hourly breakdown by campaign",
"which campaign spent most this hour", "campaign pacing today".
For account-level hourly totals, use get_realtime_traffic.
For keyword-level hourly, use get_keyword_hourly.
Rows are capped for context; summary totals are exact over ALL rows.
Empty result = no matching data, not an outage.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| hours_backoptional | int | 24 |
| ad_programoptional | str | None |
| campaign_idoptional | str | None |
| limitoptional | int | 50 |
READ
get_placements
Use when user asks about PLACEMENT performance — "Top of Search", "TOS", "Product Pages",
"Rest of Search", "placement breakdown", or "where are my ads showing".
Returns each campaign split by placement (Top of Search / Product Pages / Rest of Search)
with impressions, clicks, cost, sales, orders, and the bid adjustment percentage. SP-only data.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: Marketplace code
date_from: Start date YYYY-MM-DD (default: 7 days ago)
date_to: End date YYYY-MM-DD (default: today)
limit: Max rows (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| limitoptional | int | None |
WRITE
update_campaign
Update CAMPAIGN budget, status (enable/pause), and/or name in batches. Call when the user asks to change a
campaigns daily budget, pause/enable a campaign, or rename it. CANNOT create new campaigns — only updates existing ones. Supports SP, SB, SD. Does NOT change placement
bid adjustments (Top of Search / Product Pages %) - use update_campaign_placement for that.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
ad_program: SP, SB, or SD
updates: JSON string list of dicts; each needs campaignId + at least one of budget/state/name:
{"campaignId": "...", "budget": 50.0, "state": "ENABLED", "name": "...", "portfolioId": "..."}
state = ENABLED/PAUSED (SD also ARCHIVED; auto-cased). portfolioId = assign to portfolio (or 0 to remove). Max per call: SP 1000, SB 10, SD 100.
confirmed: Must be True to execute. First call returns a preview.
updates_ref: OPTIONAL. Id of a changeset uploaded earlier
(upload_changeset / mcp_push.py --upload). When given, the
rows come from storage and `updates` must be left empty.
This is how a bulk file is pushed without putting the whole
payload in the conversation.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| ad_programrequired | str | — |
| updatesoptional | str | None |
| confirmedoptional | bool | False |
| updates_refoptional | str | None |
WRITE
update_campaign_audience_bid
AMC audience bid boosting for Sponsored Products: raise the bid by a percentage when the shopper is in one of
the given audiences (SP v3 dynamicBidding.shopperCohortBidding). v76, admin switch "AMC audience bid boosting".
SP only - SB and SD have no audience boost in Amazon's API; a placement % is update_campaign_placement.
Args:
client_id: exact client name from get_clients
marketplace: US, CA, UK, IN ...
updates: JSON STRING - list of {"campaignId": "...", "percentage": 0-900, "audienceIds": ["...", ...]}.
percentage 0 with no audienceIds removes the boost from that campaign.
confirmed: False = preview only (always allowed). True = send to Amazon (needs the admin switch on).
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| updatesrequired | str | — |
| confirmedoptional | bool | False |
WRITE
update_campaign_placement
Update CAMPAIGN PLACEMENT BID ADJUSTMENT(S) only — the Top of Search / Product Pages / Rest of Search percentage.
Call this when the user asks to change placement %, bid adjustment, Top of Search bid boost, etc.
Does NOT touch budget — use update_campaign_budget for that. Best for SP (also handles SB).
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
ad_program: "SP" or "SB"
updates: JSON string — list of dicts, each with campaignId and placement adjustments:
{"campaignId": "...", "placementBidding": [
{"placement": "PLACEMENT_TOP", "percentage": 50},
{"placement": "PLACEMENT_PRODUCT_PAGE", "percentage": 20}
]}
SP placement values: PLACEMENT_TOP (Top of Search), PLACEMENT_PRODUCT_PAGE (Product Pages),
PLACEMENT_REST_OF_SEARCH (Rest of Search). percentage is 0-900.
SB placement values: TOP_OF_SEARCH, DETAIL_PAGE, HOME, OTHER (SP names are translated).
percentage is -99 to 900. Amazon only accepts SB adjustments with automated bidding off,
so an SB update also turns bid optimization off for that campaign.
Optionally include "strategy" (LEGACY_FOR_SALES / AUTO_FOR_SALES / MANUAL).
confirmed: Must be True to execute. First call returns a preview.
updates_ref: OPTIONAL. Id of a changeset uploaded earlier
(upload_changeset / mcp_push.py --upload). When given, the
rows come from storage and `updates` must be left empty.
This is how a bulk file is pushed without putting the whole
payload in the conversation.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| ad_programrequired | str | — |
| updatesoptional | str | None |
| confirmedoptional | bool | False |
| updates_refoptional | str | None |
Products & listings 10
WRITE
add_product_ads
ADD product ads (ASINs/SKUs) to an EXISTING campaign/ad group.
Use when the user wants to add products to advertise in a campaign.
For adding keywords or targets, use add_keywords_targets instead.
Supported ad_programs: SP, SD
Required fields:
SP: adGroupId, campaignId, state (ENABLED/PAUSED), asin (vendors) or sku (sellers)
SD: adGroupId, campaignId, state (enabled/paused), asin (vendors) or sku (sellers)
Max per call: SP 1000, SD 100.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
ad_program: SP or SD
entities: JSON string — array of product ad dicts with required fields
confirmed: Must be True to execute. First call returns a preview.
updates_ref: OPTIONAL. Id of a changeset uploaded earlier
(upload_changeset / mcp_push.py --upload). When given, the
rows come from storage and `entities` must be left empty.
This is how a bulk file is pushed without putting the whole
payload in the conversation.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| ad_programrequired | str | — |
| entitiesoptional | str | None |
| confirmedoptional | bool | False |
| updates_refoptional | str | None |
READ
find_weak_listings
Listings in this client's own catalogue that fail a basic content check:
too few images, no A+ content, or a low star rating. Use when the user asks
which listings are weak, thin, need better images/A+, or "what should we fix".
Returns the client's OWN products only — competitor ASINs are never included.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier (same one every other tool uses)
marketplace: 2-letter country code. Default: all marketplaces
min_images: Flag listings with fewer gallery images than this (default: 5)
min_rating: Flag listings rated below this (default: 4.0)
require_aplus: True also flags listings with no A+ content (default: True)
limit: Max rows (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | None |
| min_imagesoptional | int | 5 |
| min_ratingoptional | float | 4.0 |
| require_aplusoptional | bool | True |
| limitoptional | int | None |
READ
get_adproduct_performance
Use when user asks for ASIN/adproduct performance, product-level performance, or wants to see
BOTH ad performance AND total sales (organic + ad) for each ASIN.
Returns one row per ASIN with: ad spend, ad sales, ad orders (from product_data),
PLUS total store sales, total orders, sessions (from sales_data / Business Report),
PLUS computed organic_sales, ACOS, TACOS, organic_share_pct.
Includes ASINs with only organic sales (no ads) so you see full catalog performance.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
date_from: Start date YYYY-MM-DD (default: 30 days ago)
date_to: End date YYYY-MM-DD (default: today)
ad_program: SP, SD, or None for all
asin: Filter to specific ASIN (optional)
min_spend: Only show ASINs with ad_spend above this (default: 0)
status: Entity status filter — defaults to ENABLED + PAUSED, hides ARCHIVED.
Pass "ENABLED", "PAUSED", or "ARCHIVED" to override.
limit: Max rows
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| ad_programoptional | str | None |
| asinoptional | str | None |
| min_spendoptional | float | 0 |
| statusoptional | str | None |
| limitoptional | int | None |
READ
get_competitor_products
Scraped listing data for the COMPETITOR ASINs this client advertises against
(relation = 'targeted'). Use for competitive comparison — their titles, brands,
ratings, review counts, image counts and prices.
These are NOT the client's products. Never add these counts to the client's
own catalogue numbers; use find_weak_listings or get_scrape_coverage for that.
IMPORTANT - If this returns empty, this client has no scraped competitor
targets. It does NOT mean the data source is down.
Args:
client_id: The client identifier
marketplace: 2-letter country code. Default: all
limit: Max rows (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | None |
| limitoptional | int | None |
READ
get_fba_reports
Read raw data from any of the 6 FBA S3 parquet report files.
REPORT TYPES:
- "awd_inventory": Amazon Warehousing & Distribution warehouse stock levels
(available_units, reserved_units, inbound qty). Snapshot-based.
- "reimbursements": Amazon refunds for damaged/lost items
(case_id, currency_amount, reason). Approval-date filterable.
- "removals": Removal requests from FBA (return/dispose/liquidate)
(request_date, order_status, quantities). Request-date filterable.
- "shipments": Outbound FBA shipments/sales
(shipment_date, quantity, amount). Shipment-date filterable.
- "ledger": Full inventory audit trail — every movement/adjustment
(received, damaged, disposed, shipped, transferred). Event-based.
- "manage_inventory": Raw fba_manage_inventory rows (all inventory quantity columns).
For simple current-stock queries, prefer `get_inventory` instead.
ROUTING:
Use get_inventory for: "current stock", "how much stock", "low stock alerts", "days of supply"
Use get_fba_reports for: everything else — reimbursements, removals, shipments history,
AWD stock, ledger audit, or raw manage_inventory rows for custom analysis.
Data source: S3 parquet at inventory-data/<client>-<mkt>/<YYYY-MM>/<report>.parquet
Rows are capped for context; `summary` totals are exact over ALL rows.
Args:
client_id: Client identifier (e.g. "AMERICAN TEXTILE INDUSTRIES LLC")
report_type: One of awd_inventory / reimbursements / removals / shipments / ledger / manage_inventory
marketplace: US, CA, UK, IN, etc.
date_from: YYYY-MM-DD start filter (default: 30 days ago). Filter column varies by report_type.
date_to: YYYY-MM-DD end filter (default: today)
asin: Filter to specific ASIN
sku: Filter to specific SKU
limit: Max rows to return
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| report_typerequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| asinoptional | str | None |
| skuoptional | str | None |
| limitoptional | int | None |
READ
get_inventory
Get FBA inventory data for a client. Data is weekly snapshots stored in S3.
Returns per-ASIN/SKU inventory: warehouse stock, fulfillable, unsellable,
reserved, inbound pipeline (working/shipped/receiving), future supply, and price.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier (matches inventory-data/<CLIENT-MARKETPLACE>/ folder)
marketplace: 2-letter country code (US, CA, UK, IN, etc.)
week_start: Filter by week_start date YYYY-MM-DD (default: latest week available)
week_end: Filter by week_end date YYYY-MM-DD (optional, for range queries)
asin: Filter to specific ASIN (optional)
sku: Filter to specific SKU (optional)
low_stock_only: If True, return only items with afn-fulfillable-quantity < 20
limit: Max rows (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| week_startoptional | str | None |
| week_endoptional | str | None |
| asinoptional | str | None |
| skuoptional | str | None |
| low_stock_onlyoptional | bool | False |
| limitoptional | int | None |
READ
get_listing_quality
Ad spend joined to scraped listing quality, per ASIN. This is the tool that
answers "where are we spending money on a weak listing" — it puts cost, sales
and ACOS next to rating, review count, image count, video count and A+ status.
An ASIN that has spend but was never scraped still appears, with
scrape_status = 'not_scraped' and blank listing fields. That is honest
reporting, not a failure.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: 2-letter country code (default: US)
date_from: Start date YYYY-MM-DD (default: 30 days ago)
date_to: End date YYYY-MM-DD (default: today)
min_spend: Only ASINs with cost above this (default: 0)
limit: Max rows (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| min_spendoptional | float | 0 |
| limitoptional | int | None |
READ
get_product_detail
Scraped Amazon detail-page data for one ASIN (or a comma-separated list of ASINs).
Use when the user asks what a listing LOOKS like rather than how the ads performed:
title, brand, bullets, description, rating, review count, image/video count,
A+ content, brand story, storefront, price, availability, buy box, seller.
This is scraped listing content, NOT ad performance. For spend/sales use
get_products. To see spend and listing quality side by side use get_listing_quality.
Empty result = no matching data, not an outage.
Do not invent narratives about system outages or fall back to external files.
Args:
asin: One ASIN, or several separated by commas (max 20)
marketplace: 2-letter country code (US, CA, UK, IN, MX, AE, SA, AU). Default: all
client_id: Optional, narrows to one client
include_competitors: True also returns 'targeted' competitor ASINs (default: False)
| Parameter | Type | Default |
|---|---|---|
| asinrequired | str | — |
| marketplaceoptional | str | None |
| client_idoptional | str | None |
| include_competitorsoptional | bool | False |
READ
get_product_entities
Get ALL advertised products (ASINs) with their current status — includes paused/archived ads.
Data is from the latest daily snapshot.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: US, CA, UK, AE, SA, IN, AU etc. (required)
state: Filter by ENABLED, PAUSED, or ARCHIVED (optional)
campaign_id: Filter by specific campaign ID (optional)
ad_program: Filter by "SP", "SB", or "SD" (optional)
asin: Filter by specific ASIN (optional)
limit: Max rows to return (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| stateoptional | str | None |
| campaign_idoptional | str | None |
| ad_programoptional | str | None |
| asinoptional | str | None |
| limitoptional | int | None |
READ
get_products
Use when user asks for product/ASIN-level ad data, or as FALLBACK when get_campaign and get_keywords return empty.
Priority order: get_campaign (1st) -> get_keywords (2nd) -> get_products (3rd) -> get_search_terms (last).
Returns ASIN-level ad performance from the product report. Ad products (ASINs) that are ENABLED but had ZERO
impressions (absent from the performance report) are merged in from the entity snapshot, showing status. Covers SP, SD.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: 2-letter country code
date_from: Start date YYYY-MM-DD (default: 30 days ago)
date_to: End date YYYY-MM-DD (default: today)
ad_program: "SP", "SD", or None
min_spend: Only products with cost above this (default: 0)
limit: Max rows (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| ad_programoptional | str | None |
| min_spendoptional | float | 0 |
| statusoptional | str | None |
| limitoptional | int | None |
Budgets 2
READ
get_budget_usage
Current daily budget usage percentage per campaign (real-time, updates every 15 min).
Shows which campaigns are close to exhausting their daily budget.
Use for: budget pacing checks, "AMS budget", "budget usage", finding underspending or about-to-exhaust campaigns.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: Client name (case-insensitive)
marketplace: US, CA, UK, etc.
high_usage_only: If True, only show campaigns >75% budget used
limit: Max rows
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| high_usage_onlyoptional | bool | False |
| limitoptional | int | None |
READ
recommend_budgets
Smart budget recommendations based on performance (ROAS + orders) AND utilization.
mode="utilization" (v39, ticket #57) runs the daily-routine STEP 8 rule
server-side instead of in the prompt. target_roas / min_orders are NOT
needed in this mode. Per ENABLED campaign with spend in the window:
util_pct = (spend / lookback_days) / daily_budget * 100
ACCOUNT_ROAS = total sales / total spend across all campaigns
RAISE util > utilization_gate_pct AND roas > ACCOUNT_ROAS
-> recommended = budget * raise_factor
DECREASE util > utilization_gate_pct AND roas < 0.6 * ACCOUNT_ROAS
-> recommended = max(budget * decrease_factor, budget_floor);
never when budget <= budget_floor
HOLD everything else (reason given)
cooldown a campaign with a budget change pushed in the last
cooldown_days (from the change log) is returned with
action="cooldown" and is not to be pushed today.
Returns `recommendations` (one row per campaign) + counts in `summary`.
Returns 3 lists:
- underfunded_campaigns: Hitting budget cap AND performing well (ROAS >= target).
Recommend budget INCREASE — leaving money on the table.
- overfunded_campaigns: Spending fully but returning below target ROAS.
Recommend budget DECREASE — cutting waste.
- review_pause_campaigns: Low orders AND low ROAS.
Recommend review or pause — likely not worth the spend.
Each recommendation includes reasoning (logic field), current + recommended budget,
change amount, and current + target ROAS.
REQUIRES target_roas and min_orders. If user doesn't provide these, the tool returns
an error telling you to ASK the user. Do NOT pick defaults.
scale_down_strategy options:
- "adaptive" (default): peak spend on days when ROAS >= target × 1.2. Falls back
to avg × 0.7 if no good ROAS days. Most personalized to campaign history.
- "conservative": avg_daily_spend × 0.7 (light cut, safe)
- "aggressive": avg_daily_spend × 0.5 (deep cut, faster savings)
ROUTING: Use for "budget recommendations", "which campaigns to scale up",
"budget optimization", "reallocate budget", "budget audit", "budget check".
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
target_roas: REQUIRED. Desired ROAS (e.g., 3.0 = $3 sales per $1 spend)
min_orders: REQUIRED. Minimum orders in lookback to consider campaign active
lookback_days: Days to evaluate (default 7)
ad_program: SP, SB, SD, or None for all
scale_down_strategy: "adaptive" (default) | "conservative" | "aggressive"
cap_hit_threshold_pct: % of days hitting budget cap to flag underfunded (default 30)
peak_use_threshold_pct: % peak utilization to flag overfunded (default 90)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| target_roasoptional | float | None |
| min_ordersoptional | int | None |
| lookback_daysoptional | int | 7 |
| ad_programoptional | str | None |
| scale_down_strategyoptional | str | 'adaptive' |
| cap_hit_threshold_pctoptional | float | 30.0 |
| peak_use_threshold_pctoptional | float | 90.0 |
| modeoptional | str | 'roas' |
| raise_factoroptional | float | 1.2 |
| decrease_factoroptional | float | 0.8 |
| utilization_gate_pctoptional | float | 90.0 |
| budget_flooroptional | float | 5.0 |
| cooldown_daysoptional | int | 4 |
Performance & sales 8
READ
compare_periods
Compare ad performance between two date periods.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: Marketplace code
ad_program: "SP", "SB", or "SD" (default: all)
period1_from/to: First period dates (default: last 7 days)
period2_from/to: Second period dates (default: 7 days before period 1)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| ad_programoptional | str | None |
| period1_fromoptional | str | None |
| period1_tooptional | str | None |
| period2_fromoptional | str | None |
| period2_tooptional | str | None |
READ
find_wasted_spend
Find keywords/targets with high spend but zero or very low sales (wasted ad spend).
Every flagged row carries ONE `action` (v39, ticket #56). This tool works on
the keyword/target being bid on, so it NEVER suggests negation - negatives
are a search-term decision (search_term_analysis / get_search_terms):
- "pause" zero sales on real spend
- "reduce_bid" sales exist but ACOS is above acos_threshold
- "watch" clicks below min_clicks - not enough evidence to act
`summary` has the count per action.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: Marketplace code
ad_program: "SP", "SB", or "SD" (default: all)
min_spend: Minimum spend threshold (default: 50)
acos_threshold: ACOS ratio above which to flag (default: 2.0 = 200%)
days: Lookback window (default: 30)
limit: Max rows (default: no limit)
min_clicks: evidence gate - rows under this many clicks are returned as
action="watch" instead of pause/reduce_bid (default 0 = off)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| ad_programoptional | str | None |
| min_spendoptional | float | 50 |
| acos_thresholdoptional | float | 2.0 |
| daysoptional | int | 30 |
| limitoptional | int | None |
| min_clicksoptional | int | 0 |
READ
get_hourly_data
⚠️ ONLY call this tool when the user EXPLICITLY asks for HOURLY breakdown or dayparting analysis.
per_date=True: one row per DATE (sums of the hours) instead of every hour - the freshest daily totals of
store sales and ad spend (TACOS = spend / sales), e.g. for a 7-day sales matrix.
Do NOT use for daily, weekly, monthly, or general performance queries — use get_campaign or get_search_terms instead.
Returns hour-by-hour ad performance (spend, clicks, impressions, orders, sales).
Data comes from a separate hourly dataset — heavier query, only use when needed.
Date in CSV is DD-MM-YYYY format. Provide date_from/date_to in YYYY-MM-DD format — conversion is handled automatically.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: 2-letter country code (US, CA, UK, IN, MX, AE, SA, AU)
date_from: Start date YYYY-MM-DD (default: 7 days ago)
date_to: End date YYYY-MM-DD (default: today)
hour: Filter by specific hour e.g. '08:00 AM' (optional)
limit: Max rows (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| houroptional | str | None |
| limitoptional | int | None |
| per_dateoptional | bool | False |
READ
get_performance_data
Ad performance + total store sales for ANY date range and ANY granularity.
Not just daily — supports total (whole period), daily, weekly, monthly views.
ROUTING: Use for ALL performance data questions across a period.
- Total for a period → granularity="total"
- Day-by-day trend → granularity="daily" (default)
- Weekly rollup → granularity="weekly" (returns daily rows + weekly total)
- Monthly rollup → granularity="monthly" (returns daily rows + monthly total)
Data sources (all UNIONed / joined):
- Ad performance: campaign_placement_data (SP) + campaign_data (SB/SD)
- Total store sales: sales_data (Amazon Business Report)
Returns per row:
- Ad: impressions, clicks, ad_spend, ad_sales, ad_orders
- Store: total_sales, total_orders, sessions (only for account breakdown)
- Computed: acos, tacos, cpc, ctr, cvr (as percentages)
- row_type: "daily" for daily rows, "weekly_total"/"monthly_total" for summary rows
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
date_from: YYYY-MM-DD (default: 30 days ago)
date_to: YYYY-MM-DD (default: today)
breakdown: "account" (default, one row per date bucket)
| "campaign" (per date bucket per campaign)
| "keyword" (per date bucket per keyword)
granularity: "total" (single summary row for whole range)
| "daily" (default, one row per day)
| "weekly" (daily rows + weekly totals)
| "monthly" (daily rows + monthly totals)
ad_program: SP, SB, SD, or None
campaign_id: one campaign id, or a comma-separated list (breakdown != account)
keyword_text: keyword text match (substring), or a comma-separated list of texts
keyword_ids: comma-separated keyword/target ids - exact match, keyword breakdown only.
Use this for a change-impact review: pass the changed ids from
get_change_history and only those rows come back.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| breakdownoptional | str | 'account' |
| granularityoptional | str | 'daily' |
| ad_programoptional | str | None |
| campaign_idoptional | str | None |
| keyword_textoptional | str | None |
| keyword_idsoptional | str | None |
READ
get_realtime_conversions
Real-time hourly conversion data from Amazon Marketing Stream.
Returns purchases, sales, units sold, attributed conversions per hour per campaign.
Conversion data lags traffic by 30-90 min (Amazon needs time to attribute clicks to orders).
14-day attribution columns continue updating as customers buy days after their click.
Use for "real-time sales", "AMS", "AMS conversion data", "stream conversions", "hourly conversions", "today's orders", or live ACOS tracking.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: Client name (case-insensitive)
marketplace: US, CA, UK, etc.
hours_back: 1-48 hours (default 24)
ad_program: SP, SB, SD, or None for all
limit: Max rows
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| hours_backoptional | int | 24 |
| ad_programoptional | str | None |
| limitoptional | int | None |
READ
get_realtime_traffic
Real-time hourly ad traffic from Amazon Marketing Stream (updates every 15 min).
Returns hourly impressions, clicks, cost per campaign for the last N hours.
Use when user asks for "real-time", "AMS", "AMS traffic data", "stream data", "right now", "last hour", or "today's hourly".
Data lags ~15-30 min behind real-time. Source covers a rolling ~48 hour window.
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: Client name (matches AMS-Conversion folder name, case-insensitive)
marketplace: US, CA, UK, IN, AE etc.
hours_back: How many hours back from now (default 24, max 48 — source only has 2 days)
ad_program: SP, SB, SD, or None for all
limit: Max rows (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| hours_backoptional | int | 24 |
| ad_programoptional | str | None |
| limitoptional | int | None |
READ
get_sales_data
Use when user asks for TOTAL sales, revenue, business report, organic sales, or TACOS.
This is NOT ad sales — this is total business performance (ad + organic combined), ASIN-level.
Returns: revenue, orders, units, sessions from business/order reports.
For AD-only sales, use get_campaign or get_keywords instead.
When user says "sales" without specifying, clarify: "Ad sales or total sales including organic?"
This is organic + ad sales combined (not just ad sales).
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = no matching data, not an outage.
Args:
client_id: The client identifier
marketplace: US, CA, UK, IN, etc.
date_from: Start date YYYY-MM-DD (default: 30 days ago)
date_to: End date YYYY-MM-DD (default: today)
asin: Filter by specific ASIN (optional)
limit: Max rows (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| asinoptional | str | None |
| limitoptional | int | None |
READ
get_scrape_coverage
How much scraped listing data exists, and how fresh it is, per client and
marketplace. Call this first when the user asks whether we have listing data
for a client, or why a listing tool came back empty.
IMPORTANT - If a client is missing from this list, that client has never been
scraped. It does NOT mean the data source is down.
Args:
client_id: Optional, narrows to one client
marketplace: Optional 2-letter country code
| Parameter | Type | Default |
|---|---|---|
| client_idoptional | str | None |
| marketplaceoptional | str | None |
Changes & history 15
WRITE
apply_staged_changes
PUSH previously-staged changes to Amazon via the Ads API. Use when the user is ready to apply
changes that were saved (staged) earlier. Select which to apply by change_id or by change_date.
Pushes keyword/target bid+state, campaign budget+state, and (v39) staged negatives
(change_type negative_keyword / negative_target - rows need campaignId, adGroupId and
keywordText+matchType or expression). Any other change_type is reported under "skipped".
success=true ONLY when every attempted row was acknowledged by Amazon.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, etc.
change_id: apply a specific staged batch (preferred)
change_date: apply everything staged on this date
confirmed: must be True to push. First call returns a preview.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| change_idoptional | str | None |
| change_dateoptional | str | None |
| confirmedoptional | bool | False |
WRITE
delete_changeset
DELETE one of your changesets now, instead of waiting for it to expire.
The audit log keeps the record of anything that was already pushed.
Args:
changeset_id: cs_xxxxxxxxxx
confirmed: must be True to delete. First call returns a preview.
| Parameter | Type | Default |
|---|---|---|
| changeset_idrequired | str | — |
| confirmedoptional | bool | False |
WRITE
delete_staged_changes
Delete (void) staged/draft change batches that haven't been pushed yet.
Use to REMOVE stale draft batches from previous days so they cannot be
accidentally pushed. Deleted batches are gone — re-stage fresh suggestions
to push again.
ROUTING: use for "delete draft", "void batch", "remove stale changes",
"clear old staged bids".
Two-step confirmation:
- First call with confirmed=False: shows what would be deleted (dry run)
- Second call with confirmed=True: actually deletes
Args:
client_id: Client identifier
marketplace: Marketplace code (optional, for logging)
change_id: Specific batch to delete (from list_staged_changes)
change_date: YYYY-MM-DD — delete ALL batches from this date
confirmed: Must be True to actually delete. Default False = preview.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | None |
| change_idoptional | str | None |
| change_dateoptional | str | None |
| confirmedoptional | bool | False |
READ
get_audit_log
View recent write actions taken by the agent.
Empty result = no matching data, not an outage.
Args:
last_n: Number of recent actions to show (default: 20)
| Parameter | Type | Default |
|---|---|---|
| last_noptional | int | 20 |
READ
get_change_history
View past changes pushed to Amazon for an account, from the durable S3 change log.
Covers keywords, targets, campaigns, placements, and product ads with old/new bid,
old/new status, old/new budget, and old/new placement where applicable.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier (required)
marketplace: Filter by marketplace, e.g. US, IN (optional)
date_from: Start date YYYY-MM-DD (optional)
date_to: End date YYYY-MM-DD (optional)
year_month: Which monthly file to read, format YYYY_MM (defaults to current month)
change_type: keyword, target, campaign, placement, or productAds (optional)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | None |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| year_monthoptional | str | None |
| change_typeoptional | str | None |
READ
get_changeset
SHOW one changeset's metadata: rows, kind, client, status, expiry.
Never returns the rows themselves.
Empty result = no matching data, not an outage.
Args:
changeset_id: cs_xxxxxxxxxx
| Parameter | Type | Default |
|---|---|---|
| changeset_idrequired | str | — |
READ
get_staged_changes
Retrieve staged (not-yet-pushed) change rows for a client — the full saved data. Filterable by date
range, type, or a specific batch (change_id). Large results are saved as a CSV file automatically,
so this doubles as the date-wise EXPORT. Use to review or export staged changes.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: optional
date_from: optional YYYY-MM-DD (export everything staged on/after this date)
date_to: optional YYYY-MM-DD
change_type: optional filter (keyword/campaign/etc.)
change_id: optional — a specific staged batch
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | None |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| change_typeoptional | str | None |
| change_idoptional | str | None |
READ
get_todays_changes
View all keyword/target status changes made today.
Empty result = no matching data, not an outage.
Args:
client_id: Filter by client (optional)
marketplace: Filter by marketplace (optional)
change_type: "keyword" or "target" (optional)
| Parameter | Type | Default |
|---|---|---|
| client_idoptional | str | None |
| marketplaceoptional | str | None |
| change_typeoptional | str | None |
READ
list_changesets
LIST your stored changesets. Metadata only — this never returns the rows,
because dumping a payload back into a conversation is the cost this
feature exists to remove.
Empty result = no matching data, not an outage.
Args:
client_id: optional filter
status: optional filter — "new" or "applied"
limit: max rows to return (default 50)
| Parameter | Type | Default |
|---|---|---|
| client_idoptional | str | None |
| statusoptional | str | None |
| limitoptional | int | 50 |
READ
list_staged_changes
List staged (not-yet-pushed) changes for a client — summary by date and type, with batch ids.
Use to see what changes are parked in the draft store before exporting or applying them.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: optional
date_from: optional YYYY-MM-DD
date_to: optional YYYY-MM-DD
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | None |
| date_fromoptional | str | None |
| date_tooptional | str | None |
READ
reset_changeset
Put an APPLIED changeset back to "new" so it can be pushed again.
Use only when a re-push is genuinely wanted — the double-push guard
exists for a reason.
Args:
changeset_id: cs_xxxxxxxxxx
| Parameter | Type | Default |
|---|---|---|
| changeset_idrequired | str | — |
WRITE
stage_changes
SAVE changes to a draft store WITHOUT pushing to Amazon. Use when the user wants to prepare/stage
changes to review, export, or apply later — NOT push live now. Stored per client in S3, append-only,
tagged with a change date so they can be exported date-wise.
Two modes:
1. Direct: pass `rows` = JSON array of full row dicts (all ids + fields you want to save).
2. Re-fetch: pass `entity_ids` = JSON array of ids + change_type; the tool pulls the current full
rows from the matching entity table (entity_keywords / entity_campaigns / entity_adproducts) and stages those.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, etc.
change_type: keyword | target | campaign | campaign_placement | product_ad | search_term
| negative_keyword | negative_target (v39: pushable by apply_staged_changes;
rows need campaignId, adGroupId, keywordText, matchType [NEGATIVE_EXACT /
NEGATIVE_PHRASE] or expression, plus ad_program) | custom
rows: JSON array of row dicts (mode 1). Each row can have any columns — they are all stored.
entity_ids: JSON array of entity id strings (mode 2) — fetches current rows for these ids.
change_date: YYYY-MM-DD tag for the change (default: today). Used for date-wise export.
note: optional note stored on every staged row.
updates_ref: OPTIONAL. Id of a changeset uploaded earlier
(upload_changeset / mcp_push.py --upload). When given, the
rows come from storage and `rows` must be left empty.
This is how a bulk file is pushed without putting the whole
payload in the conversation.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| change_typerequired | str | — |
| rowsoptional | str | None |
| entity_idsoptional | str | None |
| change_dateoptional | str | None |
| noteoptional | str | None |
| updates_refoptional | str | None |
READ
suggest_bid_changes
Generate bid adjustment suggestions based on target ACOS. Does NOT make changes.
Returns per suggestion (each row has):
- keyword: text (like "cotton sheets") OR targeting expression (like "close-match" or 'asin="B01..."')
- matchType: BROAD/PHRASE/EXACT (real keywords)
OR TARGETING_EXPRESSION_PREDEFINED (auto-targeting: close-match/loose-match/substitutes/complements)
OR TARGETING_EXPRESSION (product target or category target)
- keywordId, adgroupId, campaignId
- entity_type: "keyword" or "target"
- api_route: "keywords" or "targets"
- targetId: same numeric value as keywordId, populated only when entity_type=target
- action: INCREASE / REDUCE
- current_cpc, suggested_bid, change_pct, reason, current_acos
- spend, sales, orders
CRITICAL - ROUTING TO CORRECT AMAZON API:
Amazon Ads has TWO separate APIs for bid updates:
- keywords API for BROAD/PHRASE/EXACT keyword entities
- targets API for auto-targeting AND product-target entities
Sending a target to the keywords API returns ENTITY_NOT_FOUND.
HOW TO APPLY THESE SUGGESTIONS:
1. Split suggestions into two groups by api_route (or by matchType):
Group A: matchType in [BROAD, PHRASE, EXACT]
-> keywords API
Group B: matchType in [TARGETING_EXPRESSION_PREDEFINED, TARGETING_EXPRESSION]
-> targets API
2. Call batch_update_entities TWICE:
- Once with entity_type="keywords" for Group A (use keywordId)
- Once with entity_type="targets" for Group B (use targetId — same numeric value as keywordId)
3. NEVER mix keywords and targets in one batch_update_entities call.
CRITICAL for SB (Sponsored Brands):
- SB keywords updates REQUIRE both `campaignId` AND `adGroupId` in each data_batch item.
- SB targets updates REQUIRE `adGroupId` in each data_batch item.
- Without these, Amazon returns success with code=INVALID_ARGUMENT and reason=KEYWORD_MISSING_AD_GROUP_ID / TARGET_MISSING_AD_GROUP_ID (no actual change applied).
- SP updates do NOT need adGroupId — only keywordId/targetId is enough.
Rows are capped for context; `summary` totals are exact over ALL rows.
Args:
client_id: The client identifier
marketplace: Marketplace code
ad_program: "SP", "SB", or "SD" (default: all)
target_acos: Target ACOS ratio (0.25 = 25%)
days: Lookback window
limit: Max suggestions (default: no limit)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| ad_programoptional | str | None |
| target_acosoptional | float | None |
| daysoptional | int | 30 |
| limitoptional | int | None |
READ
sweep_changesets
ADMIN. Delete every expired changeset now instead of waiting for the
lazy hourly sweep. Reports what it removed.
No inputs — call it directly.
READ
upload_changeset
STORE a bulk change file once and get back a short id to reference later.
Point of this tool: the rows are uploaded a single time, then every write
tool can be called with updates_ref="cs_..." instead of the whole payload.
A 1000 row file costs about 27k tokens inline, and about 40 as a reference.
Prefer uploading from the box with `mcp_push.py --upload` (or the admin
dashboard) — that path never puts the rows in a conversation at all.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
kind: keywords | targets | themes | productAds | negativeKeywords |
negativeTargets | campaigns | campaign_placements | new_keywords |
new_targets | new_themes | new_productAds | staged_rows
rows: JSON string — array of row dicts, the same shape the matching
write tool documents. Validated here, so a bad file is refused
before it can cost an API call.
ad_program: SP, SB or SD
note: optional free text stored with the changeset
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| kindrequired | str | — |
| rowsrequired | str | — |
| ad_programoptional | str | 'SP' |
| noteoptional | str | None |
Skills 7
READ
approve_skill
[ADMIN ONLY] Approve a pending skill. It then becomes available
for all users to sync into their local skill folders.
Empty result = no matching data, not an outage.
Args:
skill_id: integer ID from list_pending_skills()
note: optional note for the submitter (max 1000 chars)
| Parameter | Type | Default |
|---|---|---|
| skill_idrequired | int | — |
| noteoptional | str | '' |
READ
get_approved_skills
List all approved community skills. Use to discover patterns
other team members have submitted and that admins have blessed.
Empty result = no matching data, not an outage.
Args:
category: optional filter — 'workflow' | 'athena' | 'guardrail' | etc.
| Parameter | Type | Default |
|---|---|---|
| categoryoptional | str | None |
READ
get_my_skills
List skills you've submitted, with their current review status.
Empty result = no matching data, not an outage.
No inputs — call it directly.
READ
get_skill_detail
[ADMIN ONLY] Get the full content of a specific skill submission.
Empty result = no matching data, not an outage.
Args:
skill_id: integer ID from list_pending_skills() output
| Parameter | Type | Default |
|---|---|---|
| skill_idrequired | int | — |
READ
list_pending_skills
[ADMIN ONLY] Return all skills awaiting admin review.
Use this when you (an admin) ask 'show me pending skills' or
'what skills need approval'. Non-admin callers receive an error.
Returns: JSON list of pending skill submissions with id, title,
category, submitted_by, submitted_at, content (truncated to 500 chars
for the list view — use get_skill_detail(id) for full content).
Empty result = no matching data, not an outage.
No inputs — call it directly.
READ
reject_skill
[ADMIN ONLY] Reject a pending skill with a reason for the submitter.
Empty result = no matching data, not an outage.
Args:
skill_id: integer ID from list_pending_skills()
reason: required explanation (max 1000 chars)
| Parameter | Type | Default |
|---|---|---|
| skill_idrequired | int | — |
| reasonrequired | str | — |
READ
submit_my_skill
Submit a new skill / workflow / pattern for admin review.
After admin approval, the skill becomes part of the shared knowledge
base that all users can sync into their local environments.
Empty result = no matching data, not an outage.
Args:
title: short title, e.g. "Quarterly review template"
content: full skill body (Markdown supported, max 50KB)
category: 'workflow' (default) | 'athena' | 'guardrail' | 'analysis' | 'other'
| Parameter | Type | Default |
|---|---|---|
| titlerequired | str | — |
| contentrequired | str | — |
| categoryoptional | str | 'workflow' |
Reports & support 5
READ
get_my_reports
Your own submitted daily reports, newest first.
Use to check whether you already reported today, or to review what you
reported earlier in the week.
Args:
limit: how many days back to return (default 14).
| Parameter | Type | Default |
|---|---|---|
| limitoptional | int | 14 |
READ
get_my_support_requests
View your submitted support tickets and admin responses.
Empty result = no matching data, not an outage.
No inputs — call it directly.
READ
get_report_format
STEP 1 of submitting your daily report. Call this FIRST, before submit_daily_report.
Returns the exact format the server expects, plus the MCP activity the server
has already recorded for you today (so you do not have to reconstruct it).
Use this whenever the user asks to "submit my report", "send my daily report",
"report my work", or similar. Follow the returned instructions exactly, then
call submit_daily_report with what you found.
No inputs — call it directly.
READ
submit_daily_report
STEP 2 of submitting your daily report. Call get_report_format FIRST.
Saves your report to your profile. It appears on your dashboard and on the
admin Reports page immediately, and goes to the WhatsApp group.
Re-submitting for the same date creates a new version. The previous one is
kept, not deleted.
THE REPORT IS THE TASK LIST. Every job gets its own entry with its own
numbers -- negatives, budgets and bids are never described in one
sentence, and analysing is never merged with pushing.
Args:
tasks: JSON array, one object per task. This is the report.
[{"category":"mcp","client":"Binca","marketplace":"IN",
"task":"Negative analysis",
"detail":"322 exact negs, 46 ASIN targets, 473 phrase negs"},
{"category":"mcp","client":"Binca","marketplace":"IN",
"task":"Budget optimizer","settings":"L7",
"detail":"33 campaigns","result":"net -Rs963/day"},
{"category":"mcp","client":"Binca","marketplace":"IN",
"task":"Bid increases","pushed":20,"attempted":23}]
Fields: category (mcp|other), client, marketplace, task, settings,
detail, pushed (int), attempted (int), result, how. Only 'task' is
required. Use 'other' category for non-Amazon terminal work.
mcp_summary: LEGACY free text. Leave blank when you pass tasks.
other_summary: LEGACY free text. Leave blank when you pass tasks.
approach: Fallback 'how' for the whole day, used only when no task
carries its own. Taken from the session tool_sequence.
highlight: The single most reusable thing from today -- a technique,
a check worth repeating, a mistake worth avoiding. Shared
with the whole team. Leave blank rather than padding it.
tokens_mcp: Tokens spent on MCP work (from opencode.db).
tokens_other: Tokens spent on other work (from opencode.db).
sessions_count: How many OpenCode sessions today.
blockers: Anything blocking you, or 'none'.
report_date: YYYY-MM-DD. Leave blank for today (IST). Use this to
back-fill a day you missed.
| Parameter | Type | Default |
|---|---|---|
| tasksoptional | str | '' |
| mcp_summaryoptional | str | '' |
| other_summaryoptional | str | '' |
| approachoptional | str | '' |
| highlightoptional | str | '' |
| tokens_mcpoptional | int | 0 |
| tokens_otheroptional | int | 0 |
| sessions_countoptional | int | 0 |
| blockersoptional | str | 'none' |
| report_dateoptional | str | '' |
READ
submit_support_request
Open a request with the Optimiseres team (bug, data request, MIS change, access, report change, new feature,
question). The team is mailed at once; you are mailed and see it on your dashboard on every change.
Args:
subject: Brief title of your request
description: What is wrong or what is needed, for which account, by when
request_type: question | bug | data | mis_change | access | report_change | feature
client_id: the client this is about (as in get_clients), optional
marketplace: US, IN, UK ... optional
priority: low | normal | high | urgent
| Parameter | Type | Default |
|---|---|---|
| subjectrequired | str | — |
| descriptionrequired | str | — |
| request_typeoptional | str | 'question' |
| client_idoptional | str | '' |
| marketplaceoptional | str | '' |
| priorityoptional | str | 'normal' |
Session & login 6
READ
get_my_session_setting
Show YOUR session logout setting.
By default every session is logged out on the admin's timer. You can ask an
admin to make YOUR session never auto-logout, with request_no_logout. This
tool tells you which mode you are on and the status of any request. Affects
only your own account.
No inputs — call it directly.
READ
refresh_credentials_cache
Force re-download credentials XLSX from Google Drive.
Use this if a new account was added or credentials were updated.
Empty result = no matching data, not an outage.
Args:
No inputs — call it directly.
READ
request_login_otp
Request a one-time code for re-authentication. Your email is auto-detected
from your existing session. If not found, provide your registered email.
Empty result = no matching data, not an outage.
Args:
email: Your registered email (optional — auto-detected if possible)
| Parameter | Type | Default |
|---|---|---|
| emailoptional | str | '' |
READ
request_no_logout
Ask an admin to make YOUR session never auto-logout.
By default every session expires on the admin's timer and you must log in
again. This sends a request to an admin; until they approve it, your session
still follows the admin timer. Affects only your own account.
Args:
reason: Optional short note for the admin (why you need a permanent session).
| Parameter | Type | Default |
|---|---|---|
| reasonoptional | str | '' |
READ
set_my_mode
Opt YOURSELF in or out of the v37 behaviours. Affects only your own account,
never anyone else's, and takes effect on your very next call.
Call with no arguments to see what you are currently on.
response_mode:
"compact" fast mode. Big results are capped to the top rows (ranked by
spend) with exact totals in `summary`, and the full result is
written to a file you can fetch. Much smaller replies.
"full" the original v36 behaviour - every row inline. Slower and far
larger, but nothing is capped.
"" clear your override and follow the server default.
write_path:
"official" send your Amazon UPDATES through Amazon's official Ads MCP
server instead of the direct API. Falls back automatically if
the account is not enabled for it. Amazon lists this as beta.
"direct" the proven direct Ads API. This is the default.
"" clear your override and follow the server default.
Args:
response_mode: "compact", "full", or "" to clear
write_path: "official", "direct", or "" to clear
confirmed: required to CHANGE anything; omit it to just read your settings
| Parameter | Type | Default |
|---|---|---|
| response_modeoptional | str | '' |
| write_pathoptional | str | '' |
| confirmedoptional | bool | False |
READ
verify_login_otp
Verify the OTP code and restore your session. Email is auto-detected.
Empty result = no matching data, not an outage.
Args:
code: The 6-digit code from your email
email: Your registered email (optional — auto-detected if possible)
| Parameter | Type | Default |
|---|---|---|
| coderequired | str | — |
| emailoptional | str | '' |
Other tools 40
READ
amc_ask
Ask Amazon Marketing Cloud (AMC) an audience question for this client, through Amazon's official Ads MCP.
Questions (pick one): new_to_brand | repeat_buyers | time_to_reorder. Leave question empty to list them.
sql = your own AMC SELECT (admin only). AMC queries take minutes: if the answer is not ready within
wait_seconds you get an execution_id - call amc_result later. AMC hides groups under 100 people.
Args:
client_id: Client identifier (from get_clients)
marketplace: US, CA, UK, IN, etc.
question: new_to_brand, repeat_buyers or time_to_reorder
days: how many days back (1-400, default 90; AMC data ends ~2 days ago)
sql: admin only - a custom AMC SELECT instead of a question
wait_seconds: how long to wait for the answer (0-120)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| questionoptional | str | '' |
| daysoptional | int | 90 |
| sqloptional | str | '' |
| wait_secondsoptional | int | 50 |
WRITE
amc_create_audience
Turn an AMC cohort into an audience for Sponsored Display / DSP targeting, IF Amazon's official server offers an
audience tool for this account (the tool says so). Then boost SP bids on it with update_campaign_audience_bid.
Preview first (confirmed=False), show the user, then confirmed=True.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
name: audience name (as it should appear in the Ads console)
question: a ready question or saved query whose rows are the cohort (its SQL must return user_id)
sql: admin only - a custom AMC SELECT returning user_id
description: optional text for the audience
confirmed: False = preview, True = create
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| namerequired | str | — |
| questionoptional | str | '' |
| sqloptional | str | '' |
| descriptionoptional | str | '' |
| confirmedoptional | bool | False |
READ
amc_discover
ADMIN ONLY, read only. Find each client's AMC ids from Amazon instead of typing them: the AMC account
id (ENTITY id, from Amazon's official account list) and the AMC instance id (from the AMC instance list).
save=True stores them for amc_ask where exactly one instance is found (never overwrites ids that differ).
Args:
client_id: one client (from get_clients), or "" for every client
marketplace: with client_id
save: store the ids found (default False = report only)
max_accounts: stop after this many accounts (default 150)
| Parameter | Type | Default |
|---|---|---|
| client_idoptional | str | '' |
| marketplaceoptional | str | '' |
| saveoptional | bool | False |
| max_accountsoptional | int | 150 |
READ
amc_export
An AMC result as a file. to="xlsx" = an Excel download link on the console; to="drive" = an .xlsx saved in the
team's Drive report folder (the link is returned).
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
result_id: from amc_ask / amc_results
to: xlsx | drive
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| result_idrequired | int | — |
| tooptional | str | 'xlsx' |
READ
amc_result
Status and rows of an AMC query started with amc_ask.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
execution_id: from amc_ask
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| execution_idrequired | str | — |
READ
amc_results
The AMC questions already run for this client (newest first): question, status, rows, when, who. Use the
result_id with amc_export to get the Excel file, or amc_result with the execution_id to see the rows again.
Args:
client_id: Client identifier (from get_clients)
marketplace: US, CA, UK, IN, etc.
limit: how many (default 20)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| limitoptional | int | 20 |
READ
amc_save_query
ADMIN / MANAGER. Save an AMC SELECT under a name so anyone with access can run it with amc_ask(question=name).
client_id empty = shared with every client that has AMC ids. weekly=True adds it to the Monday AMC pack (the console runs
it every week for each client with AMC ids and keeps the results).
Args:
name: short name (letters, digits, space, _ . -)
sql: one AMC SELECT / WITH query (read only)
client_id: a client (from get_clients) or "" for all
marketplace: with client_id
days: default window in days (1-400)
weekly: run every Monday in the AMC pack
| Parameter | Type | Default |
|---|---|---|
| namerequired | str | — |
| sqlrequired | str | — |
| client_idoptional | str | '' |
| marketplaceoptional | str | '' |
| daysoptional | int | 90 |
| weeklyoptional | bool | False |
READ
answer_exact
Compute an EXACT count/total over EVERY row in Athena, without shipping rows.
Use this instead of counting or summing rows yourself. The row tools can
return hundreds of thousands of rows for a large account - more than fits
in any context window - so any total you add up by hand is a total over
whatever slice you happened to see, not over the account. This tool asks
the database and returns the real number in a few dozen tokens.
ROUTING: use for "how many", "what is the total", "how much did we spend
on X", "how many keywords over N", "top N by spend" - any question whose
answer is a number or a short ranked list.
Args:
client_id: Client name
dataset: keywords | search_terms | campaigns | products | placements
metric: spend | sales | clicks | impressions | orders | units
marketplace: US, IN, UK, ...
date_from / date_to: YYYY-MM-DD. Defaults to the last 30 days.
filters: list of {"field": ..., "op": ..., "value": ...}
ops: eq ne gt gte lt lte contains not_contains
fields: campaign, campaign_id, ad_group, keyword, keyword_id,
match_type, search_term, asin, sku, placement, ad_program,
status, date, spend, sales_value, clicks_value,
impressions_value
group_by: optional field to break the answer down by
top_n: how many groups to return when group_by is used (default 10)
Returns: matching_rows, total_<metric>, and the top groups when grouped.
Every number is computed over the full dataset, not a sample.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| datasetrequired | str | — |
| metricoptional | str | 'spend' |
| marketplaceoptional | str | 'US' |
| date_fromoptional | str | None |
| date_tooptional | str | None |
| filtersoptional | list | None |
| group_byoptional | str | None |
| top_noptional | int | 10 |
WRITE
approve_rule_profile
ADMIN: approve a method someone wrote, so rules may run it.
Read what it will do first: the profile's conditions and caps are on
list_rule_profiles, and running any rule that follows it still builds a plan
before anything is pushed.
Args:
name: profile name
confirmed: must be True
note: optional note kept with the decision
| Parameter | Type | Default |
|---|---|---|
| namerequired | str | — |
| confirmedoptional | bool | False |
| noteoptional | str | None |
WRITE
approve_run
APPROVE a waiting rule run and push exactly the rows it planned, by reference.
Anyone with write access to that seller may approve, not only the person who
ran it. A plan older than plan_max_age_hours must be re-run instead.
Args:
run_id: from run_rule or run_rules
confirmed: must be True
write_path: "direct" or "official" for this push only
| Parameter | Type | Default |
|---|---|---|
| run_idrequired | str | — |
| confirmedoptional | bool | False |
| write_pathoptional | str | None |
WRITE
archive_entities
ARCHIVE Sponsored Products entities by id (campaigns, adGroups, keywords, targets, productAds,
negativeKeywords). Archiving CANNOT be undone - an archived entity can never be enabled again. Preview
first (confirmed=False), show the user the list, and confirm only after an explicit yes.
Use when: the user clearly asks to archive / delete for good. To stop something for now, use
update_keyword_status / update_target_status / update_campaign with PAUSED instead.
Returns: success and error rows per id.
Args:
client_id: exact name from get_clients
marketplace: US, CA, UK, IN, ...
entity_type: campaigns | adGroups | keywords | targets | productAds | negativeKeywords
ids: comma-separated ids from get_live_entities - never typed from memory (max 1000)
confirmed: False = preview only; True = archive
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| entity_typerequired | str | — |
| idsrequired | str | — |
| confirmedoptional | bool | False |
WRITE
batch_update_entities
PREFERRED for multiple updates. Batch update keywords/targets/themes/productAds in ONE API call.
Always use this instead of calling update_keyword_status or update_target_status repeatedly.
Supports up to 1000 items for SP, 100 for SB per API call.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
ad_program: "SP" or "SB"
entity_type: "keywords", "targets", "themes" (SB only), "productAds" (SP only)
updates: JSON string — list of update dicts. Each dict should have:
Keywords: {"keywordId": "...", "state": "paused/enabled", "bid": 1.50}
Targets: {"targetId": "...", "state": "paused/enabled", "bid": 1.50}
Themes: {"themeId": "...", "state": "paused/enabled", "bid": 1.50}
ProductAds: {"adId": "...", "state": "paused/enabled"}
Include campaignId/adGroupId when available.
State and bid are both optional — include whichever you want to change.
confirmed: Must be True to execute
updates_ref: OPTIONAL. Id of a changeset uploaded earlier
(upload_changeset / mcp_push.py --upload). When given, the
rows come from storage and `updates` must be left empty.
This is how a bulk file is pushed without putting the whole
payload in the conversation.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| ad_programrequired | str | — |
| entity_typerequired | str | — |
| updatesoptional | str | None |
| confirmedoptional | bool | False |
| updates_refoptional | str | None |
WRITE
create_ad_group
CREATE one new ad group inside an EXISTING campaign (SP or SD). Preview first (confirmed=False), show the
user, then the same arguments with confirmed=True.
Use when: the user wants a new ad group in a campaign that already exists (for a new campaign use
create_campaign - it makes the first ad group itself). Do not use for SB (not supported).
Returns: the new adGroupId. Next: add_keywords_targets / add_product_ads with that adGroupId.
Args:
client_id: exact name from get_clients
marketplace: US, CA, UK, IN, ...
ad_program: SP or SD
campaign_id: fetch it with get_live_entities(entity_type="campaigns") - never type it
name: ad group name
default_bid: default bid in the account currency (e.g. 0.75)
state: ENABLED or PAUSED
confirmed: False = preview only; True = create
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| ad_programrequired | str | — |
| campaign_idrequired | str | — |
| namerequired | str | — |
| default_bidrequired | float | — |
| stateoptional | str | 'ENABLED' |
| confirmedoptional | bool | False |
WRITE
delete_rule
DELETE a rule. Past runs and their receipts are kept.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
name: rule name
confirmed: must be True
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| namerequired | str | — |
| confirmedoptional | bool | False |
WRITE
delete_rule_profile
DELETE a rule profile. Refused while any rule still follows it, and the
refusal names those rules.
Args:
name: profile name
confirmed: must be True
| Parameter | Type | Default |
|---|---|---|
| namerequired | str | — |
| confirmedoptional | bool | False |
READ
get_account_scorecard
The weekly account scorecard (the team's "Planned template"): per week Spend, Ad Sales, Total Sales, order items,
Sessions, ACOS, TACOS, CPC, CVR, CTR, Organic %, stock weeks (total FBA inventory / the week's units), SKU counts
(inventory > 5, 80% of spend, zero-spend SKUs), OOS SKUs (> 1% of 30-day revenue), zero-sale spend of ENABLED
targets, Auto / Phrase / Exact / Broad / ASIN-Category and SP / SB / SD spend share + ROAS with the amounts.
Same numbers as the Scorecard page and workbook. CA stock columns are blank (North America pooled stock).
Weeks are Monday..Sunday. Finished weeks come from the console's cache; a week that is not built yet is built on
the spot (a few seconds). The current week is week-to-date.
Args:
client_id: exact client name from get_clients
marketplace: US, CA, UK, IN ...
weeks: how many weeks back from the last full week (1-8)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| weeksoptional | int | 4 |
READ
get_category_scorecard
The weekly scorecard for ONE account split by product category: per category the week, the L2W and the L4W
weekly average of Spend, Ad Sales, Total Sales, order items, Sessions, ACOS, TACOS, CPC, CVR, CTR, Organic %,
stock weeks, total inventory, SKU counts (inventory > 5, 80% of spend, zero-spend SKUs), OOS SKUs (> 1% of
30-day revenue) and SP / SD spend share + ROAS. Categories come from the account's Category workbook (weekly
report); ASINs it does not list are "Uncategorised". Built on request (about 10-30 s), never scheduled.
Args:
client_id: exact client name from get_clients
marketplace: US, CA, UK, IN ...
week_start: any date in the week wanted (YYYY-MM-DD); default = the last full week (Monday..Sunday)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| week_startoptional | str | '' |
READ
get_client_facts
Everything the console knows about ONE client account, in plain facts:
services on/off, whether our Amazon Ads and Seller Central access works,
which data arrived today and yesterday (keywords, campaigns, product ads,
search terms, SB/SD, sales, MIS row, daily report), when the daily report,
MIS image and weekly report were last sent and to how many recipients,
budget schedule state, automation rules and their last runs, product page
scraping coverage, the jobs that serve it (and whether its last run included
this account), and open alerts.
Use it for any "why / did / when" question about a client's pipelines.
Args:
client_id: the client's name (any spelling used anywhere)
marketplace: 2-letter country code (needed when the client sells in several)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | None |
READ
get_job_status
Every scheduled Amazon job (data pulls, daily/weekly/monthly reports, MIS
chain, bid and budget automations, the product page scraper, other teams'
pipelines): where it runs, when, its real last result and next run. With
a job name or key: its last runs and which accounts failed in the last one.
Team only.
Args:
job: optional job key or title, e.g. "daily_report_mail" or "MIS - build daily MIS table"
| Parameter | Type | Default |
|---|---|---|
| joboptional | str | None |
READ
get_live_entities
v39: read campaigns / ad groups / keywords / targets / product ads LIVE from the
Amazon Ads API - no snapshot lag. Read-only.
Every other entity tool (get_keyword_entities, get_campaign metadata, stage_changes
re-fetch) reads the 03:30 daily snapshot, so a campaign created today, or one the
snapshot job skipped, has no resolvable ids until tomorrow. Use THIS tool when:
- you just created something and need its ids (campaign -> ad groups -> targets)
- ids from the performance tables are missing from get_keyword_entities (ticket #72)
- you need auto-targeting groups (close-match / loose-match / substitutes /
complements) to pause some of them right after creating an AUTO campaign
entity_type by program:
SP: campaigns | adGroups | keywords | targets | productAds | negativeKeywords
SB: campaigns | adGroups | ads | keywords | targets
SD: campaigns | adGroups | targets | productAds
Filters: campaign_id / ad_group_id (single or comma-separated), state
(ENABLED default, PAUSED, ARCHIVED, or ALL). Rows come back exactly as Amazon
returns them (camelCase ids as strings for SP).
Rows are capped for context; `summary` totals are exact over ALL rows.
Empty result = Amazon has nothing matching, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
ad_program: SP, SB or SD
entity_type: see above
campaign_id: one id or a comma-separated list
ad_group_id: one id or a comma-separated list
state: ENABLED | PAUSED | ARCHIVED | ALL
limit: max rows to fetch from Amazon (default 1000, hard cap 5000)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| ad_programoptional | str | 'SP' |
| entity_typeoptional | str | 'campaigns' |
| campaign_idoptional | str | None |
| ad_group_idoptional | str | None |
| stateoptional | str | 'ENABLED' |
| limitoptional | int | 1000 |
READ
get_ops_overview
The whole Amazon operation right now, as measured by the operations console:
open problems (alerts), jobs that failed or missed their slot, which data
arrived today per dataset, MIS images sent today, last night's product page
scraper, new client connections waiting, dead tokens, the runners, whether
automation and budgets are switched on. Use it for "is everything fine
today?", "what is broken?", "did the pipelines run?".
Team only.
No inputs — call it directly.
READ
get_result
READ a page of a result that was too big to return in one answer.
When compact mode caps a reply it parks the WHOLE result under a short
handle and puts that handle in the reply as `result_ref`. This reads it
back a page at a time, in the order the capped reply ranked it - so row 0
here is the row the cap kept first, and the rows past the cap follow.
Use this instead of re-running a heavy query to see row 201 onwards.
Results are kept for MCP_RESULT_TTL_DAYS days (default 7).
Args:
result_ref: the handle from a capped reply, like rs_0123456789
limit: rows per page (default 200, max 1000)
offset: row to start at, 0 based
columns: optional comma separated subset, e.g. "asin,cost,sales"
| Parameter | Type | Default |
|---|---|---|
| result_refrequired | str | — |
| limitoptional | int | 200 |
| offsetoptional | int | 0 |
| columnsoptional | str | None |
READ
get_rule
READ one rule in full, including what it will ACTUALLY run with after its
profile and this seller's overrides are combined.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
name: rule name
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| namerequired | str | — |
READ
get_rules_status
START HERE for rule sets. Shows every switch that decides whether a rule can
run or push, its current value and who may change it; your own settings; how
many rules you can see per seller and per workflow; and runs waiting for you.
A rule pushes to Amazon only when ALL of these say yes:
rules_enabled (admin) -> rules_auto_enabled (admin, for automatic pushes)
-> the rule is enabled -> its mode, grant expiry and window
-> the call passed apply_now=True and confirmed=True
Empty result = no matching data, not an outage.
No inputs — call it directly.
READ
get_run
READ one rule run in full: the plan, the exact params and caps it ran with,
the profile version, what was skipped and why, the switches at the time, the
changeset ids, and the push receipt. This is the record. An agent's closing
sentence is not.
Args:
run_id: from run_rule or run_rules
| Parameter | Type | Default |
|---|---|---|
| run_idrequired | str | — |
READ
get_started
START HERE. How to use this server safely: which tool for which question, the preview -> confirm
rule for changes, how fresh each data source is, and the most common mistakes.
Args:
topic: "" for the short guide, or one of workflows, tools, changes, budgets, rules, data, mistakes, amc,
routine (the 9-step daily routine -> tools), sb_video (SB video campaigns), all
| Parameter | Type | Default |
|---|---|---|
| topicoptional | str | '' |
READ
list_audiences
The audiences this account can BID-BOOST on in Sponsored Products (AMC rule-based / lookalike audiences and
Amazon audiences made available to sponsored ads). Read-only. v76, admin switch "AMC audience bid boosting".
Bid boosts apply to SP campaigns only (Amazon's API); Sponsored Display audience TARGETING is a target
expression, not this.
Args:
client_id: exact client name from get_clients
marketplace: US, CA, UK, IN ...
search: part of an audience name (optional)
limit: max audiences (default 200)
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
| searchoptional | str | '' |
| limitoptional | int | 200 |
READ
list_rule_profiles
LIST the rule profiles you can use: yours and every shared one. A profile is
a method written once (template + thresholds + caps) that many sellers' rules
follow, each adding only what differs for that seller.
Empty result = no matching data, not an outage.
Args:
template: only profiles of this template (optional)
| Parameter | Type | Default |
|---|---|---|
| templateoptional | str | None |
READ
list_rule_templates
LIST the rule templates a rule or profile can be built from, with every
parameter, its default and what it means. See get_rules_status for switches.
Empty result = no matching data, not an outage.
No inputs — call it directly.
READ
list_rules
LIST rule sets across every seller you can access. Filter by seller, by
marketplace or by workflow. Omit everything to see all of yours.
Empty result = no matching data, not an outage.
Args:
client_id: one seller (optional)
marketplace: US, CA, UK, IN, etc. (optional)
workflow: a workflow label, e.g. "daily-pause" (optional)
| Parameter | Type | Default |
|---|---|---|
| client_idoptional | str | None |
| marketplaceoptional | str | None |
| workflowoptional | str | None |
READ
list_runs
LIST recent rule runs across every seller you can access: what each planned,
what it pushed, who approved it.
Empty result = no matching data, not an outage.
Args:
client_id: Client identifier (optional)
marketplace: US, CA, UK, IN, etc. (optional)
name: rule name (optional)
days: how far back (default 7)
limit: max runs (default 25)
status: awaiting_approval | applied | rejected | parked_after_hours |
no_matches | failed
| Parameter | Type | Default |
|---|---|---|
| client_idoptional | str | None |
| marketplaceoptional | str | None |
| nameoptional | str | None |
| daysoptional | int | 7 |
| limitoptional | int | 25 |
| statusoptional | str | None |
READ
official_read
Run ONE read tool of Amazon's official Ads MCP for this client (see official_tools for names). The
account ids in the arguments must be this client's own; profileId is filled in when missing. Billing
tools are admin only. Change tools are refused.
Args:
client_id: Client identifier (from get_clients)
marketplace: US, CA, UK, IN, etc.
tool: exact official tool name from official_tools
arguments_json: the tool's arguments as a JSON object
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| toolrequired | str | — |
| arguments_jsonoptional | str | '{}' |
READ
official_tools
List the READ tools of Amazon's official Ads MCP for this client's region (reporting, AMC, account
info...). Use official_read to run one. Change tools of the official server are not available here -
use this server's own change tools (preview -> confirm, audited).
Args:
client_id: Client identifier (from get_clients)
marketplace: US, CA, UK, IN, etc.
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplaceoptional | str | 'US' |
WRITE
reject_rule_profile
ADMIN: reject a method someone wrote. It stays saved so they can fix it, but
no rule can run it.
Args:
name: profile name
reason: what to change, shown to whoever wrote it
confirmed: must be True
| Parameter | Type | Default |
|---|---|---|
| namerequired | str | — |
| reasonoptional | str | '' |
| confirmedoptional | bool | False |
WRITE
reject_run
REJECT a waiting rule run. Nothing is pushed, and its stored changesets are
deleted straight away rather than left to expire.
Args:
run_id: from run_rule or run_rules
reason: free text, stored with the run
| Parameter | Type | Default |
|---|---|---|
| run_idrequired | str | — |
| reasonoptional | str | '' |
WRITE
run_rule
RUN one rule. Builds the plan server-side and answers with counts, money and
five sample rows. The matched rows go to a changeset, never into this reply.
Pushes only when every switch agrees (see get_rules_status). Otherwise the
plan waits for approve_run, and `why_not_pushed` names each reason.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
name: rule name
apply_now: ask to push in the same call (auto-mode rules only)
confirmed: must be True alongside apply_now
verify_live: read live state from Amazon before acting (default True)
write_path: "direct" or "official" for this run only
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| namerequired | str | — |
| apply_nowoptional | bool | False |
| confirmedoptional | bool | False |
| verify_liveoptional | bool | True |
| write_pathoptional | str | None |
WRITE
run_rules
RUN many rules in one call: a whole workflow across every seller you can
access, or every rule of one seller. One compact line per rule comes back;
use get_run(run_id) for the full plan of any one of them.
Inside one call, an entity a rule already acted on for a seller is left
alone by that seller's later rules, so two methods never act twice.
Give workflow, client_id, or both. Running everything with no filter is
refused on purpose.
Args:
workflow: workflow label, e.g. "daily-pause"
client_id: one seller (optional)
marketplace: US, CA, UK, IN, etc. (optional)
apply_now / confirmed: as run_rule, applied to every rule
verify_live: as run_rule
write_path: "direct" or "official" for these runs only
max_seconds: stop starting new rules after this long and report what is
left, so a 17 seller sweep can never outrun the caller's
timeout (default 45, max 600)
skip_ran_within_minutes: skip rules that already ran this recently. Use
it to RESUME a sweep that stopped on its time budget
without planning the same rules twice.
| Parameter | Type | Default |
|---|---|---|
| workflowoptional | str | None |
| client_idoptional | str | None |
| marketplaceoptional | str | None |
| apply_nowoptional | bool | False |
| confirmedoptional | bool | False |
| verify_liveoptional | bool | True |
| write_pathoptional | str | None |
| max_secondsoptional | int | 45 |
| skip_ran_within_minutesoptional | int | 0 |
WRITE
save_rule
CREATE or UPDATE a rule for one seller. Saving never changes anything on
Amazon. Every save bumps the rule version.
Two ways to write a rule:
standalone: template + params + caps, all on this rule
from a profile: profile="kw-pause-standard" plus ONLY what differs for this
seller in params / caps (e.g. {"spend_floor": 300} for INR).
Change the profile later and this rule follows.
Args:
client_id: Client identifier
marketplace: US, CA, UK, IN, etc.
name: lowercase name, e.g. "kw-pause"
template: see list_rule_templates. Optional when a profile is given.
params: JSON object. Standalone: thresholds. With a profile: overrides only.
caps: JSON object. max_rows, cooldown_days, max_spend_impact, bid_floor,
bid_ceiling, max_bid_change_pct. With a profile: overrides only.
mode: "ask" (default) or "auto"
auto_until: YYYY-MM-DD. Required for auto; automation always expires.
window_hours: "09:00-19:00". Required for auto. Outside it a run waits.
enabled: omit to keep the current state on an edit
workflow: label that groups rules across sellers, e.g. "daily-pause"
profile: follow a saved method. "" detaches the rule from its profile.
confirmed: must be True to save
| Parameter | Type | Default |
|---|---|---|
| client_idrequired | str | — |
| marketplacerequired | str | — |
| namerequired | str | — |
| templateoptional | str | None |
| paramsoptional | str | None |
| capsoptional | str | None |
| modeoptional | str | 'ask' |
| auto_untiloptional | str | None |
| window_hoursoptional | str | None |
| enabledoptional | bool | None |
| workflowoptional | str | None |
| profileoptional | str | None |
| confirmedoptional | bool | False |
WRITE
save_rule_profile
CREATE or UPDATE a rule profile: a method many sellers' rules can follow.
Editing a profile changes every rule that follows it, from their next run,
and the run records the profile version it used.
Writing your own method (template="custom_rule"): params carries what it
reads, what it does and the conditions, for example
{"source": "search_terms", "action": "add_negative",
"where": [["clicks", ">=", 15], ["orders", "=", 0]]}
list_rule_templates -> write_your_own has every allowed field, operator and
action, and how_to_write_one has the whole sequence. A method you write is
saved WAITING: an admin approves it once, and then every rule that follows
it can run. Editing an approved one sends it back to them.
Args:
name: lowercase, e.g. "kw-pause-standard"
template: see list_rule_templates. "custom_rule" is the one you write.
params: JSON object of the thresholds this method sets
caps: JSON object of the caps this method sets
shared: True lets other people's rules follow it (admins only)
description: one line on what the method is for
confirmed: must be True
| Parameter | Type | Default |
|---|---|---|
| namerequired | str | — |
| templaterequired | str | — |
| paramsoptional | str | None |
| capsoptional | str | None |
| sharedoptional | bool | None |
| descriptionoptional | str | None |
| confirmedoptional | bool | False |
WRITE
set_rules_switch
ADMIN: flip one switch on the rules switchboard. Takes effect within 30
seconds, no restart. Every change is logged with who made it.
rules_enabled on | off master switch for running rules
rules_auto_enabled on | off automation kill switch
upload_policy write_users | admins_only
plan_max_age_hours a number older plans must be re-run, not approved
Args:
switch: one of the names above
value: the new value
confirmed: must be True
| Parameter | Type | Default |
|---|---|---|
| switchrequired | str | — |
| valuerequired | str | — |
| confirmedoptional | bool | False |
⚠
WRITE tools change real campaigns. They are staged and confirmed where possible, need edit access, and every push is recorded in the change history with your name on it.