AdWhispr gives Claude competitor ad intelligence and campaign execution.
Research: ingest any brand's entire public ad library from Meta and TikTok. Find verified competitors actually running ads in your niche right now, search ads semantically by concept ("social proof", "founder story"), pull a brand's TikTok ads with the proven winners first, and get real Google Keyword Planner data for any topic.
Briefs: generate a full competitive brief on any brand longevity curve, top hooks, longest-running winners, format mix, and a positioning verdict, with a downloadable PDF.
Execution: connect your own Meta, Google, or TikTok ad account once via OAuth, then launch complete campaigns from chat, Google Search, Performance Max, TikTok video, and Meta single-image or carousel ads from your own creative library. Every campaign is created paused with a preview-and-confirm step, so nothing spends until you explicitly resume it. Read performance, adjust budgets, and pause or resume campaigns conversationally.
Free tier included, no API keys to manage. Try: "Who has the best ads in my niche?" or "Launch a Google Search campaign for my store at $20/day."
Protocol
MCP 2025-11-25
Server version
1.0.0
Supports
Tools
Resources
Overall score
B
Overall quality score: 82 out of 10082/100
Server metadata
4 of 8 fields50/1004 / 8 pts
Identity, discovery, and usage metadata advertised during the MCP handshake.
AdWhispr is a competitor-ad research and campaign execution platform. Use this short guide to choose tools correctly.
Common workflows:
★ Find the best competitor ads in the user's space (the most common request)
• When the user asks "who has the best ads in my space", "show me winning ads for my product/niche", "who are my competitors", or anything similar WITHOUT naming a specific competitor: call get_my_brand FIRST to learn their product/niche. If nothing is saved, ask for their product page URL. The moment they reveal their business in ANY form — a link, their website, or just a plain description ("I sell X", "I run a Y", "we make Z"), even in passing — call save_my_brand to persist it (it takes a URL or a description), then continue researching without re-asking.
• Then call find_competitors (it uses the saved brand automatically) and present its VERIFIED advertisers — brands checked, seconds ago, to be running ads right now, ranked by active-ad count. Keep its three buckets separate: lead with the verified advertisers, mention the "checked, not currently advertising" ones honestly, and never present the "couldn't verify" names as advertisers. Do NOT brainstorm competitor names from your own knowledge — your guesses may not advertise at all, which is the exact failure this tool prevents. Only if find_competitors returns nothing may you name competitors yourself, and if you do, say those names are unverified.
• For a verified brand already in AdWhispr, use its brand ID with get_brand_ads (sortBy:longevity) to surface the proven winners. For a verified brand not tracked yet, offer to add_brand it (pass the pageId find_competitors gave you) and set the expectation that its ads take a minute or two to load. TWO ID TYPES, never mix them: a brandId is a UUID and is what get_brand_ads/get_brand_stats/search_ads take; a pageId is numeric and works ONLY in add_brand. Passing a pageId as brandId fails validation. get_brand_ads defaults to ACTIVE ads (running N
Protocol
Pass100/10016 / 16 pts
Connection, authentication, and protocol compatibility.
How to fix: For tools that render a UI resource, add openai/toolInvocation with string fields invoking and invoked (present-tense labels shown while the tool runs and after it finishes, e.g. "Searching…" / "Searched").
All view resources are readable and use ui:// with a supported MCP Apps HTML MIME type
View resources declare a domain
1 ChatGPT UI domain issue(s) found
How to fix: For ChatGPT submission, set one exact HTTPS origin such as "https://app.example.com" on every view via _meta.ui.domain (or openai/widgetDomain). Paths are not valid and all views in one app must share the origin.
How to fix: Use a ui:// URI and text/html;profile=mcp-app. For mcp-use servers, set the widget description in widgetMetadata; other stacks can use _meta.ui.widgetDescription or the OpenAI compatibility alias.
The title clearly communicates the tool’s action and subject. Keep it concise.
Description92/100
Return the user's OWN saved business/product/niche. Call this FIRST when the user asks to see the best ads 'in my space', 'for my product', 'in my niche', or 'who are my competitors' WITHOUT naming a specific competitor — then use their niche to find and surface the best-performing competitor ads. If nothing is saved, it tells you to ask for their product URL.
Describe the returned information so the agent knows whether it will answer the request.
Inputs100/100
This tool declares no inputs, so argument descriptions are not needed.
No input fields.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "get_my_brand",
"title": "Get My Brand",
"description": "Return the user's OWN saved business/product/niche. Call this FIRST when the user asks to see the best ads 'in my space', 'for my product', 'in my niche', or 'who are my competitors' WITHOUT naming a specific competitor — then use their niche to find and surface the best-performing competitor ads. If nothing is saved, it tells you to ask for their product URL.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {}
},
"annotations": {
"title": "Get My Brand",
"readOnlyHint": true,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description87/100
Save or UPDATE the user's OWN product/business so it persists for competitor research and future clones — no clone required. Call this WHENEVER the user reveals what their business is, in ANY phrasing: a product URL or website, OR just a plain description ('I sell minimalist wallets', 'I run a fitness app', 'we make baby seats', 'my site is example.com') — whether they explicitly ask to save it or just mention it in passing. Accepts a URL (best, we extract details) or a plain-text description. It replaces the saved product, so it also handles switching to a new one. After saving, immediately research the competitors in that space.
Describe the returned information so the agent knows whether it will answer the request.
Inputs75/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
productUrl
The user's product page URL (best — we auto-extract details), OR a plain-text description of what they sell
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "save_my_brand",
"title": "Save My Brand",
"description": "Save or UPDATE the user's OWN product/business so it persists for competitor research and future clones — no clone required. Call this WHENEVER the user reveals what their business is, in ANY phrasing: a product URL or website, OR just a plain description ('I sell minimalist wallets', 'I run a fitness app', 'we make baby seats', 'my site is example.com') — whether they explicitly ask to save it or just mention it in passing. Accepts a URL (best, we extract details) or a plain-text description. It replaces the saved product, so it also handles switching to a new one. After saving, immediately research the competitors in that space.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"productUrl"
],
"properties": {
"productUrl": {
"type": "string",
"description": "The user's product page URL (best — we auto-extract details), OR a plain-text description of what they sell"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Save My Brand",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
Remove the user's saved OWN brand entirely (business, product, website, audience, tone, logo, colors). Use when the user says to clear, remove, reset, forget, or delete their saved brand/profile — NOT for switching to a new one (use save_my_brand for that, which replaces it). After clearing, nothing is saved until they save_my_brand again.
The description explains the capability, when to use it, and what to expect.
Inputs100/100
This tool declares no inputs, so argument descriptions are not needed.
No input fields.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clear_my_brand",
"title": "Clear My Brand",
"description": "Remove the user's saved OWN brand entirely (business, product, website, audience, tone, logo, colors). Use when the user says to clear, remove, reset, forget, or delete their saved brand/profile — NOT for switching to a new one (use save_my_brand for that, which replaces it). After clearing, nothing is saved until they save_my_brand again.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {}
},
"annotations": {
"title": "Clear My Brand",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description93/100
Save a SPECIFIC product (its product-page URL) to the user's catalog — we extract the product's name, description, price and ALL its photos. Video ads the user generates in the AdWhispr web app (https://adwhispr.com/dashboard) about this product then show the REAL product from those photos instead of an AI-invented stand-in. Use for e-commerce users who want ads about a specific product (their store URL /products/... link is ideal). If the user wants to UPLOAD photos instead (no product page, page photos show people, or they ask 'can I upload a photo?'), send them to My Brand > Products (https://adwhispr.com/dashboard/my-brand) — each saved product has an Add photos button there; uploads are person-scanned automatically. The Creative Library (dashboard/creatives) is NOT for product photos — never point there for this. Distinct from save_my_brand (the brand as a whole): one brand, many products. Free.
The description explains the capability, when to use it, and what to expect.
Inputs75/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
productUrl
The product page URL (e.g. https://store.com/products/item) — NOT the site homepage
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "add_product",
"title": "Add a Product",
"description": "Save a SPECIFIC product (its product-page URL) to the user's catalog — we extract the product's name, description, price and ALL its photos. Video ads the user generates in the AdWhispr web app (https://adwhispr.com/dashboard) about this product then show the REAL product from those photos instead of an AI-invented stand-in. Use for e-commerce users who want ads about a specific product (their store URL /products/... link is ideal). If the user wants to UPLOAD photos instead (no product page, page photos show people, or they ask 'can I upload a photo?'), send them to My Brand > Products (https://adwhispr.com/dashboard/my-brand) — each saved product has an Add photos button there; uploads are person-scanned automatically. The Creative Library (dashboard/creatives) is NOT for product photos — never point there for this. Distinct from save_my_brand (the brand as a whole): one brand, many products. Free.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"productUrl"
],
"properties": {
"productUrl": {
"type": "string",
"format": "uri",
"description": "The product page URL (e.g. https://store.com/products/item) — NOT the site homepage"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Add a Product",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description95/100
List the user's saved products (name, price, photo count, productId). Saved products power the video ads the user generates in the AdWhispr web app (https://adwhispr.com/dashboard) — ads about a product feature its REAL photos. Use this to show the user what's saved, or to find the productId for remove_product. Free, read-only.
The description explains the capability, when to use it, and what to expect.
Inputs100/100
This tool declares no inputs, so argument descriptions are not needed.
No input fields.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "list_my_products",
"title": "List My Products",
"description": "List the user's saved products (name, price, photo count, productId). Saved products power the video ads the user generates in the AdWhispr web app (https://adwhispr.com/dashboard) — ads about a product feature its REAL photos. Use this to show the user what's saved, or to find the productId for remove_product. Free, read-only.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {}
},
"annotations": {
"title": "List My Products",
"readOnlyHint": true,
"openWorldHint": false,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description91/100
Delete ONE saved product from the user's catalog by productId (from list_my_products). Use when the user says to remove/delete a product or stops selling it. Does not touch the brand itself (clear_my_brand does that).
Explain mutations, irreversible effects, or prerequisites that matter before calling this tool.
Inputs96/100
Input documentation gives an agent enough context to populate the arguments.
productId
The productId to remove, from list_my_products
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "remove_product",
"title": "Remove a Product",
"description": "Delete ONE saved product from the user's catalog by productId (from list_my_products). Use when the user says to remove/delete a product or stops selling it. Does not touch the brand itself (clear_my_brand does that).",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"productId"
],
"properties": {
"productId": {
"type": "string",
"description": "The productId to remove, from list_my_products"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Remove a Product",
"readOnlyHint": false,
"openWorldHint": false,
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description95/100
Find competitors in the user's space that are VERIFIED to be running ads right now, ranked by how many active ads they have. ALWAYS use this instead of suggesting competitor names from your own knowledge — your guesses may not advertise at all, and this tool checks the live ad library and returns real, just-checked active-ad counts. Uses the user's saved brand automatically (call get_my_brand/save_my_brand first if nothing is saved); pass `niche` only to override (e.g. 'meditation apps in Brazil'). Returns verified advertisers separated from 'checked, not advertising' and 'couldn't verify' — present them exactly that way.
The description explains the capability, when to use it, and what to expect.
Inputs88/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
niche
Optional override for the space to search, e.g. 'meditation apps in Brazil'. Omit to use the user's saved brand.
Clear enough to supply this argument.
limit
Max verified competitors to return (default 5, max 8)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "find_competitors",
"title": "Find Competitors",
"description": "Find competitors in the user's space that are VERIFIED to be running ads right now, ranked by how many active ads they have. ALWAYS use this instead of suggesting competitor names from your own knowledge — your guesses may not advertise at all, and this tool checks the live ad library and returns real, just-checked active-ad counts. Uses the user's saved brand automatically (call get_my_brand/save_my_brand first if nothing is saved); pass `niche` only to override (e.g. 'meditation apps in Brazil'). Returns verified advertisers separated from 'checked, not advertising' and 'couldn't verify' — present them exactly that way.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"limit": {
"type": "integer",
"maximum": 8,
"minimum": 1,
"description": "Max verified competitors to return (default 5, max 8)"
},
"niche": {
"type": "string",
"description": "Optional override for the space to search, e.g. 'meditation apps in Brazil'. Omit to use the user's saved brand."
}
},
"additionalProperties": false
},
"annotations": {
"title": "Find Competitors",
"readOnlyHint": true,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description94/100
Get ads for a specific brand with enrichment data (hooks, formats, tones, performance scores, thumbnails, video links). Renders ad images and videos inline. DEFAULTS to ACTIVE ads (what the competitor is running NOW) — that's what a user wants when they ask for the best/winning ads. Only pass status:'all' or 'inactive' if the user explicitly asks for past/old/all ads. Use search_brands first to find the brand's ID.
The description explains the capability, when to use it, and what to expect.
Inputs93/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
brandId
Brand UUID from search_brands. Optional when brandName is provided.
Clear enough to supply this argument.
brandName
Brand name to fetch ads for (e.g. "Holo") — resolved server-side to the best-matching tracked brand, same ranking as search_brands. Use this to fetch a named brand's ads in a SINGLE call without calling search_brands first.
Clear enough to supply this argument.
status
Which ads to show — 'active' (DEFAULT, currently running), 'inactive' (stopped), or 'all'. Keep the default unless the user explicitly wants past/all ads.
Clear enough to supply this argument.
format
Filter by creative format. Accepts the enum labels (ugc_talking_head, ugc_lifestyle, studio_product, text_overlay, before_after, slideshow, animation, screenshot, meme, carousel) or everyday words for them ("cartoon"/"animated" → animation, "talking head" → ugc_talking_head, "UGC" → both UGC formats, "product shot" → studio_product, "before and after" → before_after).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
mediaType
Filter by media type: 'image' (static image ads) or 'video'. Use this — NOT format — when the user asks for image ads or video ads, so results need no client-side re-filtering.
Clear enough to supply this argument.
limit
Max ads to return (default 20)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "get_brand_ads",
"title": "Get Brand Ads",
"description": "Get ads for a specific brand with enrichment data (hooks, formats, tones, performance scores, thumbnails, video links). Renders ad images and videos inline. DEFAULTS to ACTIVE ads (what the competitor is running NOW) — that's what a user wants when they ask for the best/winning ads. Only pass status:'all' or 'inactive' if the user explicitly asks for past/old/all ads. Use search_brands first to find the brand's ID.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"limit": {
"type": "integer",
"maximum": 50,
"minimum": 1,
"description": "Max ads to return (default 20)"
},
"format": {
"type": "string",
"description": "Filter by creative format. Accepts the enum labels (ugc_talking_head, ugc_lifestyle, studio_product, text_overlay, before_after, slideshow, animation, screenshot, meme, carousel) or everyday words for them (\"cartoon\"/\"animated\" → animation, \"talking head\" → ugc_talking_head, \"UGC\" → both UGC formats, \"product shot\" → studio_product, \"before and after\" → before_after)."
},
"sortBy": {
"enum": [
"longevity",
"performance_score",
"newest",
"estimated_revenue"
],
"type": "string",
"description": "Sort order: longevity (default, longest-running first), performance_score, newest, estimated_revenue"
},
"status": {
"enum": [
"active",
"inactive",
"all"
],
"type": "string",
"description": "Which ads to show — 'active' (DEFAULT, currently running), 'inactive' (stopped), or 'all'. Keep the default unless the user explicitly wants past/all ads."
},
"brandId": {
"type": "string",
"format": "uuid",
"description": "Brand UUID from search_brands. Optional when brandName is provided."
},
"brandName": {
"type": "string",
"description": "Brand name to fetch ads for (e.g. \"Holo\") — resolved server-side to the best-matching tracked brand, same ranking as search_brands. Use this to fetch a named brand's ads in a SINGLE call without calling search_brands first."
},
"mediaType": {
"enum": [
"image",
"video"
],
"type": "string",
"description": "Filter by media type: 'image' (static image ads) or 'video'. Use this — NOT format — when the user asks for image ads or video ads, so results need no client-side re-filtering."
}
},
"additionalProperties": false
},
"annotations": {
"title": "Get Brand Ads",
"readOnlyHint": true,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description85/100
Semantic search across ads using AI embeddings. Find ads by concept (e.g. "before and after transformation", "social proof testimonials"). Style/format words in the query ("cartoon", "talking head", "meme", "product shot") also match the ads' AI-classified creative-format labels directly. Renders matching ads inline. Requires a brandId.
Describe the returned information so the agent knows whether it will answer the request.
Inputs75/100
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
query
Search query describing what kind of ads to find
Clear enough to supply this argument.
brandId
Brand UUID to search within
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
limit
Max results (default 10)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
The title clearly communicates the tool’s action and subject. Keep it concise.
Description96/100
Start tracking a new brand. Finds the brand in the ad library, creates it, and begins ingesting their ads. If find_competitors gave you a pageId for this brand, pass it as pageId so the exact verified page is ingested (avoids a wrong name match); keep name for display. DISCIPLINE: daily adds are capped (3/day free) and deleting a brand does NOT refund the counter — add ONE brand per call, ONLY a brand the user asked for or explicitly agreed to, and NEVER batch-add extras "for comparison" on your own. The response reports remaining daily adds; relay that when it hits 1.
Describe the returned information so the agent knows whether it will answer the request.
Inputs92/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
name
Brand name to search for and add (e.g. "Allbirds")
Clear enough to supply this argument.
platform
Platform to search (default: meta)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
pageId
Exact Facebook page ID to ingest (e.g. from find_competitors). When provided, the name search is skipped so the right page is tracked.
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "add_brand",
"title": "Add Brand",
"description": "Start tracking a new brand. Finds the brand in the ad library, creates it, and begins ingesting their ads. If find_competitors gave you a pageId for this brand, pass it as pageId so the exact verified page is ingested (avoids a wrong name match); keep name for display. DISCIPLINE: daily adds are capped (3/day free) and deleting a brand does NOT refund the counter — add ONE brand per call, ONLY a brand the user asked for or explicitly agreed to, and NEVER batch-add extras \"for comparison\" on your own. The response reports remaining daily adds; relay that when it hits 1.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"name"
],
"properties": {
"name": {
"type": "string",
"description": "Brand name to search for and add (e.g. \"Allbirds\")"
},
"pageId": {
"type": "string",
"description": "Exact Facebook page ID to ingest (e.g. from find_competitors). When provided, the name search is skipped so the right page is tracked."
},
"platform": {
"enum": [
"meta",
"tiktok"
],
"type": "string",
"description": "Platform to search (default: meta)"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Add Brand",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description99/100
Generate a full, exportable competitive brief on a brand's ad strategy. Returns formatted Markdown (render it for the user as-is) that LEADS with AdWhispr's derived intelligence — the creative-longevity curve (how many ads are proven 31+ day winners vs fresh tests), engagement-verified reach (real scraped likes/comments/shares where measured), and creative-iteration rate (new creatives launched per month) — then top hooks, the longest-running winners, format mix, and an opinionated positioning verdict. Includes a one-click PDF download link. Use this when the user asks for a 'brief', 'competitive brief', 'full breakdown', 'strategy brief', 'report on', or 'analyze X's whole strategy'. Use search_brands first to get the brandId. Pro feature — free users get an upgrade prompt instead. Takes ~60 seconds.
The description explains the capability, when to use it, and what to expect.
Inputs97/100
Input documentation gives an agent enough context to populate the arguments.
brandId
Brand UUID from search_brands
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "generate_brief",
"title": "Generate Competitive Brief",
"description": "Generate a full, exportable competitive brief on a brand's ad strategy. Returns formatted Markdown (render it for the user as-is) that LEADS with AdWhispr's derived intelligence — the creative-longevity curve (how many ads are proven 31+ day winners vs fresh tests), engagement-verified reach (real scraped likes/comments/shares where measured), and creative-iteration rate (new creatives launched per month) — then top hooks, the longest-running winners, format mix, and an opinionated positioning verdict. Includes a one-click PDF download link. Use this when the user asks for a 'brief', 'competitive brief', 'full breakdown', 'strategy brief', 'report on', or 'analyze X's whole strategy'. Use search_brands first to get the brandId. Pro feature — free users get an upgrade prompt instead. Takes ~60 seconds.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"brandId"
],
"properties": {
"brandId": {
"type": "string",
"format": "uuid",
"description": "Brand UUID from search_brands"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Generate Competitive Brief",
"readOnlyHint": true,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description99/100
Research Google Search keywords for any topic, product, or seed terms. Returns real Google Keyword Planner data — average monthly search volume, top-of-page CPC (cost-per-click) ranges, and competition level — to help the user plan their own advertising. Use this when the user asks 'what keywords should I target', 'how much does X cost per click', 'search volume for Y', or 'give me keyword ideas around Z'. Pass one or more seed keywords/topics. Optionally set country (default US) and language (default en).
The description explains the capability, when to use it, and what to expect.
Inputs81/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
seedKeywords
One or more seed keywords or topics (e.g. ["meal prep delivery", "healthy meal kits"])
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
country
2-letter ISO country code for geo targeting (default US). Every major market worldwide is supported, e.g. US, GB, DE, FR, ES, IT, NL, PL, HU, RO, UA, TR, AE, SA, EG, BR, MX, IN, ID, JP, KR.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
language
2-letter ISO language code (default en). 30+ languages supported, e.g. en, es, fr, de, it, pt, nl, pl, ru, uk, ro, cs, hu, tr, ar, hi, id, vi, th, ja, ko, zh. Match the language to the country for accurate local volume.
Clear enough to supply this argument.
limit
Max keyword ideas to return (default 30)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "research_keywords",
"title": "Research Keywords",
"description": "Research Google Search keywords for any topic, product, or seed terms. Returns real Google Keyword Planner data — average monthly search volume, top-of-page CPC (cost-per-click) ranges, and competition level — to help the user plan their own advertising. Use this when the user asks 'what keywords should I target', 'how much does X cost per click', 'search volume for Y', or 'give me keyword ideas around Z'. Pass one or more seed keywords/topics. Optionally set country (default US) and language (default en).",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"seedKeywords"
],
"properties": {
"limit": {
"type": "integer",
"maximum": 50,
"minimum": 1,
"description": "Max keyword ideas to return (default 30)"
},
"country": {
"type": "string",
"description": "2-letter ISO country code for geo targeting (default US). Every major market worldwide is supported, e.g. US, GB, DE, FR, ES, IT, NL, PL, HU, RO, UA, TR, AE, SA, EG, BR, MX, IN, ID, JP, KR."
},
"language": {
"type": "string",
"description": "2-letter ISO language code (default en). 30+ languages supported, e.g. en, es, fr, de, it, pt, nl, pl, ru, uk, ro, cs, hu, tr, ar, hi, id, vi, th, ja, ko, zh. Match the language to the country for accurate local volume."
},
"seedKeywords": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"description": "One or more seed keywords or topics (e.g. [\"meal prep delivery\", \"healthy meal kits\"])"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Research Keywords",
"readOnlyHint": true,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description97/100
Given a competitor's URL or domain, return the keywords Google associates with that page's CONTENT — a content/positioning proxy for what that site is about and could target. IMPORTANT: this is NOT the competitor's actual live bids (Google does not expose those); present it honestly as 'keywords this site is about / could target'. Each keyword includes search volume, CPC range, and competition. Use when the user asks 'what keywords is competitor.com about', 'what could X be bidding on', or 'analyze this domain's keyword themes'.
The description explains the capability, when to use it, and what to expect.
Inputs88/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
competitorUrl
Competitor URL or domain (e.g. 'https://kiavi.com' or 'kiavi.com')
Clear enough to supply this argument.
country
2-letter country code for geo targeting (default US)
Clear enough to supply this argument.
language
2-letter language code (default en)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
limit
Max keyword ideas to return (default 30)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "research_competitor_keywords",
"title": "Research Competitor Keywords",
"description": "Given a competitor's URL or domain, return the keywords Google associates with that page's CONTENT — a content/positioning proxy for what that site is about and could target. IMPORTANT: this is NOT the competitor's actual live bids (Google does not expose those); present it honestly as 'keywords this site is about / could target'. Each keyword includes search volume, CPC range, and competition. Use when the user asks 'what keywords is competitor.com about', 'what could X be bidding on', or 'analyze this domain's keyword themes'.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"competitorUrl"
],
"properties": {
"limit": {
"type": "integer",
"maximum": 50,
"minimum": 1,
"description": "Max keyword ideas to return (default 30)"
},
"country": {
"type": "string",
"description": "2-letter country code for geo targeting (default US)"
},
"language": {
"type": "string",
"description": "2-letter language code (default en)"
},
"competitorUrl": {
"type": "string",
"description": "Competitor URL or domain (e.g. 'https://kiavi.com' or 'kiavi.com')"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Research Competitor Keywords",
"readOnlyHint": true,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
TWO modes. DEFAULT (content:'ads'): a competitor's live TikTok ADS from TikTok's public ad-transparency library (Commercial Content Library, last 90 days across EEA), sorted by longevity so the longest-running proven winners surface first; each ad returns video, cover, dates, days-running, estimated audience, and the videos play inline. Ads limits: EU-FOCUSED (brands not advertising in the EEA have little/no data) and NO spend/impressions (use longevity); the library has many fragmented accounts per brand, so the result lists alternates with their advertiserId — re-call with advertiserId if the auto-pick is wrong. ORGANIC mode (content:'organic'): a creator's OWN posted TikToks (not ads) with real views, likes, comments, shares, saves and captions, sorted by 'popular' or 'latest' — pass the @handle. Organic works for ANY public TikTok account worldwide (not EU-limited); the top few videos play inline and the rest render as cover-thumbnail cards that click through to TikTok. Use ads mode for 'what TikTok ads is X running'; use organic mode for 'show me X's TikToks / their latest/top TikTok videos'. Clone any winner with clone_tiktok_ad (ads) or clone_video_ad with the post link (organic).
The description explains the capability, when to use it, and what to expect.
Inputs88/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
advertiser
The competitor brand/advertiser name (ads mode) OR the creator's TikTok @handle (organic mode), e.g. 'Gymshark' or '@gymshark'
Clear enough to supply this argument.
content
'ads' (default) = paid ad-library ads; 'organic' = the creator's own posted TikToks
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "research_tiktok_ads",
"title": "Research Competitor TikTok Ads + Content",
"description": "TWO modes. DEFAULT (content:'ads'): a competitor's live TikTok ADS from TikTok's public ad-transparency library (Commercial Content Library, last 90 days across EEA), sorted by longevity so the longest-running proven winners surface first; each ad returns video, cover, dates, days-running, estimated audience, and the videos play inline. Ads limits: EU-FOCUSED (brands not advertising in the EEA have little/no data) and NO spend/impressions (use longevity); the library has many fragmented accounts per brand, so the result lists alternates with their advertiserId — re-call with advertiserId if the auto-pick is wrong. ORGANIC mode (content:'organic'): a creator's OWN posted TikToks (not ads) with real views, likes, comments, shares, saves and captions, sorted by 'popular' or 'latest' — pass the @handle. Organic works for ANY public TikTok account worldwide (not EU-limited); the top few videos play inline and the rest render as cover-thumbnail cards that click through to TikTok. Use ads mode for 'what TikTok ads is X running'; use organic mode for 'show me X's TikToks / their latest/top TikTok videos'. Clone any winner with clone_tiktok_ad (ads) or clone_video_ad with the post link (organic).",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"advertiser"
],
"properties": {
"sort": {
"enum": [
"popular",
"latest"
],
"type": "string",
"description": "Organic mode only: 'popular' = TikTok's most-popular ranking (default), 'latest' = newest first"
},
"limit": {
"type": "integer",
"maximum": 50,
"minimum": 1,
"description": "Max results (default 15 ads / 12 organic videos)"
},
"content": {
"enum": [
"ads",
"organic"
],
"type": "string",
"description": "'ads' (default) = paid ad-library ads; 'organic' = the creator's own posted TikToks"
},
"country": {
"type": "string",
"description": "Ads mode only: EEA country code to scope results (e.g. DE, FR, ES); defaults to ALL countries"
},
"advertiser": {
"type": "string",
"description": "The competitor brand/advertiser name (ads mode) OR the creator's TikTok @handle (organic mode), e.g. 'Gymshark' or '@gymshark'"
},
"advertiserId": {
"type": "string",
"description": "Ads mode only: target a SPECIFIC advertiser account id (from a previous result's candidate list) instead of auto-picking"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Research Competitor TikTok Ads + Content",
"readOnlyHint": true,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description99/100
PRODUCES: a SHOOT-READY SCRIPT BRIEF the user films themselves — NOT a finished video and NOT an image. It samples real frames from the competitor's TikTok ad, analyzes the hook, structure, pacing, and product moments, then writes a shot-by-shot script that keeps what's working but swaps in the user's product and voice. COST: free (no credit; text output). Get the advertiser name + adId from research_tiktok_ads. Pass productUrl (the user's product page) to tailor it if their brand isn't set up yet. After shooting, the user uploads the video and launch_tiktok_campaign takes it live (paused first). If the user instead wants a finished video generated for them, that happens in the AdWhispr web app (https://adwhispr.com/dashboard) — finished videos land in their Creative Library, launchable here via launch_tiktok_campaign.
The description explains the capability, when to use it, and what to expect.
Inputs97/100
Input documentation gives an agent enough context to populate the arguments.
advertiser
Competitor advertiser name (same as used in research_tiktok_ads, e.g. 'Gymshark')
Clear enough to supply this argument.
adId
The ad id to clone, from a research_tiktok_ads result
Clear enough to supply this argument.
productUrl
The user's product page URL, to tailor the script (used if their brand isn't saved yet)
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "clone_tiktok_ad",
"title": "Clone Competitor TikTok Ad",
"description": "PRODUCES: a SHOOT-READY SCRIPT BRIEF the user films themselves — NOT a finished video and NOT an image. It samples real frames from the competitor's TikTok ad, analyzes the hook, structure, pacing, and product moments, then writes a shot-by-shot script that keeps what's working but swaps in the user's product and voice. COST: free (no credit; text output). Get the advertiser name + adId from research_tiktok_ads. Pass productUrl (the user's product page) to tailor it if their brand isn't set up yet. After shooting, the user uploads the video and launch_tiktok_campaign takes it live (paused first). If the user instead wants a finished video generated for them, that happens in the AdWhispr web app (https://adwhispr.com/dashboard) — finished videos land in their Creative Library, launchable here via launch_tiktok_campaign.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"advertiser",
"adId"
],
"properties": {
"adId": {
"type": "string",
"description": "The ad id to clone, from a research_tiktok_ads result"
},
"advertiser": {
"type": "string",
"description": "Competitor advertiser name (same as used in research_tiktok_ads, e.g. 'Gymshark')"
},
"productUrl": {
"type": "string",
"description": "The user's product page URL, to tailor the script (used if their brand isn't saved yet)"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Clone Competitor TikTok Ad",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description96/100
Connect one of the user's OWN ad accounts so AdWhispr can launch and manage campaigns in it. Supports Meta (Facebook/Instagram), Google Ads, and TikTok Ads today; LinkedIn is coming. All platforms return a browser link the user opens to sign in and grant access on the platform's own consent screen (accountId is ignored). Connecting an ad account and listing connected accounts are free on every plan — always offer connecting. On free accounts, the other account tools (performance analysis, managing campaigns, launching) may return a one-click upgrade link instead of running; relay it when they do.
The description explains the capability, when to use it, and what to expect.
Inputs88/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
platform
Ad platform — "meta", "google", and "tiktok" are supported today; "linkedin" is coming
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
accountId
Not needed — connection happens via the returned sign-in link. Omit this.
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "connect_ad_account",
"title": "Connect Ad Account",
"description": "Connect one of the user's OWN ad accounts so AdWhispr can launch and manage campaigns in it. Supports Meta (Facebook/Instagram), Google Ads, and TikTok Ads today; LinkedIn is coming. All platforms return a browser link the user opens to sign in and grant access on the platform's own consent screen (accountId is ignored). Connecting an ad account and listing connected accounts are free on every plan — always offer connecting. On free accounts, the other account tools (performance analysis, managing campaigns, launching) may return a one-click upgrade link instead of running; relay it when they do.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"platform"
],
"properties": {
"platform": {
"enum": [
"meta",
"google",
"tiktok",
"linkedin"
],
"type": "string",
"description": "Ad platform — \"meta\", \"google\", and \"tiktok\" are supported today; \"linkedin\" is coming"
},
"accountId": {
"type": "string",
"description": "Not needed — connection happens via the returned sign-in link. Omit this."
}
},
"additionalProperties": false
},
"annotations": {
"title": "Connect Ad Account",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description99/100
List the EXISTING campaigns in one of the user's connected ad accounts (name, status, budget, and campaign id). Read-only. Use this to see what's already running before adjusting a specific campaign — the returned id feeds pause_campaign, resume_campaign, and update_budget.
The description explains the capability, when to use it, and what to expect.
Inputs63/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
platform
Ad platform — "meta", "google", and "tiktok" are supported today; "linkedin" is coming
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
accountId
Connected ad account id, e.g. "act_1234567890"
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "list_campaigns",
"title": "List Campaigns",
"description": "List the EXISTING campaigns in one of the user's connected ad accounts (name, status, budget, and campaign id). Read-only. Use this to see what's already running before adjusting a specific campaign — the returned id feeds pause_campaign, resume_campaign, and update_budget.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"platform",
"accountId"
],
"properties": {
"platform": {
"enum": [
"meta",
"google",
"tiktok",
"linkedin"
],
"type": "string",
"description": "Ad platform — \"meta\", \"google\", and \"tiktok\" are supported today; \"linkedin\" is coming"
},
"accountId": {
"type": "string",
"description": "Connected ad account id, e.g. \"act_1234567890\""
}
},
"additionalProperties": false
},
"annotations": {
"title": "List Campaigns",
"readOnlyHint": true,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description96/100
Look up ad-targeting options AND create Custom Audiences (Meta). LOOKUPS (read-only): kind 'interests' turns a niche or topic (e.g. 'health') into real platform interest ids with audience sizes; kind 'locations' turns a place name (e.g. 'Miami') into targetable location ids/keys; kind 'audiences' lists the account's existing Custom Audiences (how retargeting works — e.g. website visitors); kind 'pixels' lists the account's Meta or TikTok pixels (required for sales/conversion campaigns; TikTok rows include the conversion events on each pixel). CREATE AUDIENCES (Meta only, spends nothing by itself, Meta fills it over the next hours): kind 'create_website_audience' builds a retargeting pool from the account's pixel traffic (optional retentionDays 1-180 default 30, excludePurchasers) — use for 'retarget people who visited my site'; kind 'create_lookalike' reaches new people who behave like an existing audience (pass seedAudienceId from a kind 'audiences' lookup, ratioPct 1-10 where 1 = closest match, and country ISO-2) — use for 'find more people like my customers'. Target the created audience afterwards by passing its id as audienceIds on a launch. Platform support: meta = all lookups + both creates; tiktok = interests/locations/audiences/pixels; google = locations only. Show the user matches and let them confirm before launching; never invent interest ids or location keys, and never mix ids across platforms. Lookup ids/keys go into the targeting params of launch_campaign, launch_cloned_ad, launch_meta_ad, launch_search_campaign, launch_pmax_campaign, or launch_tiktok_campaign.
The description explains the capability, when to use it, and what to expect.
Inputs83/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
platform
Which ad platform (default meta). Ids are NOT interchangeable across platforms. Audience creation is Meta only.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
accountId
Connected ad account id on that platform, e.g. Meta "act_1234567890"
Clear enough to supply this argument.
kind
What to do: look up interests/locations/audiences/pixels, or CREATE a Meta audience (create_website_audience = pixel retargeting pool; create_lookalike = new people like an existing audience)
Clear enough to supply this argument.
query
Search term — required for interests ("health and wellness") and locations ("Miami")
Resolve the mismatch between this description and its schema constraints.
name
Audience creation only: a name for the new audience (a clear default is generated if omitted)
Clear enough to supply this argument.
retentionDays
create_website_audience only: how many days of pixel visitors to include, 1–180 (default 30)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
excludePurchasers
create_website_audience only: exclude people who purchased in the last 180 days
Clear enough to supply this argument.
seedAudienceId
create_lookalike only: the existing audience to model (id from a kind "audiences" lookup). Never invent it.
Clear enough to supply this argument.
ratioPct
create_lookalike only: similarity %, 1 = closest match (default 1)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
country
create_lookalike only: ISO-2 country the lookalike lives in (default US)
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "search_ad_targeting",
"title": "Search & Create Ad Targeting",
"description": "Look up ad-targeting options AND create Custom Audiences (Meta). LOOKUPS (read-only): kind 'interests' turns a niche or topic (e.g. 'health') into real platform interest ids with audience sizes; kind 'locations' turns a place name (e.g. 'Miami') into targetable location ids/keys; kind 'audiences' lists the account's existing Custom Audiences (how retargeting works — e.g. website visitors); kind 'pixels' lists the account's Meta or TikTok pixels (required for sales/conversion campaigns; TikTok rows include the conversion events on each pixel). CREATE AUDIENCES (Meta only, spends nothing by itself, Meta fills it over the next hours): kind 'create_website_audience' builds a retargeting pool from the account's pixel traffic (optional retentionDays 1-180 default 30, excludePurchasers) — use for 'retarget people who visited my site'; kind 'create_lookalike' reaches new people who behave like an existing audience (pass seedAudienceId from a kind 'audiences' lookup, ratioPct 1-10 where 1 = closest match, and country ISO-2) — use for 'find more people like my customers'. Target the created audience afterwards by passing its id as audienceIds on a launch. Platform support: meta = all lookups + both creates; tiktok = interests/locations/audiences/pixels; google = locations only. Show the user matches and let them confirm before launching; never invent interest ids or location keys, and never mix ids across platforms. Lookup ids/keys go into the targeting params of launch_campaign, launch_cloned_ad, launch_meta_ad, launch_search_campaign, launch_pmax_campaign, or launch_tiktok_campaign.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"accountId",
"kind"
],
"properties": {
"kind": {
"enum": [
"interests",
"locations",
"audiences",
"pixels",
"create_website_audience",
"create_lookalike"
],
"type": "string",
"description": "What to do: look up interests/locations/audiences/pixels, or CREATE a Meta audience (create_website_audience = pixel retargeting pool; create_lookalike = new people like an existing audience)"
},
"name": {
"type": "string",
"description": "Audience creation only: a name for the new audience (a clear default is generated if omitted)"
},
"query": {
"type": "string",
"description": "Search term — required for interests (\"health and wellness\") and locations (\"Miami\")"
},
"country": {
"type": "string",
"maxLength": 2,
"minLength": 2,
"description": "create_lookalike only: ISO-2 country the lookalike lives in (default US)"
},
"platform": {
"enum": [
"meta",
"google",
"tiktok"
],
"type": "string",
"description": "Which ad platform (default meta). Ids are NOT interchangeable across platforms. Audience creation is Meta only."
},
"ratioPct": {
"type": "integer",
"maximum": 10,
"minimum": 1,
"description": "create_lookalike only: similarity %, 1 = closest match (default 1)"
},
"accountId": {
"type": "string",
"description": "Connected ad account id on that platform, e.g. Meta \"act_1234567890\""
},
"retentionDays": {
"type": "integer",
"maximum": 180,
"minimum": 1,
"description": "create_website_audience only: how many days of pixel visitors to include, 1–180 (default 30)"
},
"seedAudienceId": {
"type": "string",
"description": "create_lookalike only: the existing audience to model (id from a kind \"audiences\" lookup). Never invent it."
},
"excludePurchasers": {
"type": "boolean",
"description": "create_website_audience only: exclude people who purchased in the last 180 days"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Search & Create Ad Targeting",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description95/100
Create a new ad campaign in the user's connected account. It is ALWAYS created PAUSED — it will not spend until the user resumes it with resume_campaign. This is a two-step action: call it first WITHOUT confirmToken to get a preview + a confirmToken, then call it AGAIN with the same args plus that confirmToken to actually create it. Objective is one of: traffic, sales, leads, awareness, engagement, app, video_views (video_views is TikTok only). If the user has not clearly said what they want the campaign to achieve, ASK them to pick a goal from that list before launching. Never guess the objective. META TARGETING: on Meta, passing a dailyBudgetUsd with objective traffic/sales/awareness/engagement creates the campaign PLUS a targeted ad set — interests, ages, gender, countries/cities/regions, and retargeting audiences all supported (resolve ids/keys with search_ad_targeting first). A sales objective automatically attaches the account's Meta pixel and optimizes for purchases; if the account has no pixel the tool explains that and suggests traffic instead.
The description explains the capability, when to use it, and what to expect.
Inputs72/100
17 of 19 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
platform
Ad platform — "meta", "google", and "tiktok" are supported today; "linkedin" is coming
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
accountId
Connected ad account id, e.g. "act_1234567890"
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
name
Campaign name
Explain the meaning of this value, not just its name.
objective
The campaign goal. Must be exactly one of: traffic, sales, leads, awareness, engagement, app, video_views (video_views is TikTok only). If the user has not clearly stated a goal, ASK them which one they want before calling this tool instead of guessing.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
dailyBudgetUsd
Daily budget in the ad account billing currency (e.g. 25 = 25.00/day in that currency)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
countries
ISO-2 country codes to target, e.g. ["US","GB"]. Defaults to US when no geo is given. IGNORED when cityKeys or regionKeys are set — Meta rejects a country combined with a city inside it, so pick ONE granularity.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
cityKeys
City keys from search_ad_targeting (kind "locations"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations).
Clear enough to supply this argument.
regionKeys
Region/state keys from search_ad_targeting (kind "locations"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
radiusAddress
RADIUS targeting: a street address or place to target AROUND (e.g. "Hoofdstraat 12, Amsterdam"). Meta locates the address itself — no lookup needed. When set, all other geo params are ignored (one circle IS the geography). Use when the user wants "within X km of my shop/city/address".
Clear enough to supply this argument.
radiusKm
Radius in km around radiusAddress (1–80, default 15). Only meaningful together with radiusAddress.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
ageMin
Minimum age (18–65)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
ageMax
Maximum age (18–65; 65 means 65+)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
gender
Gender targeting (default all)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
interests › items › id
Not provided
Missing description. Explain what this value means and how to supply it.
interests › items › name
Not provided
Missing description. Explain what this value means and how to supply it.
audienceIds
Existing Custom Audience ids from search_ad_targeting (kind "audiences") — this is how retargeting works.
Clear enough to supply this argument.
devicePlatforms
Device platforms to target, e.g. ["mobile"]. ONLY set this when the user explicitly asks to target by device — NEVER ask the user about device targeting; the default (all devices) is correct for most launches, and the preview will state it.
Clear enough to supply this argument.
userOs
Mobile OS targeting, e.g. ["iOS"] to reach iPhone/iPad users only (implies mobile-only delivery). ONLY set this when the user explicitly asks for it (e.g. "target iOS users", "iPhone owners") — NEVER prompt the user about OS or device targeting.
Clear enough to supply this argument.
confirmToken
Pass the token returned by the preview step to actually create the campaign
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "launch_campaign",
"title": "Launch Campaign",
"description": "Create a new ad campaign in the user's connected account. It is ALWAYS created PAUSED — it will not spend until the user resumes it with resume_campaign. This is a two-step action: call it first WITHOUT confirmToken to get a preview + a confirmToken, then call it AGAIN with the same args plus that confirmToken to actually create it. Objective is one of: traffic, sales, leads, awareness, engagement, app, video_views (video_views is TikTok only). If the user has not clearly said what they want the campaign to achieve, ASK them to pick a goal from that list before launching. Never guess the objective. META TARGETING: on Meta, passing a dailyBudgetUsd with objective traffic/sales/awareness/engagement creates the campaign PLUS a targeted ad set — interests, ages, gender, countries/cities/regions, and retargeting audiences all supported (resolve ids/keys with search_ad_targeting first). A sales objective automatically attaches the account's Meta pixel and optimizes for purchases; if the account has no pixel the tool explains that and suggests traffic instead.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"platform",
"accountId",
"name",
"objective"
],
"properties": {
"name": {
"type": "string",
"description": "Campaign name"
},
"ageMax": {
"type": "integer",
"maximum": 65,
"minimum": 18,
"description": "Maximum age (18–65; 65 means 65+)"
},
"ageMin": {
"type": "integer",
"maximum": 65,
"minimum": 18,
"description": "Minimum age (18–65)"
},
"gender": {
"enum": [
"all",
"male",
"female"
],
"type": "string",
"description": "Gender targeting (default all)"
},
"userOs": {
"type": "array",
"items": {
"enum": [
"iOS",
"Android"
],
"type": "string"
},
"description": "Mobile OS targeting, e.g. [\"iOS\"] to reach iPhone/iPad users only (implies mobile-only delivery). ONLY set this when the user explicitly asks for it (e.g. \"target iOS users\", \"iPhone owners\") — NEVER prompt the user about OS or device targeting."
},
"cityKeys": {
"type": "array",
"items": {
"type": "string"
},
"description": "City keys from search_ad_targeting (kind \"locations\"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations)."
},
"platform": {
"enum": [
"meta",
"google",
"tiktok",
"linkedin"
],
"type": "string",
"description": "Ad platform — \"meta\", \"google\", and \"tiktok\" are supported today; \"linkedin\" is coming"
},
"radiusKm": {
"type": "number",
"maximum": 80,
"minimum": 1,
"description": "Radius in km around radiusAddress (1–80, default 15). Only meaningful together with radiusAddress."
},
"accountId": {
"type": "string",
"description": "Connected ad account id, e.g. \"act_1234567890\""
},
"countries": {
"type": "array",
"items": {
"type": "string",
"maxLength": 2,
"minLength": 2
},
"description": "ISO-2 country codes to target, e.g. [\"US\",\"GB\"]. Defaults to US when no geo is given. IGNORED when cityKeys or regionKeys are set — Meta rejects a country combined with a city inside it, so pick ONE granularity."
},
"interests": {
"type": "array",
"items": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
},
"additionalProperties": false
},
"description": "Meta interest ids from search_ad_targeting (kind \"interests\"). Never invent ids — always search first and confirm the picks with the user."
},
"objective": {
"enum": [
"traffic",
"sales",
"leads",
"awareness",
"engagement",
"app",
"video_views"
],
"type": "string",
"description": "The campaign goal. Must be exactly one of: traffic, sales, leads, awareness, engagement, app, video_views (video_views is TikTok only). If the user has not clearly stated a goal, ASK them which one they want before calling this tool instead of guessing."
},
"regionKeys": {
"type": "array",
"items": {
"type": "string"
},
"description": "Region/state keys from search_ad_targeting (kind \"locations\"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations)."
},
"audienceIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "Existing Custom Audience ids from search_ad_targeting (kind \"audiences\") — this is how retargeting works."
},
"confirmToken": {
"type": "string",
"description": "Pass the token returned by the preview step to actually create the campaign"
},
"radiusAddress": {
"type": "string",
"description": "RADIUS targeting: a street address or place to target AROUND (e.g. \"Hoofdstraat 12, Amsterdam\"). Meta locates the address itself — no lookup needed. When set, all other geo params are ignored (one circle IS the geography). Use when the user wants \"within X km of my shop/city/address\"."
},
"dailyBudgetUsd": {
"type": "number",
"description": "Daily budget in the ad account billing currency (e.g. 25 = 25.00/day in that currency)",
"exclusiveMinimum": 0
},
"devicePlatforms": {
"type": "array",
"items": {
"enum": [
"mobile",
"desktop"
],
"type": "string"
},
"description": "Device platforms to target, e.g. [\"mobile\"]. ONLY set this when the user explicitly asks to target by device — NEVER ask the user about device targeting; the default (all devices) is correct for most launches, and the preview will state it."
}
},
"additionalProperties": false
},
"annotations": {
"title": "Launch Campaign",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description96/100
Create a complete, ready-to-run Google SEARCH campaign in the user's connected Google Ads account: it builds the campaign, ad group, keywords, AND a responsive search ad in one step. ALWAYS created PAUSED — nothing serves until the user resumes it with resume_campaign. This is the way to act on research_keywords results ('launch a campaign on these keywords'). CALL ADS: to make the search ads drive PHONE CALLS (a click-to-call button), also pass callPhoneNumber + callCountryCode — a CALL asset is attached to the campaign so the ad shows the phone number. Two-step action: call WITHOUT confirmToken to get a preview + confirmToken, then call AGAIN with the same args plus that confirmToken to create it. Requires at least 3 headlines (≤30 chars each), 2 descriptions (≤90 chars each), and a final URL.
The description explains the capability, when to use it, and what to expect.
Inputs87/100
Explain the meaning of this value, not just its name.
accountId
Connected Google Ads account id (digits, e.g. "2132148460")
Clear enough to supply this argument.
name
Campaign name
Explain the meaning of this value, not just its name.
keywords
Keywords to target (e.g. from research_keywords)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
headlines
3–15 ad headlines, each ≤30 characters
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
descriptions
2–4 ad descriptions, each ≤90 characters
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
finalUrl
Landing page URL the ad clicks through to (full https:// URL)
Clear enough to supply this argument.
dailyBudgetUsd
Daily budget in the ad account billing currency (e.g. 25 = 25.00/day in that currency)
Clear enough to supply this argument.
defaultCpc
Max CPC bid per keyword in the account billing currency (default 1.00 — usually TOO LOW to win auctions; a campaign that gets no impressions is almost always bidding below Google's first-page estimate, visible via get_account_performance with campaignId). Set from research_keywords CPC ranges when available.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
matchType
Keyword match type (default PHRASE)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
locationIds
Google location ids from search_ad_targeting (platform "google", kind "locations"). Default: United States. Never invent ids.
Clear enough to supply this argument.
callPhoneNumber
CALL ADS: a phone number in national format (e.g. "202 555 0140") to attach as a click-to-call button, so the search ads drive phone calls. Must be paired with callCountryCode. The account may need to accept call-recording consent in Google Ads settings first (a clear steer explains if so).
Clear enough to supply this argument.
callCountryCode
CALL ADS: the ISO-2 country code of callPhoneNumber (e.g. "US", "IN"). Required whenever callPhoneNumber is set.
Clear enough to supply this argument.
confirmToken
Pass the token returned by the preview step to actually create the campaign
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "launch_search_campaign",
"title": "Launch Google Search Campaign",
"description": "Create a complete, ready-to-run Google SEARCH campaign in the user's connected Google Ads account: it builds the campaign, ad group, keywords, AND a responsive search ad in one step. ALWAYS created PAUSED — nothing serves until the user resumes it with resume_campaign. This is the way to act on research_keywords results ('launch a campaign on these keywords'). CALL ADS: to make the search ads drive PHONE CALLS (a click-to-call button), also pass callPhoneNumber + callCountryCode — a CALL asset is attached to the campaign so the ad shows the phone number. Two-step action: call WITHOUT confirmToken to get a preview + confirmToken, then call AGAIN with the same args plus that confirmToken to create it. Requires at least 3 headlines (≤30 chars each), 2 descriptions (≤90 chars each), and a final URL.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"accountId",
"name",
"keywords",
"headlines",
"descriptions",
"finalUrl",
"dailyBudgetUsd"
],
"properties": {
"name": {
"type": "string",
"description": "Campaign name"
},
"finalUrl": {
"type": "string",
"description": "Landing page URL the ad clicks through to (full https:// URL)"
},
"keywords": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"description": "Keywords to target (e.g. from research_keywords)"
},
"accountId": {
"type": "string",
"description": "Connected Google Ads account id (digits, e.g. \"2132148460\")"
},
"headlines": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 3,
"description": "3–15 ad headlines, each ≤30 characters"
},
"matchType": {
"enum": [
"BROAD",
"PHRASE",
"EXACT"
],
"type": "string",
"description": "Keyword match type (default PHRASE)"
},
"defaultCpc": {
"type": "number",
"description": "Max CPC bid per keyword in the account billing currency (default 1.00 — usually TOO LOW to win auctions; a campaign that gets no impressions is almost always bidding below Google's first-page estimate, visible via get_account_performance with campaignId). Set from research_keywords CPC ranges when available.",
"exclusiveMinimum": 0
},
"locationIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "Google location ids from search_ad_targeting (platform \"google\", kind \"locations\"). Default: United States. Never invent ids."
},
"confirmToken": {
"type": "string",
"description": "Pass the token returned by the preview step to actually create the campaign"
},
"descriptions": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 2,
"description": "2–4 ad descriptions, each ≤90 characters"
},
"dailyBudgetUsd": {
"type": "number",
"description": "Daily budget in the ad account billing currency (e.g. 25 = 25.00/day in that currency)",
"exclusiveMinimum": 0
},
"callCountryCode": {
"type": "string",
"description": "CALL ADS: the ISO-2 country code of callPhoneNumber (e.g. \"US\", \"IN\"). Required whenever callPhoneNumber is set."
},
"callPhoneNumber": {
"type": "string",
"description": "CALL ADS: a phone number in national format (e.g. \"202 555 0140\") to attach as a click-to-call button, so the search ads drive phone calls. Must be paired with callCountryCode. The account may need to accept call-recording consent in Google Ads settings first (a clear steer explains if so)."
}
},
"additionalProperties": false
},
"annotations": {
"title": "Launch Google Search Campaign",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description97/100
Create a complete Google PERFORMANCE MAX campaign in the user's connected Google Ads account. AdWhispr AUTO-GENERATES all the creative assets (headlines, descriptions, landscape + square images, and uses the user's saved logo + business name) from their AdWhispr brand profile — so you normally only need accountId, name, and a daily budget. ALWAYS created PAUSED; nothing serves until the user resumes it with resume_campaign. Prerequisites checked automatically: the account must have CONVERSION TRACKING set up (PMax bids to conversions) and the user must have a brand logo + website in their AdWhispr profile; if not, the tool returns a clear message explaining what to fix. Two-step action: call WITHOUT confirmToken to generate the assets and get a preview + confirmToken, then call AGAIN with the same accountId/name/dailyBudgetUsd plus that confirmToken to create it. You may optionally override the copy via headlines/descriptions/longHeadlines.
The description explains the capability, when to use it, and what to expect.
Inputs82/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
accountId
Connected Google Ads account id (digits, e.g. "2132148460")
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
name
Campaign name (must be unique in the account)
Clear enough to supply this argument.
dailyBudgetUsd
Daily budget in the ad account billing currency (e.g. 30 = 30.00/day in that currency)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
finalUrl
Landing page URL (defaults to the website in the user profile)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
businessName
Optional: override business name (≤25 chars)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
searchThemes
Optional: search-theme audience signals
Explain the meaning of this value, not just its name.
locationIds
Google location ids from search_ad_targeting (platform "google", kind "locations"). Default: United States. Never invent ids.
Clear enough to supply this argument.
confirmToken
Pass the token returned by the preview step to actually create the campaign
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
{
"title": "Launch Google Performance Max Campaign",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "launch_pmax_campaign",
"title": "Launch Google Performance Max Campaign",
"description": "Create a complete Google PERFORMANCE MAX campaign in the user's connected Google Ads account. AdWhispr AUTO-GENERATES all the creative assets (headlines, descriptions, landscape + square images, and uses the user's saved logo + business name) from their AdWhispr brand profile — so you normally only need accountId, name, and a daily budget. ALWAYS created PAUSED; nothing serves until the user resumes it with resume_campaign. Prerequisites checked automatically: the account must have CONVERSION TRACKING set up (PMax bids to conversions) and the user must have a brand logo + website in their AdWhispr profile; if not, the tool returns a clear message explaining what to fix. Two-step action: call WITHOUT confirmToken to generate the assets and get a preview + confirmToken, then call AGAIN with the same accountId/name/dailyBudgetUsd plus that confirmToken to create it. You may optionally override the copy via headlines/descriptions/longHeadlines.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"accountId",
"name",
"dailyBudgetUsd"
],
"properties": {
"name": {
"type": "string",
"description": "Campaign name (must be unique in the account)"
},
"finalUrl": {
"type": "string",
"description": "Landing page URL (defaults to the website in the user profile)"
},
"accountId": {
"type": "string",
"description": "Connected Google Ads account id (digits, e.g. \"2132148460\")"
},
"headlines": {
"type": "array",
"items": {
"type": "string"
},
"description": "Optional: override auto-generated headlines (≤30 chars each, ≥3)"
},
"locationIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "Google location ids from search_ad_targeting (platform \"google\", kind \"locations\"). Default: United States. Never invent ids."
},
"businessName": {
"type": "string",
"description": "Optional: override business name (≤25 chars)"
},
"confirmToken": {
"type": "string",
"description": "Pass the token returned by the preview step to actually create the campaign"
},
"descriptions": {
"type": "array",
"items": {
"type": "string"
},
"description": "Optional: override descriptions (≤90 chars each, ≥2)"
},
"searchThemes": {
"type": "array",
"items": {
"type": "string"
},
"description": "Optional: search-theme audience signals"
},
"longHeadlines": {
"type": "array",
"items": {
"type": "string"
},
"description": "Optional: override long headlines (≤90 chars each, ≥1)"
},
"dailyBudgetUsd": {
"type": "number",
"description": "Daily budget in the ad account billing currency (e.g. 30 = 30.00/day in that currency)",
"exclusiveMinimum": 0
}
},
"additionalProperties": false
},
"annotations": {
"title": "Launch Google Performance Max Campaign",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description86/100
List the user's CREATIVE LIBRARY — their own ad videos and images uploaded to AdWhispr (dashboard > Creatives). Each entry has a name and a creativeId; videos can be launched on TikTok directly by passing creativeName (or creativeId) to launch_tiktok_campaign, no URL needed. Pass tiktokAccountId (their connected TikTok advertiser id) to ALSO list videos already sitting in their TikTok asset library, reusable via videoId. Call this whenever the user references 'my video', 'my creative', or asks what assets they have.
Describe the returned information so the agent knows whether it will answer the request.
Inputs92/100
Input documentation gives an agent enough context to populate the arguments.
tiktokAccountId
Connected TikTok advertiser id — include to also list videos already in their TikTok asset library
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "list_my_creatives",
"title": "List My Creatives",
"description": "List the user's CREATIVE LIBRARY — their own ad videos and images uploaded to AdWhispr (dashboard > Creatives). Each entry has a name and a creativeId; videos can be launched on TikTok directly by passing creativeName (or creativeId) to launch_tiktok_campaign, no URL needed. Pass tiktokAccountId (their connected TikTok advertiser id) to ALSO list videos already sitting in their TikTok asset library, reusable via videoId. Call this whenever the user references 'my video', 'my creative', or asks what assets they have.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"tiktokAccountId": {
"type": "string",
"description": "Connected TikTok advertiser id — include to also list videos already in their TikTok asset library"
}
},
"additionalProperties": false
},
"annotations": {
"title": "List My Creatives",
"readOnlyHint": true,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description97/100
Create a complete, ready-to-run TIKTOK campaign in the user's connected TikTok Ads account: campaign, ad group (targeting + budget + schedule), the user's video uploaded to their asset library, and the video ad itself — in one step. ALWAYS created PAUSED; nothing serves until the user resumes it with resume_campaign (TikTok also runs its own ad review). TWO PREREQUISITES: (1) a video the USER OWNS — easiest is creativeName referencing their AdWhispr creative library (see list_my_creatives; they upload at dashboard > Creatives), or videoUrl (direct link to their MP4) or videoId (a video already in their TikTok asset library); never a competitor's video file — and to run a CREATIVE TEST, pass 2–5 library names as creativeNames: each video becomes its own ad in ONE ad group, whose budget TikTok shifts toward the winner; (2) the user's TikTok account must be linked to the ad account as an identity (TikTok Ads Manager > Assets > Identity) — TikTok no longer allows ads under a made-up name; the tool checks this and explains if it's missing. The caption (adText) is auto-written from the user's AdWhispr brand profile when omitted; the landing page defaults to their saved website. Supported objectives: traffic (default), sales (needs pixelId from TikTok Ads Manager), awareness, video_views. Daily budget minimum is 20 in the account's currency (TikTok's ad-group floor). Targeting defaults to the United States. Two-step action: call WITHOUT confirmToken to upload the video and get a preview + confirmToken, then call AGAIN with the same accountId/name/dailyBudgetUsd plus that confirmToken to create it.
The description explains the capability, when to use it, and what to expect.
Inputs85/100
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
accountId
Connected TikTok advertiser id (digits)
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
name
Campaign name
Explain the meaning of this value, not just its name.
objective
The campaign goal, defaults to traffic. Must be one of: traffic, sales, awareness, video_views. If the user cares about a specific goal but has not said which, ASK them to choose before launching instead of guessing.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
dailyBudgetUsd
Ad group daily budget in the ad account billing currency — minimum 20
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
creativeName
Name of a video in the user's AdWhispr creative library (see list_my_creatives) — the easiest way to supply the video
Clear enough to supply this argument.
creativeNames
CREATIVE TEST: 2–5 library video names — each becomes its OWN ad in ONE ad group, and TikTok shifts the budget toward the winner. Wins over creativeName/videoUrl/videoId.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
creativeId
Creative library id (alternative to creativeName)
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
videoUrl
Direct URL to the user's OWN video file (MP4) — uploaded to their TikTok asset library
Clear enough to supply this argument.
videoId
A video id already in the user's TikTok asset library (alternative to videoUrl)
Clear enough to supply this argument.
adText
Ad caption, max 100 characters, no emoji (auto-written from the brand profile when omitted)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
landingPageUrl
Landing page URL (defaults to the website in the user profile)
Clear enough to supply this argument.
callToAction
Call to action, e.g. LEARN_MORE (default), SHOP_NOW, SIGN_UP, DOWNLOAD_NOW
Clear enough to supply this argument.
locationIds
TikTok location ids from search_ad_targeting (platform "tiktok", kind "locations"). Default: United States. Never invent ids.
Clear enough to supply this argument.
ageMin
Minimum age (18+; TikTok uses buckets, the closest are applied)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
ageMax
Maximum age (TikTok uses buckets, the closest are applied)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
gender
Gender targeting (default all)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
interestIds
TikTok interest category ids from search_ad_targeting (platform "tiktok", kind "interests"). Never invent ids.
TikTok pixel id — required for the sales objective. Find it (plus the conversion events that exist on it) via search_ad_targeting (platform "tiktok", kind "pixels").
Clear enough to supply this argument.
optimizationEvent
Pixel event to optimize to for sales. Usually omit: the launcher auto-picks from the events that exist on the pixel (purchase-type first) and tells you the real options if it needs a choice.
Clear enough to supply this argument.
confirmToken
Pass the token returned by the preview step to actually create the campaign
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "launch_tiktok_campaign",
"title": "Launch TikTok Video Campaign",
"description": "Create a complete, ready-to-run TIKTOK campaign in the user's connected TikTok Ads account: campaign, ad group (targeting + budget + schedule), the user's video uploaded to their asset library, and the video ad itself — in one step. ALWAYS created PAUSED; nothing serves until the user resumes it with resume_campaign (TikTok also runs its own ad review). TWO PREREQUISITES: (1) a video the USER OWNS — easiest is creativeName referencing their AdWhispr creative library (see list_my_creatives; they upload at dashboard > Creatives), or videoUrl (direct link to their MP4) or videoId (a video already in their TikTok asset library); never a competitor's video file — and to run a CREATIVE TEST, pass 2–5 library names as creativeNames: each video becomes its own ad in ONE ad group, whose budget TikTok shifts toward the winner; (2) the user's TikTok account must be linked to the ad account as an identity (TikTok Ads Manager > Assets > Identity) — TikTok no longer allows ads under a made-up name; the tool checks this and explains if it's missing. The caption (adText) is auto-written from the user's AdWhispr brand profile when omitted; the landing page defaults to their saved website. Supported objectives: traffic (default), sales (needs pixelId from TikTok Ads Manager), awareness, video_views. Daily budget minimum is 20 in the account's currency (TikTok's ad-group floor). Targeting defaults to the United States. Two-step action: call WITHOUT confirmToken to upload the video and get a preview + confirmToken, then call AGAIN with the same accountId/name/dailyBudgetUsd plus that confirmToken to create it.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"accountId",
"name",
"dailyBudgetUsd"
],
"properties": {
"name": {
"type": "string",
"description": "Campaign name"
},
"adText": {
"type": "string",
"description": "Ad caption, max 100 characters, no emoji (auto-written from the brand profile when omitted)"
},
"ageMax": {
"type": "integer",
"maximum": 100,
"minimum": 18,
"description": "Maximum age (TikTok uses buckets, the closest are applied)"
},
"ageMin": {
"type": "integer",
"maximum": 100,
"minimum": 18,
"description": "Minimum age (18+; TikTok uses buckets, the closest are applied)"
},
"gender": {
"enum": [
"all",
"male",
"female"
],
"type": "string",
"description": "Gender targeting (default all)"
},
"pixelId": {
"type": "string",
"description": "TikTok pixel id — required for the sales objective. Find it (plus the conversion events that exist on it) via search_ad_targeting (platform \"tiktok\", kind \"pixels\")."
},
"videoId": {
"type": "string",
"description": "A video id already in the user's TikTok asset library (alternative to videoUrl)"
},
"videoUrl": {
"type": "string",
"description": "Direct URL to the user's OWN video file (MP4) — uploaded to their TikTok asset library"
},
"accountId": {
"type": "string",
"description": "Connected TikTok advertiser id (digits)"
},
"objective": {
"enum": [
"traffic",
"sales",
"awareness",
"video_views"
],
"type": "string",
"description": "The campaign goal, defaults to traffic. Must be one of: traffic, sales, awareness, video_views. If the user cares about a specific goal but has not said which, ASK them to choose before launching instead of guessing."
},
"creativeId": {
"type": "string",
"description": "Creative library id (alternative to creativeName)"
},
"audienceIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "Existing TikTok Custom Audience ids from search_ad_targeting (platform \"tiktok\", kind \"audiences\") — retargeting."
},
"interestIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "TikTok interest category ids from search_ad_targeting (platform \"tiktok\", kind \"interests\"). Never invent ids."
},
"locationIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "TikTok location ids from search_ad_targeting (platform \"tiktok\", kind \"locations\"). Default: United States. Never invent ids."
},
"callToAction": {
"type": "string",
"description": "Call to action, e.g. LEARN_MORE (default), SHOP_NOW, SIGN_UP, DOWNLOAD_NOW"
},
"confirmToken": {
"type": "string",
"description": "Pass the token returned by the preview step to actually create the campaign"
},
"creativeName": {
"type": "string",
"description": "Name of a video in the user's AdWhispr creative library (see list_my_creatives) — the easiest way to supply the video"
},
"creativeNames": {
"type": "array",
"items": {
"type": "string"
},
"maxItems": 5,
"description": "CREATIVE TEST: 2–5 library video names — each becomes its OWN ad in ONE ad group, and TikTok shifts the budget toward the winner. Wins over creativeName/videoUrl/videoId."
},
"dailyBudgetUsd": {
"type": "number",
"description": "Ad group daily budget in the ad account billing currency — minimum 20",
"exclusiveMinimum": 0
},
"landingPageUrl": {
"type": "string",
"description": "Landing page URL (defaults to the website in the user profile)"
},
"optimizationEvent": {
"type": "string",
"description": "Pixel event to optimize to for sales. Usually omit: the launcher auto-picks from the events that exist on the pixel (purchase-type first) and tells you the real options if it needs a choice."
}
},
"additionalProperties": false
},
"annotations": {
"title": "Launch TikTok Video Campaign",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
Align the title with the capability actually described by this tool.
Description87/100
Change a campaign's daily budget (in the ad account's own currency). Two-step: call without confirmToken for a preview + token, then call again with the confirmToken to apply.
Explain mutations, irreversible effects, or prerequisites that matter before calling this tool.
Inputs70/100
4 of 5 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
platform
Not provided
Missing description. Explain what this value means and how to supply it.
accountId
Connected ad account id
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
campaignId
The campaign id to update (or an ad set / ad group id when renaming one)
Clear enough to supply this argument.
dailyBudgetUsd
New daily budget in the ad account billing currency
Clear enough to supply this argument.
confirmToken
Token from the preview step
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "update_budget",
"title": "Update Campaign",
"description": "Change a campaign's daily budget (in the ad account's own currency). Two-step: call without confirmToken for a preview + token, then call again with the confirmToken to apply.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"platform",
"accountId",
"campaignId",
"dailyBudgetUsd"
],
"properties": {
"platform": {
"enum": [
"meta",
"google",
"tiktok",
"linkedin"
],
"type": "string"
},
"accountId": {
"type": "string",
"description": "Connected ad account id"
},
"campaignId": {
"type": "string",
"description": "The campaign id to update (or an ad set / ad group id when renaming one)"
},
"confirmToken": {
"type": "string",
"description": "Token from the preview step"
},
"dailyBudgetUsd": {
"type": "number",
"description": "New daily budget in the ad account billing currency",
"exclusiveMinimum": 0
}
},
"additionalProperties": false
},
"annotations": {
"title": "Update Campaign",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description95/100
Read or change the geographic targeting of an EXISTING campaign/ad set (two-step confirm on changes). GOOGLE: pass addLocationIds and/or removeLocationIds (geo target ids from search_ad_targeting platform "google", kind "locations") to add/remove countries or regions on a campaign. META: change where a LIVE ad set delivers, IN PLACE, without rebuilding the ad or losing its history — pass adSetId (from list_campaigns; or just campaignId and the sole ad set is used) plus EITHER radiusAddress (+ radiusKm 1-80, default 15) to target a circle around a street address (e.g. "Waddinxveen, Netherlands" + 40 km), OR setCountries / setCityKeys / setRegionKeys (ISO-2 codes / keys from search_ad_targeting platform "meta", kind "locations") to swap the geography. Changing an ad set's targeting restarts Meta's learning phase, so delivery re-stabilizes over a few days. Call with just platform/accountId/campaignId (or adSetId) to READ the current targeting. Changes are two-step: call without confirmToken for a preview + token, then again with the same args plus that token to apply. Never invent ids/keys. TikTok locations still live on the ad group and are set at launch.
The description explains the capability, when to use it, and what to expect.
Inputs95/100
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
platform
"google" (campaign geo add/remove) or "meta" (edit a live ad set's location/radius in place)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
accountId
Connected ad account id — Google Ads id (digits) or Meta "act_..."
Clear enough to supply this argument.
campaignId
Campaign id from list_campaigns. Google: the campaign to change. Meta: used to find the ad set when adSetId is not given.
Clear enough to supply this argument.
addLocationIds
GOOGLE only: geo target ids to ADD, from search_ad_targeting (platform "google", kind "locations"). Never invent ids.
Clear enough to supply this argument.
removeLocationIds
GOOGLE only: geo target ids to REMOVE — see the current list by calling this tool without add/remove first
Clear enough to supply this argument.
adSetId
META only: the ad set whose location to change (from list_campaigns). Omit to use the campaign's single ad set.
Clear enough to supply this argument.
radiusAddress
META only: a street address/place to target a circle around (Meta geocodes it). Replaces the ad set's geography.
Clear enough to supply this argument.
radiusKm
META only: radius in km around radiusAddress, 1–80 (default 15)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
setCountries
META only: ISO-2 country codes to target instead (e.g. ["NL"]). Replaces the ad set's geography.
Clear enough to supply this argument.
setCityKeys
META only: city keys from search_ad_targeting (platform "meta", kind "locations") to target instead
Clear enough to supply this argument.
setRegionKeys
META only: region keys from search_ad_targeting (platform "meta", kind "locations") to target instead
Clear enough to supply this argument.
confirmToken
Token from the preview step
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "update_campaign_locations",
"title": "Update Campaign Locations",
"description": "Read or change the geographic targeting of an EXISTING campaign/ad set (two-step confirm on changes). GOOGLE: pass addLocationIds and/or removeLocationIds (geo target ids from search_ad_targeting platform \"google\", kind \"locations\") to add/remove countries or regions on a campaign. META: change where a LIVE ad set delivers, IN PLACE, without rebuilding the ad or losing its history — pass adSetId (from list_campaigns; or just campaignId and the sole ad set is used) plus EITHER radiusAddress (+ radiusKm 1-80, default 15) to target a circle around a street address (e.g. \"Waddinxveen, Netherlands\" + 40 km), OR setCountries / setCityKeys / setRegionKeys (ISO-2 codes / keys from search_ad_targeting platform \"meta\", kind \"locations\") to swap the geography. Changing an ad set's targeting restarts Meta's learning phase, so delivery re-stabilizes over a few days. Call with just platform/accountId/campaignId (or adSetId) to READ the current targeting. Changes are two-step: call without confirmToken for a preview + token, then again with the same args plus that token to apply. Never invent ids/keys. TikTok locations still live on the ad group and are set at launch.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"platform",
"accountId",
"campaignId"
],
"properties": {
"adSetId": {
"type": "string",
"description": "META only: the ad set whose location to change (from list_campaigns). Omit to use the campaign's single ad set."
},
"platform": {
"enum": [
"meta",
"google",
"tiktok",
"linkedin"
],
"type": "string",
"description": "\"google\" (campaign geo add/remove) or \"meta\" (edit a live ad set's location/radius in place)"
},
"radiusKm": {
"type": "number",
"maximum": 80,
"minimum": 1,
"description": "META only: radius in km around radiusAddress, 1–80 (default 15)"
},
"accountId": {
"type": "string",
"description": "Connected ad account id — Google Ads id (digits) or Meta \"act_...\""
},
"campaignId": {
"type": "string",
"description": "Campaign id from list_campaigns. Google: the campaign to change. Meta: used to find the ad set when adSetId is not given."
},
"setCityKeys": {
"type": "array",
"items": {
"type": "string"
},
"description": "META only: city keys from search_ad_targeting (platform \"meta\", kind \"locations\") to target instead"
},
"confirmToken": {
"type": "string",
"description": "Token from the preview step"
},
"setCountries": {
"type": "array",
"items": {
"type": "string"
},
"description": "META only: ISO-2 country codes to target instead (e.g. [\"NL\"]). Replaces the ad set's geography."
},
"radiusAddress": {
"type": "string",
"description": "META only: a street address/place to target a circle around (Meta geocodes it). Replaces the ad set's geography."
},
"setRegionKeys": {
"type": "array",
"items": {
"type": "string"
},
"description": "META only: region keys from search_ad_targeting (platform \"meta\", kind \"locations\") to target instead"
},
"addLocationIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "GOOGLE only: geo target ids to ADD, from search_ad_targeting (platform \"google\", kind \"locations\"). Never invent ids."
},
"removeLocationIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "GOOGLE only: geo target ids to REMOVE — see the current list by calling this tool without add/remove first"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Update Campaign Locations",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": true
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description96/100
Resume a paused campaign — this takes it LIVE and it begins spending. Two-step: call without confirmToken for a warning + token, then call again with the confirmToken to go live.
The description explains the capability, when to use it, and what to expect.
Inputs63/100
3 of 4 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
platform
Not provided
Missing description. Explain what this value means and how to supply it.
accountId
Connected ad account id
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
campaignId
The campaign id to resume
Clear enough to supply this argument.
confirmToken
Token from the preview step
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
The title clearly communicates the tool’s action and subject. Keep it concise.
Description93/100
Read campaign performance (spend, impressions, clicks, conversions; on Meta also pixel purchases, add-to-carts, leads, cost per purchase and ROAS when the account has a pixel) for a connected ad account. Read-only. Defaults to the last 30 days; optionally pass since/until as YYYY-MM-DD. Pass campaignId to drill into ONE campaign — for Google Search campaigns this returns per-keyword delivery diagnostics (quality score, 'below first page bid' with the bid Google estimates would fix it, 'rarely shown', approval issues) plus concrete optimization guidance. ALWAYS drill in when a campaign is spending far less than its budget — the cause is almost always keyword-level, and the output tells you exactly what to change.
The description explains the capability, when to use it, and what to expect.
Inputs60/100
4 of 5 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
platform
Not provided
Missing description. Explain what this value means and how to supply it.
accountId
Connected ad account id
Clarify units, where to obtain this value, or conventions not already expressed in the schema.
campaignId
Drill into one campaign (id from list_campaigns). On Google Search campaigns this adds per-keyword delivery diagnostics + optimization guidance — use it to answer "why is this campaign not spending / how do I improve it?"
Clear enough to supply this argument.
since
Start date YYYY-MM-DD
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
until
End date YYYY-MM-DD
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "get_account_performance",
"title": "Get Account Performance",
"description": "Read campaign performance (spend, impressions, clicks, conversions; on Meta also pixel purchases, add-to-carts, leads, cost per purchase and ROAS when the account has a pixel) for a connected ad account. Read-only. Defaults to the last 30 days; optionally pass since/until as YYYY-MM-DD. Pass campaignId to drill into ONE campaign — for Google Search campaigns this returns per-keyword delivery diagnostics (quality score, 'below first page bid' with the bid Google estimates would fix it, 'rarely shown', approval issues) plus concrete optimization guidance. ALWAYS drill in when a campaign is spending far less than its budget — the cause is almost always keyword-level, and the output tells you exactly what to change.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"platform",
"accountId"
],
"properties": {
"since": {
"type": "string",
"description": "Start date YYYY-MM-DD"
},
"until": {
"type": "string",
"description": "End date YYYY-MM-DD"
},
"platform": {
"enum": [
"meta",
"google",
"tiktok",
"linkedin"
],
"type": "string"
},
"accountId": {
"type": "string",
"description": "Connected ad account id"
},
"campaignId": {
"type": "string",
"description": "Drill into one campaign (id from list_campaigns). On Google Search campaigns this adds per-keyword delivery diagnostics + optimization guidance — use it to answer \"why is this campaign not spending / how do I improve it?\""
}
},
"additionalProperties": false
},
"annotations": {
"title": "Get Account Performance",
"readOnlyHint": true,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description95/100
Take an image clone the user already made in the AdWhispr web app (it lives in their Creative Library) and launch it as a real, PAUSED ad in their connected Meta account — campaign + ad set + creative + ad, all paused (no spend until they resume). This closes the loop: research a competitor → clone their winning ad in the AdWhispr app → launch it from here. ONLY the cloned IMAGE comes from the clone — the destination link and ad copy are the USER'S OWN: you MUST write message (primary text, and optionally headline) fresh for the user's product, and the link is the user's own page (falls back to their saved website; the competitor's URL and copy are NEVER used — the tool refuses without your own copy). Two-step: call without confirmToken for a preview + token — the preview shows the exact destination link and copy; show them to the user — then again with the confirmToken to create it. The ad runs from one of the user's Facebook Pages: pass pageName (e.g. "adWhispr") to pick it by name, and if the user has exactly one page enabled it is used automatically — you do NOT need a numeric pageId. Only pass pageId if the user gives you an explicit numeric id. If the page can't be resolved, the tool replies with the enabled page names to choose from. Get the clonedAdId from list_my_creatives. Objective is one of: traffic (default), sales, awareness, engagement — sales optimizes for purchases via the account's Meta pixel (attached automatically; a clear error explains if the account has none); lead objectives need a lead form and are not offered here. Targeting (interests, ages, gender, geo, retargeting audiences) is supported — resolve ids/keys with search_ad_targeting first. If the user has not said what the ad should achieve, ASK them to pick traffic, sales, awareness, or engagement before launching instead of guessing.
Resolve contradictions between the description, input schema, and annotations.
Inputs84/100
21 of 23 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
accountId
Connected Meta ad account id, e.g. "act_1234567890"
Clear enough to supply this argument.
clonedAdId
UUID of an image clone from the user's Creative Library (see list_my_creatives)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
dailyBudgetUsd
Daily budget in the ad account billing currency
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
pageName
The Facebook Page to run the ad from, by name (e.g. "adWhispr"). Preferred over pageId. Omit if the user has only one page enabled — it is used automatically.
Clear enough to supply this argument.
pageId
Numeric Facebook Page id. Prefer pageName when the Page is listed. IMPORTANT: if a launch just failed because Meta returned no Pages for the ad account (common when the Page sits in a Business portfolio, or the ad account has never run an ad), ASK the user for their numeric Page id — Meta Business Settings > Pages, or the number at the end of the Page URL — and pass it here. An id given this way is trusted and launched directly; Meta itself checks whether they may advertise with it.
Clear enough to supply this argument.
link
Destination URL people land on when they click — the USER'S OWN product or site URL. Falls back to their saved website. The source/competitor ad's URL is NEVER used.
Clear enough to supply this argument.
message
REQUIRED: the ad's primary text, written fresh by you for the USER'S OWN product (never the source ad's copy — the tool refuses without this). Keep it in the spirit of the cloned layout but selling the user's product.
Clear enough to supply this argument.
headline
Optional headline below the image, written for the USER'S OWN product.
Clear enough to supply this argument.
objective
The campaign goal, defaults to traffic. Must be one of: traffic, sales, leads, awareness, engagement. Sales optimizes for purchases and leads for website lead conversions — both via the account's Meta pixel (the tool attaches it automatically; accounts without a pixel get a clear error). Leads here means WEBSITE leads (optimizing for the pixel Lead event); on-Meta lead forms are not supported. If the user cares about a specific goal but has not said which, ASK them to choose before launching instead of guessing.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
countries
ISO-2 country codes to target, e.g. ["US","GB"]. Defaults to US when no geo is given. IGNORED when cityKeys or regionKeys are set — Meta rejects a country combined with a city inside it, so pick ONE granularity.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
cityKeys
City keys from search_ad_targeting (kind "locations"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations).
Clear enough to supply this argument.
regionKeys
Region/state keys from search_ad_targeting (kind "locations"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations).
Clear enough to supply this argument.
radiusAddress
RADIUS targeting: a street address or place to target AROUND (e.g. "Hoofdstraat 12, Amsterdam"). Meta locates the address itself — no lookup needed. When set, all other geo params are ignored (one circle IS the geography). Use when the user wants "within X km of my shop/city/address".
Clear enough to supply this argument.
radiusKm
Radius in km around radiusAddress (1–80, default 15). Only meaningful together with radiusAddress.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
ageMin
Minimum age (18–65)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
ageMax
Maximum age (18–65; 65 means 65+)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
gender
Gender targeting (default all)
Clear enough to supply this argument.
interests › items › id
Not provided
Missing description. Explain what this value means and how to supply it.
interests › items › name
Not provided
Missing description. Explain what this value means and how to supply it.
audienceIds
Existing Custom Audience ids from search_ad_targeting (kind "audiences") — this is how retargeting works.
Clear enough to supply this argument.
devicePlatforms
Device platforms to target, e.g. ["mobile"]. ONLY set this when the user explicitly asks to target by device — NEVER ask the user about device targeting; the default (all devices) is correct for most launches, and the preview will state it.
Clear enough to supply this argument.
userOs
Mobile OS targeting, e.g. ["iOS"] to reach iPhone/iPad users only (implies mobile-only delivery). ONLY set this when the user explicitly asks for it (e.g. "target iOS users", "iPhone owners") — NEVER prompt the user about OS or device targeting.
Clear enough to supply this argument.
confirmToken
Token from the preview step
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "launch_cloned_ad",
"title": "Launch Cloned Ad",
"description": "Take an image clone the user already made in the AdWhispr web app (it lives in their Creative Library) and launch it as a real, PAUSED ad in their connected Meta account — campaign + ad set + creative + ad, all paused (no spend until they resume). This closes the loop: research a competitor → clone their winning ad in the AdWhispr app → launch it from here. ONLY the cloned IMAGE comes from the clone — the destination link and ad copy are the USER'S OWN: you MUST write message (primary text, and optionally headline) fresh for the user's product, and the link is the user's own page (falls back to their saved website; the competitor's URL and copy are NEVER used — the tool refuses without your own copy). Two-step: call without confirmToken for a preview + token — the preview shows the exact destination link and copy; show them to the user — then again with the confirmToken to create it. The ad runs from one of the user's Facebook Pages: pass pageName (e.g. \"adWhispr\") to pick it by name, and if the user has exactly one page enabled it is used automatically — you do NOT need a numeric pageId. Only pass pageId if the user gives you an explicit numeric id. If the page can't be resolved, the tool replies with the enabled page names to choose from. Get the clonedAdId from list_my_creatives. Objective is one of: traffic (default), sales, awareness, engagement — sales optimizes for purchases via the account's Meta pixel (attached automatically; a clear error explains if the account has none); lead objectives need a lead form and are not offered here. Targeting (interests, ages, gender, geo, retargeting audiences) is supported — resolve ids/keys with search_ad_targeting first. If the user has not said what the ad should achieve, ASK them to pick traffic, sales, awareness, or engagement before launching instead of guessing.",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"accountId",
"clonedAdId",
"dailyBudgetUsd"
],
"properties": {
"link": {
"type": "string",
"format": "uri",
"description": "Destination URL people land on when they click — the USER'S OWN product or site URL. Falls back to their saved website. The source/competitor ad's URL is NEVER used."
},
"ageMax": {
"type": "integer",
"maximum": 65,
"minimum": 18,
"description": "Maximum age (18–65; 65 means 65+)"
},
"ageMin": {
"type": "integer",
"maximum": 65,
"minimum": 18,
"description": "Minimum age (18–65)"
},
"gender": {
"enum": [
"all",
"male",
"female"
],
"type": "string",
"description": "Gender targeting (default all)"
},
"pageId": {
"type": "string",
"description": "Numeric Facebook Page id. Prefer pageName when the Page is listed. IMPORTANT: if a launch just failed because Meta returned no Pages for the ad account (common when the Page sits in a Business portfolio, or the ad account has never run an ad), ASK the user for their numeric Page id — Meta Business Settings > Pages, or the number at the end of the Page URL — and pass it here. An id given this way is trusted and launched directly; Meta itself checks whether they may advertise with it."
},
"userOs": {
"type": "array",
"items": {
"enum": [
"iOS",
"Android"
],
"type": "string"
},
"description": "Mobile OS targeting, e.g. [\"iOS\"] to reach iPhone/iPad users only (implies mobile-only delivery). ONLY set this when the user explicitly asks for it (e.g. \"target iOS users\", \"iPhone owners\") — NEVER prompt the user about OS or device targeting."
},
"message": {
"type": "string",
"description": "REQUIRED: the ad's primary text, written fresh by you for the USER'S OWN product (never the source ad's copy — the tool refuses without this). Keep it in the spirit of the cloned layout but selling the user's product."
},
"cityKeys": {
"type": "array",
"items": {
"type": "string"
},
"description": "City keys from search_ad_targeting (kind \"locations\"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations)."
},
"headline": {
"type": "string",
"description": "Optional headline below the image, written for the USER'S OWN product."
},
"pageName": {
"type": "string",
"description": "The Facebook Page to run the ad from, by name (e.g. \"adWhispr\"). Preferred over pageId. Omit if the user has only one page enabled — it is used automatically."
},
"radiusKm": {
"type": "number",
"maximum": 80,
"minimum": 1,
"description": "Radius in km around radiusAddress (1–80, default 15). Only meaningful together with radiusAddress."
},
"accountId": {
"type": "string",
"description": "Connected Meta ad account id, e.g. \"act_1234567890\""
},
"countries": {
"type": "array",
"items": {
"type": "string",
"maxLength": 2,
"minLength": 2
},
"description": "ISO-2 country codes to target, e.g. [\"US\",\"GB\"]. Defaults to US when no geo is given. IGNORED when cityKeys or regionKeys are set — Meta rejects a country combined with a city inside it, so pick ONE granularity."
},
"interests": {
"type": "array",
"items": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
},
"additionalProperties": false
},
"description": "Meta interest ids from search_ad_targeting (kind \"interests\"). Never invent ids — always search first and confirm the picks with the user."
},
"objective": {
"enum": [
"traffic",
"sales",
"leads",
"awareness",
"engagement"
],
"type": "string",
"description": "The campaign goal, defaults to traffic. Must be one of: traffic, sales, leads, awareness, engagement. Sales optimizes for purchases and leads for website lead conversions — both via the account's Meta pixel (the tool attaches it automatically; accounts without a pixel get a clear error). Leads here means WEBSITE leads (optimizing for the pixel Lead event); on-Meta lead forms are not supported. If the user cares about a specific goal but has not said which, ASK them to choose before launching instead of guessing."
},
"clonedAdId": {
"type": "string",
"format": "uuid",
"description": "UUID of an image clone from the user's Creative Library (see list_my_creatives)"
},
"regionKeys": {
"type": "array",
"items": {
"type": "string"
},
"description": "Region/state keys from search_ad_targeting (kind \"locations\"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations)."
},
"audienceIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "Existing Custom Audience ids from search_ad_targeting (kind \"audiences\") — this is how retargeting works."
},
"confirmToken": {
"type": "string",
"description": "Token from the preview step"
},
"radiusAddress": {
"type": "string",
"description": "RADIUS targeting: a street address or place to target AROUND (e.g. \"Hoofdstraat 12, Amsterdam\"). Meta locates the address itself — no lookup needed. When set, all other geo params are ignored (one circle IS the geography). Use when the user wants \"within X km of my shop/city/address\"."
},
"dailyBudgetUsd": {
"type": "number",
"description": "Daily budget in the ad account billing currency",
"exclusiveMinimum": 0
},
"devicePlatforms": {
"type": "array",
"items": {
"enum": [
"mobile",
"desktop"
],
"type": "string"
},
"description": "Device platforms to target, e.g. [\"mobile\"]. ONLY set this when the user explicitly asks to target by device — NEVER ask the user about device targeting; the default (all devices) is correct for most launches, and the preview will state it."
}
},
"additionalProperties": false
},
"annotations": {
"title": "Launch Cloned Ad",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
The title clearly communicates the tool’s action and subject. Keep it concise.
Description98/100
Launch the user's OWN images or videos as a real, PAUSED ad in their connected Meta (Facebook/Instagram) account — campaign + ad set + creative + ad, all paused (no spend until they resume). ONE image card = a single-image ad; 2–10 image cards = a CAROUSEL in the exact card order given; ONE video card = a VIDEO ad. MIXED cards (a video plus images, or several videos, 2–10 total) = a CREATIVE TEST: each card becomes its OWN ad inside ONE shared ad set, and Meta shifts the ad set's budget toward whichever ad performs — use this when the user wants several creatives competing (e.g. 'test my video against these two photos'). Use this when the user has their own finished creatives ('launch my carousel', 'run this image I made', 'launch my video on Facebook') — for launching an image clone made in the AdWhispr app use launch_cloned_ad instead; finished AI videos made in the app land in the Creative Library and launch HERE by creativeName. WHERE CREATIVES COME FROM: the user's Creative Library — reference each card by creativeName (see list_my_creatives; images and videos both work). If their files aren't uploaded yet, send them to https://adwhispr.com/dashboard/creatives to upload (drag & drop), then have them tell you when done and use list_my_creatives to find the names. A direct https imageUrl/videoUrl the user owns also works. NEVER use competitor images or ad-library assets. On confirm, a video is uploaded into the ad account and Meta processes it (~30s extra; if processing outruns the call, the campaign + ad set are still created and the tool says how to finish). Per-card headline/description/link are optional (link falls back to the ad-level link, which falls back to the user's saved website). The ad runs from one of the user's Facebook Pages: pass pageName to pick by name; with exactly one enabled page it's used automatically — a numeric pageId is not needed. Objective: traffic (default), sales (auto-attaches the account's Meta pixel), awareness, or engagement — if the user cares about the goal but hasn't said which, ASK; otherwise default to traffic. TARGETING: never interrogate the user about targeting — only set the params they explicitly asked for (resolve ids via search_ad_targeting); everything else uses defaults and the preview states exactly what was applied (marked '(default)') so the user can adjust before confirming. Two-step: call without confirmToken for a preview + token, then again with the confirmToken to create it. EDIT AN EXISTING AD: pass editAdId plus the new message/headline/link to change a live or paused ad's copy in place (no new campaign; before-vs-after preview, then confirm; the edited ad re-enters Meta review). RADIUS TARGETING: radiusAddress + radiusKm target a circle around a street address ('everyone within 10 km of my shop'). RETARGETING: set retargetWebsiteVisitors:true to CREATE a website-visitors audience from the account's Meta pixel and target this ad at it in one step ('retarget people who visited my site') — optional retargetRetentionDays (1-180, default 30) and retargetExcludePurchasers; the audience spends nothing by itself. To target an audience that ALREADY exists instead, pass its id via audienceIds (from search_ad_targeting kind 'audiences').
The description explains the capability, when to use it, and what to expect.
Inputs86/100
35 of 37 inputs have descriptions. Add descriptions to the missing inputs, including where to obtain IDs and how to supply values.
accountId
Connected Meta ad account id, e.g. "act_1234567890"
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
name
Campaign name (REQUIRED to launch; omit in edit mode)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
dailyBudgetUsd
Daily budget in the ad account billing currency (REQUIRED to launch; omit in edit mode)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
editAdId
EDIT MODE: the id of an EXISTING Meta ad whose copy should be changed (get ids from list_campaigns drill-down or the campaigns dashboard). When set, NOTHING new is created: message/headline/link become the ad's NEW copy, a preview shows before vs after, and on confirm the ad is updated in place (it re-enters Meta review before delivering again). name/dailyBudgetUsd/cards are ignored in this mode.
Clear enough to supply this argument.
headline
EDIT MODE only: the new headline for the ad being edited
Clear enough to supply this argument.
cards › items › creativeName
Name of an IMAGE or VIDEO in the user's Creative Library (see list_my_creatives) — the preferred way to supply the card
Clear enough to supply this argument.
cards › items › creativeId
Creative library id (alternative to creativeName)
Clear enough to supply this argument.
cards › items › imageUrl
Direct https URL to the user's OWN image (alternative to the library)
Clear enough to supply this argument.
cards › items › videoUrl
Direct https URL to the user's OWN video (alternative to the library). A video card must be the ONLY card.
Clear enough to supply this argument.
cards › items › headline
Card headline shown under the image (carousel) or as the ad headline (single image/video)
Clear enough to supply this argument.
cards › items › description
Smaller card sub-text (carousel cards only)
Clear enough to supply this argument.
cards › items › link
Per-card destination URL (defaults to the ad-level link)
Clear enough to supply this argument.
message
Primary text shown above the creative
Clear enough to supply this argument.
link
Destination URL for the ad (defaults to the user's saved website)
Clear enough to supply this argument.
ctaType
Call-to-action button, e.g. LEARN_MORE (default), SHOP_NOW, SIGN_UP, GET_OFFER, BOOK_NOW, CALL_NOW, WHATSAPP_MESSAGE. CALL_NOW makes a click-to-call ad and REQUIRES phoneNumber. WHATSAPP_MESSAGE makes a click-to-WhatsApp ad — pass the wa.me link as `link` and the ad set is pointed at the chat automatically. Meta rejects buttons it does not offer for the objective/format; if that happens, LEARN_MORE, SHOP_NOW, SIGN_UP, BOOK_NOW and MESSAGE_PAGE are safe everywhere.
Clear enough to supply this argument.
phoneNumber
Phone number for a CALL_NOW (click-to-call) ad, in full international format with the country code, e.g. "+998 90 123 45 67". Ask the user for the country code if they give a local number — Meta cannot dial without it.
Clear enough to supply this argument.
pageName
The Facebook Page to run the ad from, by name. Omit if the user has only one page enabled — it is used automatically.
Clear enough to supply this argument.
pageId
Numeric Facebook Page id. Prefer pageName when the Page is listed. IMPORTANT: if a launch just failed because Meta returned no Pages for the ad account (common when the Page sits in a Business portfolio, or the ad account has never run an ad), ASK the user for their numeric Page id — Meta Business Settings > Pages, or the number at the end of the Page URL — and pass it here. An id given this way is trusted and launched directly; Meta itself checks whether they may advertise with it.
Clear enough to supply this argument.
objective
The campaign goal, defaults to traffic. Sales optimizes for purchases via the account's Meta pixel (attached automatically; a clear error explains if the account has none). Leads means WEBSITE leads via the pixel Lead event by default — UNLESS you pass leadFormId, which switches it to an on-Meta instant form (no pixel).
Clear enough to supply this argument.
countries
ISO-2 country codes to target, e.g. ["US","GB"]. Defaults to US when no geo is given. IGNORED when cityKeys or regionKeys are set — Meta rejects a country combined with a city inside it, so pick ONE granularity.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
cityKeys
City keys from search_ad_targeting (kind "locations"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
regionKeys
Region/state keys from search_ad_targeting (kind "locations"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations).
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
radiusAddress
RADIUS targeting: a street address or place to target AROUND (e.g. "Hoofdstraat 12, Amsterdam"). Meta locates the address itself — no lookup needed. When set, all other geo params are ignored (one circle IS the geography). Use when the user wants "within X km of my shop/city/address".
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
radiusKm
Radius in km around radiusAddress (1–80, default 15). Only meaningful together with radiusAddress.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
ageMin
Minimum age (18–65)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
ageMax
Maximum age (18–65; 65 means 65+)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
gender
Gender targeting (default all)
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
interests › items › id
Not provided
Missing description. Explain what this value means and how to supply it.
interests › items › name
Not provided
Missing description. Explain what this value means and how to supply it.
audienceIds
Existing Custom Audience ids from search_ad_targeting (kind "audiences") — this is how retargeting works.
Remove validation rules already expressed in this field’s schema; describe its meaning and usage instead.
devicePlatforms
Device platforms to target, e.g. ["mobile"]. ONLY set this when the user explicitly asks to target by device — NEVER ask the user about device targeting; the default (all devices) is correct for most launches, and the preview will state it.
Clear enough to supply this argument.
userOs
Mobile OS targeting, e.g. ["iOS"] to reach iPhone/iPad users only (implies mobile-only delivery). ONLY set this when the user explicitly asks for it (e.g. "target iOS users", "iPhone owners") — NEVER prompt the user about OS or device targeting.
Clear enough to supply this argument.
retargetWebsiteVisitors
When true, CREATE a website-visitors audience from the account's Meta pixel and target this ad at it (retargeting). Needs a pixel on the account — a clear error explains if there is none. The audience spends nothing by itself.
Clear enough to supply this argument.
retargetRetentionDays
Retargeting window in days for retargetWebsiteVisitors, 1–180 (default 30)
Clear enough to supply this argument.
retargetExcludePurchasers
Retargeting only: exclude people who purchased in the last 180 days
Clear enough to supply this argument.
leadFormId
On-Meta lead ads: the id of an instant (lead) form the user ALREADY built in Meta Ads Manager. Only valid with objective "leads". The ad then captures leads INSIDE Facebook/Instagram via that form (no pixel, no website hop) — ideal when conversions happen off-site or there is no pixel. Prerequisites the user handles once: their Facebook Page must have accepted Facebook's Lead Generation Terms, and the ad needs an external destination link. A clear steer explains if either is missing.
Clear enough to supply this argument.
confirmToken
Token from the preview step
Clear enough to supply this argument.
Annotations75/100
Declare idempotentHint based on the tool’s actual behavior.
{
"title": "Launch Meta Ad (own images, video, or carousel)",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
Output schema0/100
No output schema is declared. Add one for structured results so clients can interpret returned fields.
Not declared
Original tool metadata
{
"name": "launch_meta_ad",
"title": "Launch Meta Ad (own images, video, or carousel)",
"description": "Launch the user's OWN images or videos as a real, PAUSED ad in their connected Meta (Facebook/Instagram) account — campaign + ad set + creative + ad, all paused (no spend until they resume). ONE image card = a single-image ad; 2–10 image cards = a CAROUSEL in the exact card order given; ONE video card = a VIDEO ad. MIXED cards (a video plus images, or several videos, 2–10 total) = a CREATIVE TEST: each card becomes its OWN ad inside ONE shared ad set, and Meta shifts the ad set's budget toward whichever ad performs — use this when the user wants several creatives competing (e.g. 'test my video against these two photos'). Use this when the user has their own finished creatives ('launch my carousel', 'run this image I made', 'launch my video on Facebook') — for launching an image clone made in the AdWhispr app use launch_cloned_ad instead; finished AI videos made in the app land in the Creative Library and launch HERE by creativeName. WHERE CREATIVES COME FROM: the user's Creative Library — reference each card by creativeName (see list_my_creatives; images and videos both work). If their files aren't uploaded yet, send them to https://adwhispr.com/dashboard/creatives to upload (drag & drop), then have them tell you when done and use list_my_creatives to find the names. A direct https imageUrl/videoUrl the user owns also works. NEVER use competitor images or ad-library assets. On confirm, a video is uploaded into the ad account and Meta processes it (~30s extra; if processing outruns the call, the campaign + ad set are still created and the tool says how to finish). Per-card headline/description/link are optional (link falls back to the ad-level link, which falls back to the user's saved website). The ad runs from one of the user's Facebook Pages: pass pageName to pick by name; with exactly one enabled page it's used automatically — a numeric pageId is not needed. Objective: traffic (default), sales (auto-attaches the account's Meta pixel), awareness, or engagement — if the user cares about the goal but hasn't said which, ASK; otherwise default to traffic. TARGETING: never interrogate the user about targeting — only set the params they explicitly asked for (resolve ids via search_ad_targeting); everything else uses defaults and the preview states exactly what was applied (marked '(default)') so the user can adjust before confirming. Two-step: call without confirmToken for a preview + token, then again with the confirmToken to create it. EDIT AN EXISTING AD: pass editAdId plus the new message/headline/link to change a live or paused ad's copy in place (no new campaign; before-vs-after preview, then confirm; the edited ad re-enters Meta review). RADIUS TARGETING: radiusAddress + radiusKm target a circle around a street address ('everyone within 10 km of my shop'). RETARGETING: set retargetWebsiteVisitors:true to CREATE a website-visitors audience from the account's Meta pixel and target this ad at it in one step ('retarget people who visited my site') — optional retargetRetentionDays (1-180, default 30) and retargetExcludePurchasers; the audience spends nothing by itself. To target an audience that ALREADY exists instead, pass its id via audienceIds (from search_ad_targeting kind 'audiences').",
"inputSchema": {
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"accountId"
],
"properties": {
"link": {
"type": "string",
"description": "Destination URL for the ad (defaults to the user's saved website)"
},
"name": {
"type": "string",
"description": "Campaign name (REQUIRED to launch; omit in edit mode)"
},
"cards": {
"type": "array",
"items": {
"type": "object",
"properties": {
"link": {
"type": "string",
"description": "Per-card destination URL (defaults to the ad-level link)"
},
"headline": {
"type": "string",
"description": "Card headline shown under the image (carousel) or as the ad headline (single image/video)"
},
"imageUrl": {
"type": "string",
"description": "Direct https URL to the user's OWN image (alternative to the library)"
},
"videoUrl": {
"type": "string",
"description": "Direct https URL to the user's OWN video (alternative to the library). A video card must be the ONLY card."
},
"creativeId": {
"type": "string",
"description": "Creative library id (alternative to creativeName)"
},
"description": {
"type": "string",
"description": "Smaller card sub-text (carousel cards only)"
},
"creativeName": {
"type": "string",
"description": "Name of an IMAGE or VIDEO in the user's Creative Library (see list_my_creatives) — the preferred way to supply the card"
}
},
"additionalProperties": false
},
"maxItems": 10,
"minItems": 1,
"description": "REQUIRED to launch (ignored in edit mode). The ad creatives IN ORDER: 1 image card = single-image ad, 2–10 image cards = carousel, 1 video card = video ad, MIXED cards (video + images, or several videos) = separate ads competing in ONE ad set (creative test). Each card needs creativeName, creativeId, imageUrl, or videoUrl."
},
"ageMax": {
"type": "integer",
"maximum": 65,
"minimum": 18,
"description": "Maximum age (18–65; 65 means 65+)"
},
"ageMin": {
"type": "integer",
"maximum": 65,
"minimum": 18,
"description": "Minimum age (18–65)"
},
"gender": {
"enum": [
"all",
"male",
"female"
],
"type": "string",
"description": "Gender targeting (default all)"
},
"pageId": {
"type": "string",
"description": "Numeric Facebook Page id. Prefer pageName when the Page is listed. IMPORTANT: if a launch just failed because Meta returned no Pages for the ad account (common when the Page sits in a Business portfolio, or the ad account has never run an ad), ASK the user for their numeric Page id — Meta Business Settings > Pages, or the number at the end of the Page URL — and pass it here. An id given this way is trusted and launched directly; Meta itself checks whether they may advertise with it."
},
"userOs": {
"type": "array",
"items": {
"enum": [
"iOS",
"Android"
],
"type": "string"
},
"description": "Mobile OS targeting, e.g. [\"iOS\"] to reach iPhone/iPad users only (implies mobile-only delivery). ONLY set this when the user explicitly asks for it (e.g. \"target iOS users\", \"iPhone owners\") — NEVER prompt the user about OS or device targeting."
},
"ctaType": {
"type": "string",
"description": "Call-to-action button, e.g. LEARN_MORE (default), SHOP_NOW, SIGN_UP, GET_OFFER, BOOK_NOW, CALL_NOW, WHATSAPP_MESSAGE. CALL_NOW makes a click-to-call ad and REQUIRES phoneNumber. WHATSAPP_MESSAGE makes a click-to-WhatsApp ad — pass the wa.me link as `link` and the ad set is pointed at the chat automatically. Meta rejects buttons it does not offer for the objective/format; if that happens, LEARN_MORE, SHOP_NOW, SIGN_UP, BOOK_NOW and MESSAGE_PAGE are safe everywhere."
},
"message": {
"type": "string",
"description": "Primary text shown above the creative"
},
"cityKeys": {
"type": "array",
"items": {
"type": "string"
},
"description": "City keys from search_ad_targeting (kind \"locations\"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations)."
},
"editAdId": {
"type": "string",
"description": "EDIT MODE: the id of an EXISTING Meta ad whose copy should be changed (get ids from list_campaigns drill-down or the campaigns dashboard). When set, NOTHING new is created: message/headline/link become the ad's NEW copy, a preview shows before vs after, and on confirm the ad is updated in place (it re-enters Meta review before delivering again). name/dailyBudgetUsd/cards are ignored in this mode."
},
"headline": {
"type": "string",
"description": "EDIT MODE only: the new headline for the ad being edited"
},
"pageName": {
"type": "string",
"description": "The Facebook Page to run the ad from, by name. Omit if the user has only one page enabled — it is used automatically."
},
"radiusKm": {
"type": "number",
"maximum": 80,
"minimum": 1,
"description": "Radius in km around radiusAddress (1–80, default 15). Only meaningful together with radiusAddress."
},
"accountId": {
"type": "string",
"description": "Connected Meta ad account id, e.g. \"act_1234567890\""
},
"countries": {
"type": "array",
"items": {
"type": "string",
"maxLength": 2,
"minLength": 2
},
"description": "ISO-2 country codes to target, e.g. [\"US\",\"GB\"]. Defaults to US when no geo is given. IGNORED when cityKeys or regionKeys are set — Meta rejects a country combined with a city inside it, so pick ONE granularity."
},
"interests": {
"type": "array",
"items": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
},
"additionalProperties": false
},
"description": "Meta interest ids from search_ad_targeting (kind \"interests\"). Never invent ids — always search first and confirm the picks with the user."
},
"objective": {
"enum": [
"traffic",
"sales",
"leads",
"awareness",
"engagement"
],
"type": "string",
"description": "The campaign goal, defaults to traffic. Sales optimizes for purchases via the account's Meta pixel (attached automatically; a clear error explains if the account has none). Leads means WEBSITE leads via the pixel Lead event by default — UNLESS you pass leadFormId, which switches it to an on-Meta instant form (no pixel)."
},
"leadFormId": {
"type": "string",
"description": "On-Meta lead ads: the id of an instant (lead) form the user ALREADY built in Meta Ads Manager. Only valid with objective \"leads\". The ad then captures leads INSIDE Facebook/Instagram via that form (no pixel, no website hop) — ideal when conversions happen off-site or there is no pixel. Prerequisites the user handles once: their Facebook Page must have accepted Facebook's Lead Generation Terms, and the ad needs an external destination link. A clear steer explains if either is missing."
},
"regionKeys": {
"type": "array",
"items": {
"type": "string"
},
"description": "Region/state keys from search_ad_targeting (kind \"locations\"). Never invent keys. When set, countries are ignored (Meta forbids overlapping locations)."
},
"audienceIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "Existing Custom Audience ids from search_ad_targeting (kind \"audiences\") — this is how retargeting works."
},
"phoneNumber": {
"type": "string",
"description": "Phone number for a CALL_NOW (click-to-call) ad, in full international format with the country code, e.g. \"+998 90 123 45 67\". Ask the user for the country code if they give a local number — Meta cannot dial without it."
},
"confirmToken": {
"type": "string",
"description": "Token from the preview step"
},
"radiusAddress": {
"type": "string",
"description": "RADIUS targeting: a street address or place to target AROUND (e.g. \"Hoofdstraat 12, Amsterdam\"). Meta locates the address itself — no lookup needed. When set, all other geo params are ignored (one circle IS the geography). Use when the user wants \"within X km of my shop/city/address\"."
},
"dailyBudgetUsd": {
"type": "number",
"description": "Daily budget in the ad account billing currency (REQUIRED to launch; omit in edit mode)",
"exclusiveMinimum": 0
},
"devicePlatforms": {
"type": "array",
"items": {
"enum": [
"mobile",
"desktop"
],
"type": "string"
},
"description": "Device platforms to target, e.g. [\"mobile\"]. ONLY set this when the user explicitly asks to target by device — NEVER ask the user about device targeting; the default (all devices) is correct for most launches, and the preview will state it."
},
"retargetRetentionDays": {
"type": "integer",
"maximum": 180,
"minimum": 1,
"description": "Retargeting window in days for retargetWebsiteVisitors, 1–180 (default 30)"
},
"retargetWebsiteVisitors": {
"type": "boolean",
"description": "When true, CREATE a website-visitors audience from the account's Meta pixel and target this ad at it (retargeting). Needs a pixel on the account — a clear error explains if there is none. The audience spends nothing by itself."
},
"retargetExcludePurchasers": {
"type": "boolean",
"description": "Retargeting only: exclude people who purchased in the last 180 days"
}
},
"additionalProperties": false
},
"annotations": {
"title": "Launch Meta Ad (own images, video, or carousel)",
"readOnlyHint": false,
"openWorldHint": true,
"destructiveHint": false
}
}
Loading score analytics…
Put your MCP to the test
A few tasks worth trying with this server, chosen from its reviewed tools. These have not been run.
01Search BrandsSearch for brands tracked in AdWhispr by name.
02Research KeywordsResearch Google Search keywords for any topic, product, or seed terms.
03Research Competitor KeywordsGiven a competitor's URL or domain, return the keywords Google associates with that page's CONTENT — a content/positioning proxy for what that site is about…
04Get Brand AdsGet ads for a specific brand with enrichment data (hooks, formats, tones, performance scores, thumbnails, video links).
add_brandadd_productclear_my_brandclone_tiktok_adcompare_brandsconnect_ad_accountfind_competitorsgenerate_briefget_account_performanceget_brand_adsget_brand_statsget_my_brand+21 more
adwhispr setup, tools, quality score, publishing readiness, and alternatives.
How do I add adwhispr to Claude, ChatGPT, or Cursor?
Add adwhispr to Claude, ChatGPT, or Cursor by connecting its remote MCP URL in each client's MCP settings. In Claude, add a custom connector. In ChatGPT, add an MCP app. In Cursor, add an MCP server under Settings. The MCP URL is https://adwhispr.com/api/claude/mcp. This server requires OAuth, so complete the login prompt after you connect.
Is adwhispr MCP ready for ChatGPT and Claude?
As of October 6, 2026, adwhispr scores 88/100 on Manufact's MCP publishing checklist. The scan does not yet meet ChatGPT publishing checks and meets Claude publishing checks. Passing these checks does not guarantee marketplace approval.
How clear is adwhispr's MCP tool documentation?
As of October 6, 2026, adwhispr scores 81/100 in Manufact's review of tool titles, descriptions, input and output schemas, and behavior annotations. The review covers 34 of 34 discovered tools. The quality score measures documentation clarity; runtime behavior and marketplace readiness require separate checks.
What tools does the adwhispr MCP server provide?
adwhispr lists 33 MCP tools, including add_brand, add_product, clear_my_brand, clone_tiktok_ad, compare_brands, connect_ad_account, find_competitors, generate_brief, get_account_performance, get_brand_ads, get_brand_stats, and get_my_brand.
What are the best alternatives to adwhispr?
As of October 20, 2026, alternatives to adwhispr in marketing-seo on the Manufact MCP leaderboard include OpenAffiliate, Buzzfy, Airefs AI Visibility, TalkGenAI, and RankControl.
Does adwhispr MCP require authentication?
adwhispr requires authentication. Connect it in Claude, ChatGPT, or Cursor and complete the OAuth login prompt.
How can adwhispr improve its MCP documentation?
compare_brands is the lowest-scoring reviewed tool at 56/100. Resolve the mismatch between this description and its schema constraints. Open its review for feedback and a copyable fix prompt, then rerun the documentation review after updating your tool metadata.
Who develops adwhispr?
adwhispr is developed by AdWhispr. It is listed as partner on the Claude connector directory.
Not your MCP?
Review any public or OAuth MCP server for protocol compatibility, tool documentation, and ChatGPT and Claude publishing readiness. No account required.