{"$schema":"https://static.modelcontextprotocol.io/schemas/mcp-server-card/v1.json","name":"com.winandscale/winandscale","title":"Win & Scale","version":"0.1.0","description":"Meta ads for AI agents. Find the ads that pay: your agent reads what each creative is and what it bought, briefs the next test, and launches every ad paused. Turning spend on is always your call.","websiteUrl":"https://winandscale.com","icons":[{"src":"https://winandscale.com/brand/logo-1024.png","mimeType":"image/png","sizes":["1024x1024"]}],"protocolVersion":"2025-11-25","serverInfo":{"name":"winandscale-mcp-server","version":"0.1.0","title":"Win & Scale"},"serverUrl":"https://winandscale.com/api/mcp","transport":{"type":"streamable-http","endpoint":"/api/mcp"},"remotes":[{"type":"streamable-http","url":"https://winandscale.com/api/mcp"}],"capabilities":{"tools":{"listChanged":true}},"authentication":{"required":true,"schemes":["oauth2","bearer"],"protectedResourceMetadata":"https://winandscale.com/.well-known/oauth-protected-resource/api/mcp"},"instructions":"You are connected to Win & Scale. The authenticated workspace holds ONE Meta ad account, read from a nightly warehouse, written to as PAUSED drafts. Tools are `meta_*` and return `{ ok: true, ... }` or `{ ok: false, error }`.\n\n## Orientation\n- A session reaches the whole workspace (an `rsk_` key may be narrower). Call `meta_get_workspace` first: `adAccountId` is the account every call hits (`meta_switch_workspace` changes it).\n- Money is real. `meta_launch_ads` creates campaign, ad set and ads PAUSED; `meta_activate` is the money-moving flip and needs the human's go-ahead.\n- Two kinds of numbers. The WAREHOUSE (`meta_get_overview`, `meta_get_performance_cube`…) is daily; its `coverage` says from when; earlier days read zero, not \"no spend\". The HISTORY (`meta_get_account_history`) is lifetime per ad. `meta_get_history_winners` and `meta_get_cross_analysis` read either (`window`).\n- What a creative IS lives in stored Values (angle, persona, offer, format, hook…); the ad name is a hint, not the record.\n- Read `meta_get_strategy` and `meta_list_learnings` before any brief or copy. Save an operator's copy correction with `meta_update_strategy` (`mode: \"suggest\"`) or it is lost.\n\n## Evidence first\nStart every review with `meta_get_evidence_health` and quote its warnings (stale sync, coverage gaps, untagged spend, poster-only videos, unseen outcomes). Compare funnels on their own goal, not Meta's \"Results\". Low delivery is inconclusive, not a loss. Hook rate is not the goal.\n\n## Golden paths\n**What worked**: `meta_get_account_history` (`meta_pull_account_history` if empty) → `meta_get_history_winners({ window })`: verdicts, Traits, `nextTests`. `meta_get_cross_analysis` pivots two Dimensions; `meta_get_performance_cube` splits by ad set or country.\n\n**Library** (/app/library) files: `meta_list_creatives` → `meta_get_creative` → `meta_tag_creatives` / `meta_set_creative_links` to correct, `meta_update_creative` renames, `meta_delete_creatives` removes. Values (audiences, messages, formats, offers…): `meta_list_taxonomy` → `meta_create_taxonomy_value` / `meta_update_taxonomy_value` (rename, archive) / `meta_merge_taxonomy_values` for two names of one idea. Copy: `meta_draft_messaging` or `meta_save_messaging` → `meta_set_messaging_status` (approve / reject; a rejected line is not redrafted).\n\n**Briefs › Tests** — the learning loop: brief a Next test (`meta_save_briefs`, `meta_list_briefs`) → `meta_create_test` commits it (frozen hypothesis and rule) → `meta_generate_draft` / `meta_launch_ads` with its `testId` (still PAUSED) → after delivery, `meta_observe_test` → `meta_conclude_test` with a verdict. Supersede a test, never rewrite it.\n\n**Sources**: `meta_add_research_source` / `meta_refresh_research_source` → `meta_list_verbatims` → `meta_link_verbatims` to a persona or angle → `meta_get_strategy_rollup`.\n\n**Live ads**: `meta_get_overview` (`meta_sync_now` if stale, `meta_backfill_insights` for older days) → `meta_suggest_next` (cut / keep / duplicate / iterate / watch; targets via `meta_set_thresholds`) → `meta_get_breakdowns` (age / country / placement), fixed with `meta_update_ad_set_targeting` (restarts learning). Purchases and ROAS need the purchase pixel.\n\n**Launch**: `meta_list_campaigns` → `meta_launch_ads` (`briefId` / `testId`; `meta_list_pages_and_pixels` for a Page) → show its `strategyCautions` → the human reviews in Ads Manager or Ads › Launches (/app/ads/launches) → `meta_activate`. Instant forms: `meta_list_lead_forms` / `meta_create_lead_form` → `OUTCOME_LEADS` with `adSet.leadForm` + `copy.leadFormId` → `meta_send_test_lead` before activating.\n\n## Rules\n- Ad names are `id__locale__format__persona__angle__concept__variant`; launching refuses one that does not parse.\n- Never activate without the human saying so in this conversation; the same for `meta_set_ad_status` ACTIVE. A `cut` verdict is advice: the human picks what to pause.\n- A test, a brief or an observation never touches delivery.","tools":[{"name":"meta_get_workspace","title":"getWorkspace","description":"Which workspace this session is on — call it first, and before any write. Returns the workspace (orgId, name, your role, `adAccountId`: the Meta ad account every read and write here hits, null when not connected), the user it acts as (id, email) and the principal (`human` over OAuth, `agent` for an rsk_ API key, which is pinned to one workspace). Wrong account? meta_list_workspaces, then meta_switch_workspace.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_workspaces","title":"listWorkspaces","description":"Every workspace you are a member of — orgId, name, your role, its connected `adAccountId` (null when not connected) — with `active` marking the one this session is on. An rsk_ API key sees only its own workspace.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_overview","title":"getOverview","description":"Account totals (spend, View Content → Add to Cart, cost per ATC, leads — form vs website — and cost per lead, conversations), the daily series, campaigns and the top ads for a period, from the last sync. `funnel` is the operator's funnel over the totals — each step's count, its rate from the step before, and spend per step — and `topAds` — live ads only, delivering now — is ranked by its deepest step; speak in those steps. `campaigns` lists every campaign that spent, `live` marking the ones with a delivering ad; `notLive` counts the paused ads the totals still include. Start here for anything inside the last 30 days; older than that is meta_get_account_history. Purchases/ROAS are blank when that pixel did not fire.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"period":{"default":"7d","description":"Reporting window. 7d/14d/30d are the last N complete days, ending yesterday (as in Ads Manager); weeks are Monday-based, this_week runs to today. UTC.","type":"string","enum":["7d","14d","30d","this_week","last_week"]},"since":{"description":"Custom window start, YYYY-MM-DD, UTC. Overrides `period`. The result's `coverage` says what the warehouse holds.","type":"string"},"until":{"description":"Custom window end, YYYY-MM-DD, inclusive. Default today.","type":"string"}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_campaigns","title":"listCampaigns","description":"Every campaign with its ad sets — ids, names, statuses and effective statuses, objectives, and each ad set's `conversionEvent` (the pixel event it optimises for: ADD_TO_CART, LEAD, PURCHASE…; null for instant forms, messaging and traffic) and `destinationType`. Use the ids for launches.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_ad_performance","title":"getAdPerformance","description":"Per-ad metrics for a period: spend, View Content, Add to Cart, VC→ATC rate, cost per ATC, leads (form / website) and cost per lead, conversations, plus purchase ROAS/CPA/AOV when that pixel fired, CPC (link), landing page views (cost, rate per link click), click→lead rate, checkouts and registrations with their costs, hook/hold, video retention (25/50/75/95/100% view rates over 3-second plays, average watch time — null on statics and on days synced before retention was stored), and the persona / angle / concept parsed from the ad name. `status` is Meta's effective status — ACTIVE means delivering.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"period":{"default":"7d","description":"Reporting window. 7d/14d/30d are the last N complete days, ending yesterday (as in Ads Manager); weeks are Monday-based, this_week runs to today. UTC.","type":"string","enum":["7d","14d","30d","this_week","last_week"]},"since":{"description":"Custom window start, YYYY-MM-DD, UTC. Overrides `period`. The result's `coverage` says what the warehouse holds.","type":"string"},"until":{"description":"Custom window end, YYYY-MM-DD, inclusive. Default today.","type":"string"},"sort":{"default":"spend","type":"string","enum":["spend","roas","cpa","purchases","hook","atc","leads","costPerLead","conversations"]},"limit":{"default":50,"type":"integer","minimum":1,"maximum":200}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_breakdowns","title":"getBreakdowns","description":"LIVE Meta call: performance for the period (or any since/until within Meta's 37 months — this one does not need the warehouse) broken down by age, gender, country, publisher_platform or device_platform, account-wide (cached ten minutes). With `adId`, ONE ad's split as the creative sheet shows it — `by` placement (platform × position, e.g. IG Reels; under 2% of spend folded into Other) or age_gender — counted on that ad's resolved goal event with its target, plus the sheet's one-line takeaway (cached for hours per ad). With `adId` and by: retention, the video's retention curve (share of viewers still watching, per second when the upload's length is known), weighted by plays; empty for a static.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"period":{"default":"7d","description":"Reporting window. 7d/14d/30d are the last N complete days, ending yesterday (as in Ads Manager); weeks are Monday-based, this_week runs to today. UTC.","type":"string","enum":["7d","14d","30d","this_week","last_week"]},"since":{"description":"Custom window start, YYYY-MM-DD, UTC. Overrides `period`. The result's `coverage` says what the warehouse holds.","type":"string"},"until":{"description":"Custom window end, YYYY-MM-DD, inclusive. Default today.","type":"string"},"by":{"type":"string","enum":["age","gender","country","publisher_platform","device_platform","placement","age_gender","retention"]},"adId":{"description":"One ad's breakdown instead of the account's. Needs by: placement, age_gender or retention.","type":"string","pattern":"^\\d{6,}$"}},"required":["by"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_account_history","title":"getAccountHistory","description":"Everything that ever ran on this account, most lifetime spend first: headline, primary text, destination URL / instant form, CTA, the funnel it fed (instant_form, website, messaging, profile, traffic) and its result, with LIFETIME spend, clicks, CPC, leads (form vs website), conversations, Add to Cart and cost per result. Numbers are per-ad lifetime totals, not a time series — for a period use meta_get_overview. Also returns the baseline per funnel and per landing page, and a pace check that holds each live funnel to its historical click→lead rate — the fastest way to tell a relaunch that is early from one spending into the void. `pull` says whether a scheduled pull is waiting on Meta's quota. Needs meta_pull_account_history once per account.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"limit":{"default":40,"type":"integer","minimum":1,"maximum":200},"funnel":{"type":"string","enum":["instant_form","website","messaging","profile","traffic","unknown"]}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_history_winners","title":"getHistoryWinners","description":"What wins, what loses, and what to make next — the verdicts behind Library values and Briefs' Next tests, over MCP. Judges every creative (default grouping; or headline, hook line, landing page, market, language) within its funnel against same-market peers on the funnel's GOAL (purchase, else add to cart — a completed calculator on a calculator funnel — else website leads; form leads for instant forms; conversations for messaging; link clicks for profile and traffic). `window` is 30d / 90d (default) / 180d from the daily warehouse, or lifetime from the history snapshot. `shared.winning` / `shared.losing` are Traits — Values of the house taxonomy stored against each creative (angle, persona, awareness, offer, pain, format, hook, talent, visual element) plus the ad's copy devices, CTA, language, market and landing page — measured by what their carriers bought against what their spend should have bought at the non-carriers' rate: `lift`, share of goals vs share of spend, distinct creatives, winners carrying it, confidence, and in how many markets it held. `traits` (ids from `traitIndex`) narrows the returned groups to creatives carrying all of them. `nextTests` are ranked iterations (a winner with one Dimension changed) and explorations (winning Values never combined, under-funded promising Values, Values competitors run, levers customers asked for), each with its computed evidence, its `basis` (account / customers / competitors), `limits` (what could make the evidence mislead — quote them) and `reverseIf`, and `prior`: committed Tests on the same lesson that already concluded. Commit one with meta_create_test. A winner's `assetId` feeds meta_get_recipe / meta_generate_draft.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"window":{"default":"90d","type":"string","enum":["30d","90d","180d","lifetime"]},"groupBy":{"default":"creative","type":"string","enum":["creative","headline","hook","landing","market","language"]},"funnel":{"type":"string","enum":["instant_form","website","messaging","profile","traffic","unknown"]},"verdict":{"type":"string","enum":["winner","average","loser","unproven"]},"traits":{"maxItems":8,"type":"array","items":{"type":"string"}},"sort":{"default":"spend","type":"string","enum":["spend","costPerGoal","goals","convertScore","clickScore"]},"limit":{"default":20,"type":"integer","minimum":1,"maximum":60}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_cross_analysis","title":"getCrossAnalysis","description":"Cross analysis inside ONE funnel: one Dimension (rows) or two against each other (rows × columns) — angle, persona, awareness, offer, pain, format, hook, talent, visual, copy, cta, language, market, landing, media. Each cell: distinct creatives, winners, spend, goals, cost per goal and lift (goals against what the spend would have bought at the funnel's own rate). A missing cell is an untested combination. Same windows as meta_get_history_winners.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"rows":{"type":"string","enum":["angle","persona","awareness","offer","offer_type","pain","season","asset_type","format","hook","headline_tactic","talent","visual","copy","cta","language","market","landing","media"]},"columns":{"type":"string","enum":["angle","persona","awareness","offer","offer_type","pain","season","asset_type","format","hook","headline_tactic","talent","visual","copy","cta","language","market","landing","media"]},"funnel":{"description":"Default: the funnel with the most spend.","type":"string","enum":["instant_form","website","messaging","profile","traffic","unknown"]},"window":{"default":"90d","type":"string","enum":["30d","90d","180d","lifetime"]}},"required":["rows"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_creatives","title":"listCreatives","description":"The creatives (and swipes) an agent strategist should review, most lifetime spend first, each with its Values on every creative Dimension (draft ones marked), the Dimensions the classifier was unsure of, its overall confidence and rationale, and its lifetime performance per funnel (verdict, goal, cost per goal vs peers). `filter`: needs_review (default — spent and unclassified, unsure or carrying drafts; plus swipes in that state), unclassified, drafts, unsure, top_spend, all. Look at one with meta_get_creative; correct many with meta_tag_creatives.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"filter":{"default":"needs_review","type":"string","enum":["needs_review","all","unclassified","drafts","unsure","top_spend"]},"subject":{"default":"all","type":"string","enum":["asset","swipe","all"]},"limit":{"default":25,"type":"integer","minimum":1,"maximum":100},"offset":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_creative","title":"getCreative","description":"One creative (or swipe) to LOOK at: its image — the 600px feed thumbnail when Meta still serves it, else our poster; a video comes back as ONE frame, say so when you judge its hook — plus its Values, confidence, rationale and performance. For an upload with a stored transcript, `transcript` is what is said and when (language, hasSpeech, segments of startSeconds + verbatim text); null when none is stored — meta_transcribe_creative makes one for a library video. Use it before correcting a Value you cannot verify from text alone.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"subject":{"default":"asset","type":"string","enum":["asset","swipe"]},"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"image":{"default":true,"type":"boolean"}},"required":["id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_briefs","title":"listBriefs","description":"Briefs on the Briefs board (/app/briefs) — board briefs and the ones written from Next tests — newest first. Each: id, title, status (draft → ready → in_production → live → learned, or dismissed), concept, copy (hook, headline, primary text, CTA, timed script), visual approach, reference, deliverables, success metric, scope (Values), cited learning ids, who wrote it, and what was made from it (drafts, assets, launches, first delivery, Tests). Status follows the work: a draft or asset puts a brief in production, an ad's first delivery makes it live, its Test's conclusion makes it learned. Dismissed briefs are left out unless asked for.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"status":{"type":"string","enum":["draft","ready","in_production","live","learned","dismissed"]},"owner":{"default":"anyone","description":"me = the human this session acts for; agent = written over MCP or the API.","type":"string","enum":["anyone","me","agent","others"]},"dimension":{"type":"string","enum":["angle","persona","awareness","offer","offer_type","pain","season","asset_type","format","hook","headline_tactic","talent","visual"]},"valueId":{"description":"Briefs scoped to this Value.","type":"string","minLength":1,"maxLength":100},"includeDismissed":{"default":false,"type":"boolean"},"limit":{"default":50,"type":"integer","minimum":1,"maximum":200}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_brief","title":"getBrief","description":"One brief in full — by its id, or by its test id (`brief:<id>`, `note:<slug>`, a Next test id): every field, the learnings it cites (statement and status), and what was made from it. Read it before meta_update_brief.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":300}},"required":["id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_evidence_health","title":"getEvidenceHealth","description":"Before judging anything: is the evidence fit for the comparison? Sync freshness, warehouse coverage of the window, ads with spend that the history has not pulled (counted, never judged), past uploads missing from the library, the share of spend on creatives with no Values, videos read from their poster only (no scene-level claim is supported for those), draft Values on winners, the goal each funnel is judged on and how many creatives could be judged, and the outcomes Meta cannot see (qualified leads, revenue, margin). Each check says what it does to the analysis and what would close it. Read it first in any review, and quote its warnings.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"window":{"default":"90d","type":"string","enum":["30d","90d","180d","lifetime"]}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_tests","title":"listTests","description":"Committed Tests — Next tests the operator decided to run — newest first: hypothesis, kind, funnel and goal, status (planned → producing → live → concluded | abandoned) and, once concluded, the conclusion (supported / rejected / inconclusive / invalid). Concluded ones are the account's lessons: they are attached to matching Next tests as `prior`.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"status":{"type":"string","enum":["planned","producing","live","concluded","abandoned"]},"limit":{"default":30,"type":"integer","minimum":1,"maximum":100}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_test","title":"getTest","description":"One Test in full: its frozen intent (hypothesis, reference, keep / change, funnel, goal, the rule that judges it), the evidence snapshot it was decided on, what it produced (drafts, assets, ads, launches) and every Observation of its outcome, newest first.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"testId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["testId"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_taxonomy","title":"listTaxonomy","description":"The house creative taxonomy and this workspace's Values. Dimensions: angle, persona, awareness, offer, offer_type, pain, season, asset_type, format, hook, headline_tactic, talent, visual (creative), copy, cta, language, market (ad). Closed Dimensions list their fixed Values; open ones return the workspace's Values with id, name, status (draft = proposed by the classifier, already counts; approved; archived = never counts) and how many creatives carry each. Visual format also lists `standard`: the standard formats (Motion's names) any creative may be tagged with by name in meta_tag_creatives — a workspace holds a row only for those it uses. Value ids are what meta_set_creative_links and meta_merge_taxonomy_values take.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_suggest_next","title":"suggestNext","description":"What to produce next. Classifies every live ad (paused ones are skipped) as cut / keep / duplicate / iterate / watch with reasons and numbers, and rolls spend up by persona and angle (the Values stored against each ad's creative, not its name; an ad is credited to each Value it carries, `unknown` when none) and by concept (the ad name's concept segment). Ads bought for a purchase are judged on ROAS (a profitable ad is never cut); ads bought for Add to Cart, leads or conversations are judged on cost per that event against a target — the operator's (meta_set_thresholds) else the account history's — and `goal` on each decision says which. `baselines` lists the history's cost per result per funnel.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"period":{"default":"7d","description":"Reporting window. 7d/14d/30d are the last N complete days, ending yesterday (as in Ads Manager); weeks are Monday-based, this_week runs to today. UTC.","type":"string","enum":["7d","14d","30d","this_week","last_week"]},"since":{"description":"Custom window start, YYYY-MM-DD, UTC. Overrides `period`. The result's `coverage` says what the warehouse holds.","type":"string"},"until":{"description":"Custom window end, YYYY-MM-DD, inclusive. Default today.","type":"string"}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_api_usage","title":"getApiUsage","description":"Meta API quota for the current hour: calls made, errors, throttles, percent of the app and ads-management allowances used, and minutes until access returns if throttled. Check before a large launch.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_launches","title":"listLaunches","description":"Recent launches made through this app, with their Meta ids and status (created = PAUSED, active, failed).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"limit":{"default":20,"type":"integer","minimum":1,"maximum":100}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_presets","title":"listPresets","description":"The workspace's launch presets — where the ads go (instant form or website), who sees them, the budget and how a batch is split into ad sets, the fallback copy and the campaign they launch into. The default (`isDefault`) is the one last launched with; meta_launch_ads uses it for anything the call leaves out. `problems` lists what stops a preset from launching.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_report_views","title":"listReportViews","description":"Saved views of the Ads report (/app/ads) — the workspace's shared ones and your own — plus the built-in templates (`templates`: Top creatives, Week over week, Top copy, Landing pages, Heavies, by-angle…), each with its URL state for THIS workspace's goal (a lead account ranks on cost per lead, never ROAS). Open any of them, saved or template, with meta_get_report_view({ view: slug }).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_report_view","title":"getReportView","description":"Open a report view and read its rows: a saved view or a template by slug (meta_list_report_views), or any report URL state (`query`, with `path`). Returns the same rows, filters, grouping, sort and totals the page shows (any catalogue metric in `m`, incl. hookScore / watchScore / clickScore / convertScore — 0–100 percentile ranks WITHIN that view's rows, null under their volume and spend floors, never a benchmark) — each row also carries `diagnosis` ({ stage, line }: where to work, read off its scores, null when they cannot say) — and, for a week-over-week view (vs=prev), each row's previous-window numbers. Warehouse only, no Meta quota. Quote its `notes`.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"view":{"description":"A saved view's or template's slug.","type":"string","minLength":1,"maxLength":64},"query":{"description":"Report URL state instead of a slug, e.g. `?group=copy&period=30d`.","anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},{"type":"string"}]},"path":{"description":"With `query`: the report page. Default: the Ads report.","type":"string","enum":["/app/creatives","/app/compare"]},"limit":{"default":25,"type":"integer","minimum":1,"maximum":100}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_search_ad_library","title":"searchAdLibrary","description":"Search the Meta Ad Library for reference ads — by keyword across every advertiser, or every ad one advertiser is running. Returns advertiser, copy, CTA, landing page, media type and how long each ad has been live. Save one with meta_save_swipe using its sourceUrl. Costs an API credit per page.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"query":{"description":"Keyword search.","type":"string","minLength":1},"company":{"description":"An advertiser's Page name; wins over query.","type":"string","minLength":1},"country":{"description":"ISO 3166-1 alpha-2. Omit for all.","type":"string","minLength":2,"maxLength":2},"mediaType":{"default":"all","type":"string","enum":["all","image","video"]},"cursor":{"description":"From a previous page.","type":"string"}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_swipes","title":"listSwipes","description":"The swipe file: reference ads the team has saved from the Ad Library, TikTok, Instagram, links or uploads — with advertiser, copy, CTA, landing page, tags and notes. These are OTHER people's ads, for inspiration; they are not launchable assets.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"source":{"default":"all","type":"string","enum":["all","ad_library","tiktok","instagram","url","upload"]},"q":{"description":"Matches advertiser, title or body.","type":"string"},"tag":{"type":"string"},"limit":{"default":50,"type":"integer","minimum":1,"maximum":200}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_recipe","title":"getRecipe","description":"The recipe of one static — a swipe or one of our assets: its format, layout zones, copy verbatim, visual system, hook, and which slots are replaceable versus kept. Also returns the prompt a replica would be generated from, so you can show or tweak it before meta_generate_draft. Extracted in the background for every static; null means not yet.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"subject":{"type":"string","enum":["asset","swipe"]},"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["subject","id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_drafts","title":"listDrafts","description":"Generated drafts — replicas rendered from a recipe — newest first, optionally for one subject. A succeeded draft is an asset with source 'ai' in the library and can be launched like any other.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"subject":{"type":"string","enum":["asset","swipe"]},"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"limit":{"default":20,"type":"integer","minimum":1,"maximum":50}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_personas","title":"listPersonas","description":"The workspace's personas — who the ads speak to — with pains, desires, objections, emotional triggers, trust needs and how they talk, each synthesized from customer quotes and curated by a human. The slug is the persona segment of the ad name; use approved ones when launching.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"status":{"default":"all","type":"string","enum":["draft","approved","archived","all"]}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_angles","title":"listAngles","description":"The messaging angles — what an ad argues: promise, mechanism, pain addressed, emotional trigger, trust signals — each with the persona it was born from. The slug is the angle segment of the ad name.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"status":{"default":"all","type":"string","enum":["draft","approved","archived","all"]}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_formats","title":"listFormats","description":"Creative formats derived from the swipe file and the library — the reusable shapes an ad takes (founder to camera, notification stack, testimonial card…). Formats are linked to creatives, not carried in the ad name.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"status":{"default":"all","type":"string","enum":["draft","approved","archived","all"]}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_research_sources","title":"listResearchSources","description":"Every research source with its id, label, kind, status and counts (documents stored, quotes mined). The id is what meta_delete_research_source takes. A source whose docCount is high and verbatimCount is 0 has not been mined yet — extraction runs on the worker's schedule, not on save.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_messaging","title":"listMessaging","description":"The copy lines (hook, headline, primary_text, objection) written for the workspace's angles, with their status (draft, approved, rejected), who wrote them (`source`: ai or human) and the quotes they cite (`verbatimIds`, empty on a human line). Filter by `angleId`, `kind` or `status`; the default `all` includes rejected lines, which drafting reads so the same line is never written again. Approved lines prefill a launch's copy. Lines live under Library › Messages (/app/library?tab=messages). Draft with meta_draft_messaging, add your own with meta_save_messaging, approve or reject with meta_set_messaging_status.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"angleId":{"description":"From meta_list_angles.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["hook","headline","primary_text","objection"]},"status":{"default":"all","type":"string","enum":["draft","approved","rejected","all"]},"limit":{"default":100,"type":"integer","minimum":1,"maximum":500}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_verbatims","title":"listVerbatims","description":"Customer quotes, exactly as written — mined from reviews, the advertiser's site and competitors. Filter by persona, angle or kind (pain, desire, objection, trigger, trust, outcome…). These are the evidence behind every persona, angle and copy line; quote them, never paraphrase them as if they were quotes.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"personaId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"angleId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"type":"string","enum":["pain","desire","objection","trigger","trust","outcome","praise","competitor","language"]},"q":{"description":"Substring match on the quote.","type":"string"},"limit":{"default":50,"type":"integer","minimum":1,"maximum":200}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_performance_cube","title":"getPerformanceCube","description":"Performance grouped and crossed on any of: campaign, adset, country (the ad set's targeted countries; an ad set bought for several is one bucket, e.g. AU+CA+GB+IE), ad (every copy of one ad name across ad sets — the creative published N times, summed), creative (the upload; a per-country localized file is its own upload), concept (the ad name's concept segment), and the stored Values angle, persona, awareness, offer, pain, format, hook, talent, visual. `rows` takes one axis or two (nested: e.g. ad → country splits each creative by ad set); `column` crosses them (angle × country). Each row: ads, distinct ad names, and `metrics` (spend, impressions, CPM, CTR, CPC, clicks, landing page views, leads, checkouts, registrations, purchases, ROAS, AOV, hook/hold and video retention rates, average watch time), and results / cost per result on the ads' goal — null with goal \"mixed\" when a cell mixes events. An ad with two Values on an axis counts under each; the total is never a sum of rows. From the daily warehouse, for a period.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"rows":{"minItems":1,"maxItems":2,"type":"array","items":{"type":"string","enum":["campaign","adset","country","ad","creative","concept","angle","persona","awareness","offer","offer_type","pain","season","asset_type","format","hook","headline_tactic","talent","visual"]}},"column":{"type":"string","enum":["campaign","adset","country","ad","creative","concept","angle","persona","awareness","offer","offer_type","pain","season","asset_type","format","hook","headline_tactic","talent","visual"]},"campaignIds":{"description":"Only these campaigns.","type":"array","items":{"type":"string"}},"limit":{"default":50,"description":"Top rows by spend.","type":"integer","minimum":1,"maximum":200},"period":{"default":"7d","description":"Reporting window. 7d/14d/30d are the last N complete days, ending yesterday (as in Ads Manager); weeks are Monday-based, this_week runs to today. UTC.","type":"string","enum":["7d","14d","30d","this_week","last_week"]},"since":{"description":"Custom window start, YYYY-MM-DD, UTC. Overrides `period`. The result's `coverage` says what the warehouse holds.","type":"string"},"until":{"description":"Custom window end, YYYY-MM-DD, inclusive. Default today.","type":"string"}},"required":["rows"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_strategy_rollup","title":"getStrategyRollup","description":"Spend, purchases, results and ROAS per Value of every creative Dimension (angle, persona, awareness, offer, pain, format, hook, talent, visual) and per persona × angle, for a period. Values are read from the classified creatives behind each ad (ad → asset → stored Values), never from the ad name. `unknown` rows are ads with no Value and still count.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"period":{"default":"7d","description":"Reporting window. 7d/14d/30d are the last N complete days, ending yesterday (as in Ads Manager); weeks are Monday-based, this_week runs to today. UTC.","type":"string","enum":["7d","14d","30d","this_week","last_week"]},"since":{"description":"Custom window start, YYYY-MM-DD, UTC. Overrides `period`. The result's `coverage` says what the warehouse holds.","type":"string"},"until":{"description":"Custom window end, YYYY-MM-DD, inclusive. Default today.","type":"string"}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_strategy","title":"getStrategy","description":"The workspace's brand & strategy — read it before writing a brief: product, offer, ideal customer and their ranked pains (the customer's words), voice, copy do's and don'ts, proof points (numbers the brand can claim, each with where it is claimed — a brief quotes no other number), and production capacity (formats the team can make per week; 0 = not yet). `goal` is the account goal and its target, READ-ONLY here (change it with meta_set_thresholds). `missing` names empty fields worth asking the operator about; `pendingSuggestions` are proposals waiting on a human.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_audience_breakdown","title":"getAudienceBreakdown","description":"LIVE Meta read (cached about an hour per workspace and window): who responds to each Value of a creative Dimension — goal cost per Value × age, gender, age × gender or placement (platform × position), the heat table behind a Value's \"Who responds\" (Library, /app/library?value=…) and Ads › Group by. Every cell counts ONE `event` — the account goal (`basis: account`), else the most-spent event (`basis: dominant`) — over only the ads bought for it; ads bought for other events are left out of every cell and reported in `excluded` ({ ads, spend }), so unlike events are never summed. An ad carrying two Values of the Dimension counts under each (rows do not add up to `totals`). Cells under 3 results carry no cost and `scored: false` — never call one best or worst. With `valueId` (an id or slug from meta_list_taxonomy) only that Value's row. Observational: Meta chose who saw each ad, so a cell is a lead to test, not a verdict — save a hypothesis with meta_save_learning if one stands out.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"by":{"type":"string","enum":["angle","persona","awareness","offer","offer_type","pain","season","asset_type","format","hook","headline_tactic","talent","visual"],"description":"The creative Dimension whose Values are the rows."},"cross":{"default":"age_gender","description":"The audience axis: age, gender, age_gender or placement.","type":"string","enum":["age","gender","age_gender","placement"]},"period":{"default":"30d","description":"Window: the last N complete days (as in Ads Manager), or a week.","type":"string","enum":["7d","14d","30d","this_week","last_week"]},"since":{"description":"Custom window start, YYYY-MM-DD, UTC. Overrides `period`. The result's `coverage` says what the warehouse holds.","type":"string"},"until":{"description":"Custom window end, YYYY-MM-DD, inclusive. Default today.","type":"string"},"valueId":{"type":"string","minLength":1,"maxLength":200}},"required":["by"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_switch_workspace","title":"switchWorkspace","description":"Move your MCP sessions to another workspace you are a member of (an orgId from meta_list_workspaces): every later call reads and writes ITS ad account. The same switch as the web app's workspace picker, minus the browser's own choice — a browser still on another workspace moves MCP back when a page loads there, so the result says to pick it in the app too. Refused for an rsk_ API key (pinned to its workspace) and for a workspace you are not in. Touches nothing on Meta.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"orgId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The workspace to switch to, from meta_list_workspaces."}},"required":["orgId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_add_research_source","title":"addResearchSource","description":"Add customer language to research. Four kinds, each taking one field: `app_store` / `google_play` take `reference` (a store link or the numeric app id, latest 500 reviews per storefront); `url` takes `url` (own site, competitor, review listing — one scraper credit); `paste` takes `text`, the reviews themselves, ONE PER BLOCK separated by a blank line — each block becomes one document. Quotes are extracted in the background; then list them with meta_list_verbatims. Synthesizing personas and angles from them is a button in the app (Library › Sources / Audiences), not a tool. Not money-moving; tagged as a write because it stores data.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"kind":{"type":"string","enum":["app_store","google_play","url","paste"]},"reference":{"description":"app_store / google_play: the store link, or the numeric app id.","type":"string","minLength":1},"url":{"description":"url: the page to read.","type":"string","format":"uri"},"text":{"description":"paste: the reviews, one per block, blocks separated by a blank line.","type":"string","minLength":8,"maxLength":200000},"country":{"description":"app_store / google_play: two-letter storefront code. Defaults to us.","type":"string","minLength":2,"maxLength":2},"label":{"description":"How this source is listed. Say whose customers these are.","type":"string"}},"required":["kind"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_delete_research_source","title":"deleteResearchSource","description":"Permanently delete one research source and everything mined from it — its documents and their quotes. Irreversible, and a persona already synthesized from those quotes keeps its text while losing the evidence under it. Use it to remove a source added in error; re-adding the same material is a fresh paste, not an undo. Ask the human first.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"sourceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"From meta_list_research_sources."}},"required":["sourceId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_refresh_research_source","title":"refreshResearchSource","description":"Fetch a research source again: an app's newest reviews, or a page's current text. Resumes from where the last fetch stopped, so only new material is read (a page costs one scraper credit). New quotes are mined in the background; list them with meta_list_verbatims. A pasted source has nothing to refresh. Id from meta_list_research_sources. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"sourceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"From meta_list_research_sources."}},"required":["sourceId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_link_verbatims","title":"linkVerbatims","description":"File customer quotes under a persona and/or an angle, so they count as that audience's or message's evidence (meta_list_verbatims filters on both). The quote text is never changed. Pass null to detach. Ids from meta_list_verbatims; persona and angle ids from meta_list_personas / meta_list_angles. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"ids":{"minItems":1,"maxItems":200,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"personaId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"angleId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]}},"required":["ids"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_save_messaging","title":"saveMessaging","description":"Add a copy line you or the human wrote, or edit one. Without `id`: needs `angleId` (meta_list_angles) and `kind` (hook, headline ≤40 chars, primary_text, objection); it is stored as a HUMAN line (`source: human`) that may cite no quote — pass `verbatimIds` to cite some — and starts as a draft unless `status: approved`. With `id` (meta_list_messaging): replaces the text (a headline stays ≤40 chars), keeps the quotes it cites, and the line becomes a human line; the angle and kind cannot move — add a new line and reject the old one. Approved lines prefill launch copy and are held to the strategy at launch (meta_get_strategy). Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"description":"The line to edit. Omit to add a new one.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"angleId":{"description":"New line: the angle it argues.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kind":{"description":"New line: its kind.","type":"string","enum":["hook","headline","primary_text","objection"]},"text":{"type":"string","minLength":1,"maxLength":2000},"verbatimIds":{"description":"New line: quotes it was written from (meta_list_verbatims). Optional.","maxItems":10,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"status":{"description":"Draft by default. `approved` makes it available to prefill launches.","type":"string","enum":["draft","approved"]}},"required":["text"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_set_messaging_status","title":"setMessagingStatus","description":"Approve, reject, or send back to draft one or several copy lines (ids from meta_list_messaging). Approved lines prefill launch copy. A rejected line KEEPS its row: meta_draft_messaging reads rejected lines so it never writes the same one again — reject rather than delete a line you do not want back. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"ids":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"status":{"type":"string","enum":["draft","approved","rejected"]}},"required":["ids","status"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_delete_messaging","title":"deleteMessaging","description":"Permanently delete copy lines (ids from meta_list_messaging). Irreversible, and drafting forgets them, so it may write the same line again — to turn a line down for good use meta_set_messaging_status with `rejected`. Use this for a line added in error. Ask the human first.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"ids":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}},"required":["ids"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_update_swipe","title":"updateSwipe","description":"Replace a swipe's tags and/or its note. Tags REPLACE what is there — meta_save_swipe on a URL already saved appends instead, so this is the way to correct a tag rather than pile another one on. Tags are lowercased and cut to 40 characters; keep them short. Pass an empty array to clear them, and null to clear the note.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"swipeId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"From meta_list_swipes."},"tags":{"maxItems":20,"type":"array","items":{"type":"string"}},"notes":{"type":["string","null"]}},"required":["swipeId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_draft_messaging","title":"draftMessaging","description":"Write copy lines for one angle from its evidence — hooks, headlines (≤40 chars), primary texts, objection handlers — each citing the quotes it was written from. Lines land as drafts; a human approves them under Library › Messages (/app/library?tab=messages), or with meta_set_messaging_status, before they prefill a launch. One model call.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"angleId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"kinds":{"type":"array","items":{"type":"string","enum":["hook","headline","primary_text","objection"]}},"count":{"default":4,"description":"Lines per kind.","type":"integer","minimum":1,"maximum":8}},"required":["angleId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_set_creative_links","title":"setCreativeLinks","description":"Set a creative's (asset or swipe) Values on the house taxonomy — a human-grade override: the classifier only fills gaps afterwards. Open Dimensions (persona, angle, format, offer, pain, visual) take Value ids from meta_list_taxonomy; closed ones (awareness, asset_type, hook, headline_tactic, offer_type, season, talent) take the word itself. `format` (up to 3, primary first) and `visual` are lists. Pass null to clear. Several creatives at once with `ids`; `visualMode: add` appends visual elements instead of replacing them.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"subject":{"type":"string","enum":["asset","swipe"]},"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"ids":{"maxItems":200,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"persona":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"angle":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"format":{"anyOf":[{"maxItems":3,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},{"type":"null"}]},"offer":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"pain":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"visual":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"visualMode":{"default":"replace","type":"string","enum":["replace","add"]},"awareness":{"anyOf":[{"type":"string","enum":["unaware","problem-aware","solution-aware","product-aware","most-aware"]},{"type":"null"}]},"asset_type":{"anyOf":[{"type":"string","enum":["ugc","hybrid","lifestyle-image-text","product-image-text","text-only","illustration","ugc-mashup","other"]},{"type":"null"}]},"hook":{"anyOf":[{"type":"string","enum":["aspirational","authority","belief","bold-claim","call-to-action-first","challenge","contrast","confession","contrarian","curiosity","demographic-callout","direct-address","directive","exclusivity","explainer","fomo","how-to","if-then","listicle","myth-busting","offer-only","price-anchor","question","reasons-why","relatability","reverse-psychology","risk-reversal","shocking-statement","social-proof","statistic","storytelling","urgency","warning","none"]},{"type":"null"}]},"headline_tactic":{"anyOf":[{"type":"string","enum":["aspirational","authority","belief","bold-claim","call-to-action-first","challenge","contrast","confession","contrarian","curiosity","demographic-callout","direct-address","directive","exclusivity","explainer","fomo","how-to","if-then","listicle","myth-busting","offer-only","price-anchor","question","reasons-why","relatability","reverse-psychology","risk-reversal","shocking-statement","social-proof","statistic","storytelling","urgency","warning","none"]},{"type":"null"}]},"offer_type":{"anyOf":[{"type":"string","enum":["no-offer","promo","always-on-offer"]},{"type":"null"}]},"season":{"anyOf":[{"type":"string","enum":["evergreen","new-year","valentines","summer","back-to-school","black-friday","christmas","other"]},{"type":"null"}]},"talent":{"anyOf":[{"type":"string","enum":["none","creator","founder","customer","model"]},{"type":"null"}]}},"required":["subject"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_save_briefs","title":"saveBriefs","description":"Save strategist briefs so the operator sees them under Briefs (/app/briefs). Brief the Next tests from meta_get_history_winners by their `id` (same `window` / `funnel` you read them in), or add a strategist note with an id `note:<slug>` plus the `evidence` lines it rests on. A brief may only quote numbers its evidence carries — for a computed Next test that is the evidence THIS app computed — and is refused otherwise. Re-saving a test id replaces its brief. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"window":{"default":"90d","type":"string","enum":["30d","90d","180d","lifetime"]},"funnel":{"type":"string","enum":["instant_form","website","messaging","profile","traffic","unknown"]},"briefs":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"testId":{"type":"string","minLength":1,"maxLength":300},"title":{"type":"string","minLength":1,"maxLength":200},"why":{"type":"string","maxLength":800},"make":{"type":"string","maxLength":800},"openers":{"maxItems":5,"type":"array","items":{"type":"string","maxLength":160}},"evidence":{"maxItems":10,"type":"array","items":{"type":"string","maxLength":400}}},"required":["testId","title"]}}},"required":["briefs"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_save_brief","title":"saveBrief","description":"Put ONE brief on the Briefs board as a Draft: title, concept (the idea and why it should work), copy (hook, headline, primaryText, cta, leadFormId, script lines {from, to, onScreen, vo}), visual approach, reference ({kind: asset | swipe | ad, id} — an own winner or a swipe with a recipe makes drafts possible), deliverables ({count, format, ratios, maxSeconds}), success ({goalEvent, target, windowDays, minExpectedGoals} — read the goal from meta_get_overview / meta_set_thresholds), scope ({dimension, valueId} from meta_list_taxonomy) and learningIds (meta_list_learnings). The concept and copy may only quote numbers their evidence carries — the cited learnings, the workspace's offer and proof points, or `evidence` lines you add for a fact nothing else carries — and are refused otherwise. Returns the brief and its page. Not money-moving; for briefs on Next tests use meta_save_briefs.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"concept":{"description":"The idea and why it should work.","type":"string","maxLength":2000},"copy":{"type":"object","properties":{"hook":{"type":"string","maxLength":200},"headline":{"type":"string","maxLength":120},"primaryText":{"type":"string","maxLength":2000},"cta":{"description":"The button, e.g. GET_QUOTE or Learn more.","type":"string","maxLength":60},"leadFormId":{"type":"string","pattern":"^\\d+$"},"script":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"from":{"type":"number","minimum":0,"maximum":600,"description":"Seconds from the start."},"to":{"type":"number","minimum":0,"maximum":600},"onScreen":{"default":"","type":"string","maxLength":300},"vo":{"default":"","description":"Voice-over, verbatim.","type":"string","maxLength":400}},"required":["from","to"]}}}},"visual":{"description":"The visual approach.","type":"string","maxLength":2000},"reference":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["asset","swipe","ad"]},"id":{"type":"string","minLength":1,"maxLength":100}},"required":["kind","id"]},{"type":"null"}]},"deliverables":{"maxItems":10,"type":"array","items":{"type":"object","properties":{"count":{"type":"integer","minimum":1,"maximum":50},"format":{"type":"string","minLength":1,"maxLength":80,"description":"Static, UGC selfie, carousel…"},"ratios":{"default":[],"maxItems":4,"type":"array","items":{"type":"string","enum":["1:1","4:5","9:16","16:9"]}},"maxSeconds":{"type":"integer","minimum":1,"maximum":600}},"required":["count","format"]}},"success":{"anyOf":[{"type":"object","properties":{"goalEvent":{"type":"string","enum":["add_to_cart","form_lead","website_lead","conversation","purchase","view_content","link_click"]},"target":{"default":null,"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}]},"windowDays":{"default":7,"type":"integer","minimum":1,"maximum":180},"minExpectedGoals":{"default":10,"type":"number","minimum":1,"maximum":1000}},"required":["goalEvent"]},{"type":"null"}]},"scope":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"dimension":{"type":"string","enum":["angle","persona","awareness","offer","offer_type","pain","season","asset_type","format","hook","headline_tactic","talent","visual"]},"valueId":{"type":"string","minLength":1,"maxLength":100}},"required":["dimension","valueId"]}},"learningIds":{"maxItems":20,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"evidence":{"description":"Facts the brief quotes that no cited learning carries — an offer price, a proof point.","maxItems":10,"type":"array","items":{"type":"string","maxLength":400}}},"required":["title"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_update_brief","title":"updateBrief","description":"Change a brief (meta_get_brief first): any of its fields (only those passed change; the evidence rule is checked again), its status, and what is linked to it. Status moves by hand are draft ⇄ ready, anything → dismissed, dismissed → draft; the rest follow the work and are refused here — link a draft or asset (in production), a launch whose ad delivers (live), a Test that concludes (learned). Links: {kind: draft | asset | launch | test, refId}. meta_generate_draft, meta_launch_ads and meta_create_test take `briefId` and link on their own. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"status":{"type":"string","enum":["draft","ready","in_production","live","learned","dismissed"]},"fields":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"concept":{"description":"The idea and why it should work.","type":"string","maxLength":2000},"copy":{"type":"object","properties":{"hook":{"type":"string","maxLength":200},"headline":{"type":"string","maxLength":120},"primaryText":{"type":"string","maxLength":2000},"cta":{"description":"The button, e.g. GET_QUOTE or Learn more.","type":"string","maxLength":60},"leadFormId":{"type":"string","pattern":"^\\d+$"},"script":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"from":{"type":"number","minimum":0,"maximum":600,"description":"Seconds from the start."},"to":{"type":"number","minimum":0,"maximum":600},"onScreen":{"default":"","type":"string","maxLength":300},"vo":{"default":"","description":"Voice-over, verbatim.","type":"string","maxLength":400}},"required":["from","to"]}}}},"visual":{"description":"The visual approach.","type":"string","maxLength":2000},"reference":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["asset","swipe","ad"]},"id":{"type":"string","minLength":1,"maxLength":100}},"required":["kind","id"]},{"type":"null"}]},"deliverables":{"maxItems":10,"type":"array","items":{"type":"object","properties":{"count":{"type":"integer","minimum":1,"maximum":50},"format":{"type":"string","minLength":1,"maxLength":80,"description":"Static, UGC selfie, carousel…"},"ratios":{"default":[],"maxItems":4,"type":"array","items":{"type":"string","enum":["1:1","4:5","9:16","16:9"]}},"maxSeconds":{"type":"integer","minimum":1,"maximum":600}},"required":["count","format"]}},"success":{"anyOf":[{"type":"object","properties":{"goalEvent":{"type":"string","enum":["add_to_cart","form_lead","website_lead","conversation","purchase","view_content","link_click"]},"target":{"default":null,"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}]},"windowDays":{"default":7,"type":"integer","minimum":1,"maximum":180},"minExpectedGoals":{"default":10,"type":"number","minimum":1,"maximum":1000}},"required":["goalEvent"]},{"type":"null"}]},"scope":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"dimension":{"type":"string","enum":["angle","persona","awareness","offer","offer_type","pain","season","asset_type","format","hook","headline_tactic","talent","visual"]},"valueId":{"type":"string","minLength":1,"maxLength":100}},"required":["dimension","valueId"]}},"learningIds":{"maxItems":20,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"evidence":{"description":"Facts the brief quotes that no cited learning carries — an offer price, a proof point.","maxItems":10,"type":"array","items":{"type":"string","maxLength":400}}}},"links":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["draft","asset","launch","test"]},"refId":{"type":"string","minLength":1,"maxLength":100}},"required":["kind","refId"]}}},"required":["id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_create_test","title":"createTest","description":"Commit to a Next test: it becomes a Test whose intent is FROZEN — hypothesis, reference, keep / change, funnel, goal, and the rule that will judge it (comparator, the expected volume it needs before judging, how long it waits for late conversions, how long it runs) — with the evidence it was decided on. Pass the Next test's `nextTestId` from meta_get_history_winners with the same `window` / `funnel`; or, for an idea no Next test proposed, `custom` with its title, hypothesis, what to try and the evidence it rests on. Comparator `baseline` (default) holds the test to the cost per goal the decision was made on; `reference` races it against the reference creative's ads over the same days — only if both run. A changed mind is a new test with `supersedesId`, never an edit. The brief it judges (`briefId`, or the Next test's saved brief) is linked to it and becomes learned when it concludes. Touches nothing on Meta. Then make it (meta_generate_draft with testId), launch it PAUSED (meta_launch_ads with testId), and read it with meta_observe_test.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"nextTestId":{"type":"string","minLength":1,"maxLength":300},"window":{"default":"90d","type":"string","enum":["30d","90d","180d","lifetime"]},"funnel":{"description":"The funnel the Next tests were read in; for an exploration that pools funnels, where to run it.","type":"string","enum":["instant_form","website","messaging","profile","traffic","unknown"]},"custom":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"hypothesis":{"type":"string","minLength":1,"maxLength":800},"try":{"default":[],"maxItems":6,"type":"array","items":{"type":"string","maxLength":200}},"evidence":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"string","maxLength":400}},"referenceAssetId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["title","hypothesis","evidence"]},"hypothesis":{"description":"Overrides the default hypothesis written from the Next test.","type":"string","maxLength":800},"comparator":{"default":"baseline","type":"string","enum":["reference","baseline"]},"minExpectedGoals":{"type":"number","minimum":1,"maximum":1000},"maturityDays":{"type":"integer","minimum":0,"maximum":90},"windowDays":{"type":"integer","minimum":1,"maximum":180},"supersedesId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"briefId":{"description":"The brief this Test judges; it is linked, and learned when the Test concludes.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_link_test_artifacts","title":"linkTestArtifacts","description":"Tie what a Test produced to it, when it was not made through meta_generate_draft / meta_launch_ads with its testId: drafts, assets (uploads), Meta ad ids, launches. A draft or asset moves a planned test to producing; an ad or launch moves it to live. A concluded or abandoned test takes nothing. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"testId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"links":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["draft","asset","ad","launch"]},"ref":{"type":"string","minLength":1,"maxLength":100}},"required":["kind","ref"]}}},"required":["testId","links"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_observe_test","title":"observeTest","description":"Read a Test's outcome now and record it as a new Observation (append-only; nothing else changes). Its ads are held to the rule frozen at commit: inconclusive until they deliver, until the maturity wait has passed and until the spend expects the declared volume; then supported or rejected only when clearly above or below what the spend should have bought (the same rule as history verdicts), else inconclusive. Low delivery is never a loss. Every result is observational: Meta chose who saw each ad.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"testId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["testId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_conclude_test","title":"concludeTest","description":"Record a Test's Conclusion — supported, rejected, inconclusive or invalid — with a note on what it means for the next creative. Final: a second conclusion is refused; a new question is a new test. Supported or rejected must match the latest Observation unless the human gives an `overrideReason`, which is kept in the note. The lesson then appears on every matching Next test, and a rejected one sinks in the same funnel and market. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"testId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"conclusion":{"type":"string","enum":["supported","rejected","inconclusive","invalid"]},"note":{"type":"string","minLength":1,"maxLength":1000},"overrideReason":{"type":"string","maxLength":400}},"required":["testId","conclusion","note"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_abandon_test","title":"abandonTest","description":"Stop a Test without a conclusion — the budget went elsewhere, or the question stopped mattering. It keeps its intent, links and observations; it teaches nothing. Pauses nothing on Meta.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"testId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["testId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_list_learnings","title":"listLearnings","description":"The account's learnings — statements of WHY something works here, each scoped on taxonomy Values, with a status (hypothesis → supported / refuted → retired, history append-only), the evidence the app computed from the scope over the last 90 days, and who added it. Plus `proposals`: drafts from concluded Tests (supported → Supported, rejected → Refuted) and strong winning Traits (→ Hypothesis) that nobody has accepted or dismissed. Read this before writing a brief: briefs cite learnings.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"status":{"type":"string","enum":["hypothesis","supported","refuted","retired"]},"dimension":{"type":"string","enum":["angle","persona","awareness","offer","offer_type","pain","season","asset_type","format","hook","headline_tactic","talent","visual"]},"valueId":{"description":"A Value id (meta_list_taxonomy), or a closed Dimension's word.","type":"string","maxLength":100},"source":{"type":"string","enum":["test","trait","analysis","agent","human"]},"includeProposals":{"default":true,"type":"boolean"}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_get_learning","title":"getLearning","description":"One learning in full: the why, what happened, what to do differently, its scope, the whole status history, its evidence recomputed NOW from the warehouse (per scope Value and together, against the rest of the account on the same goal — observational), the insight check on its statement, and the briefs that cite it.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["id"]},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_save_learning","title":"saveLearning","description":"Record a learning: `statement` is the WHY — what changed in the viewer's mind, brand-specific, still true with the numbers removed — not what happened (that is `observation`). `scope` names the Values it applies to ({ dimension, valueId } from meta_list_taxonomy; a closed Dimension takes its word) — read AND across Dimensions, OR within one, so two angles plus a persona compares the angles for that persona. The app computes the evidence from the scope; never put numbers in for it. Status is not yours to pick: it starts as a hypothesis, or supported / refuted when `testId` (or a `proposalKey` from meta_list_learnings) names a concluded Test. Returns `check.looksLikeObservation` — when true, rewrite the statement with meta_update_learning. Give your own name in `agent` so the app shows who added it. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"statement":{"type":"string","minLength":1,"maxLength":600},"observation":{"type":"string","maxLength":1200},"implication":{"description":"What to make differently because of it. Briefs quote this line.","type":"string","maxLength":800},"scope":{"default":[],"maxItems":8,"type":"array","items":{"type":"object","properties":{"dimension":{"type":"string","enum":["angle","persona","awareness","offer","offer_type","pain","season","asset_type","format","hook","headline_tactic","talent","visual"]},"valueId":{"type":"string","minLength":1,"maxLength":100}},"required":["dimension","valueId"]}},"proposalKey":{"description":"Accept a proposal from meta_list_learnings: `test:<id>` or `trait:<trait id>`.","type":"string","maxLength":300},"testId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"agent":{"description":"Your name, e.g. \"Claude\" — shown as \"Added by Claude over MCP\".","type":"string","maxLength":40}},"required":["statement"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_update_learning","title":"updateLearning","description":"Change a learning: its statement (the why), observation, implication or scope (the evidence is recomputed), or its status — appended to the history, never rewritten. Marking it supported or refuted without a `testId` needs a `reason` saying what showed it. Retire one that stopped being true with status `retired`; the briefs that cited it keep the link. Returns the insight check on the statement. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"statement":{"type":"string","minLength":1,"maxLength":600},"observation":{"anyOf":[{"type":"string","maxLength":1200},{"type":"null"}]},"implication":{"anyOf":[{"type":"string","maxLength":800},{"type":"null"}]},"scope":{"maxItems":8,"type":"array","items":{"type":"object","properties":{"dimension":{"type":"string","enum":["angle","persona","awareness","offer","offer_type","pain","season","asset_type","format","hook","headline_tactic","talent","visual"]},"valueId":{"type":"string","minLength":1,"maxLength":100}},"required":["dimension","valueId"]}},"status":{"type":"string","enum":["hypothesis","supported","refuted","retired"]},"reason":{"type":"string","maxLength":400},"testId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"agent":{"type":"string","maxLength":40}},"required":["id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_tag_creatives","title":"tagCreatives","description":"Tag many creatives at once, as a strategist reviewing the first-pass classifier. Per item, give any creative Dimension: open ones (angle, persona, offer, pain, format, visual) by Value NAME or id — a name nobody has becomes a draft Value, and near-duplicates (\"price card\" / \"Pricing cards\") fold into one; a format named from the standard list (\"Greenscreen\", \"Us Vs Them\" — meta_list_taxonomy) becomes the workspace's standard format; closed ones (awareness, asset_type, hook, headline_tactic, offer_type, season, talent) by their word or label. `format` (up to 3, primary first) and `visual` are lists and REPLACE the creative's list. null clears. Every creative touched is marked curated: the in-app classifier only fills gaps behind you. Name Values by the idea, reusable across creatives — meta_list_taxonomy first, so you reuse what exists. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"items":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"subject":{"default":"asset","type":"string","enum":["asset","swipe"]},"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"values":{"type":"object","properties":{"angle":{"type":["string","null"]},"persona":{"type":["string","null"]},"offer":{"type":["string","null"]},"pain":{"type":["string","null"]},"format":{"anyOf":[{"anyOf":[{"type":"string"},{"maxItems":3,"type":"array","items":{"type":"string"}}]},{"type":"null"}]},"visual":{"type":"array","items":{"type":"string"}},"awareness":{"anyOf":[{"type":"string","enum":["unaware","problem-aware","solution-aware","product-aware","most-aware"]},{"type":"null"}]},"asset_type":{"type":["string","null"]},"hook":{"type":["string","null"]},"headline_tactic":{"type":["string","null"]},"offer_type":{"type":["string","null"]},"season":{"type":["string","null"]},"talent":{"anyOf":[{"type":"string","enum":["none","creator","founder","customer","model"]},{"type":"null"}]}},"additionalProperties":false},"rationale":{"type":"string","maxLength":400}},"required":["id","values"]}}},"required":["items"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_delete_creatives","title":"deleteCreatives","description":"Permanently delete library uploads that never became an ad — a broken upload, a duplicate, a draft nobody will run. Deletes the file, its Values, notes and brief links. Irreversible. Refused per item, with the reason, for a creative in any ad (its performance is read through that link — pause the ads instead) or in a Test. Ids from meta_list_creatives (subject asset). Ask the human first.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"ids":{"minItems":1,"maxItems":100,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}}},"required":["ids"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_update_creative","title":"updateCreative","description":"Rename and re-tag one library upload (an `asset` from meta_list_creatives): `title` (null clears it) and/or `tags`, which REPLACE the current ones (lowercased, ≤40 chars each, ≤20). A human edit wins — the auto-labeler only ever fills what is empty. For its Values (audience, message, format…) use meta_set_creative_links or meta_tag_creatives; for a swipe's tags and note, meta_update_swipe. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"An asset id from meta_list_creatives."},"title":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}]},"tags":{"maxItems":20,"type":"array","items":{"type":"string"}}},"required":["id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_create_taxonomy_value","title":"createTaxonomyValue","description":"Add a Value to an open Dimension — an audience (persona), message (angle), format, offer, pain/desire or visual element — so creatives can be tagged with it (meta_set_creative_links, meta_tag_creatives take its id or name). Created approved, attributed to the agent. Refused with the existing Value when the same idea is already there (\"price card\" = \"Pricing cards\"; an archived one is brought back with meta_update_taxonomy_value `status: approved`). Hook, awareness and talent are closed lists and cannot be added to. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"dimension":{"type":"string","enum":["angle","persona","offer","pain","format","visual"]},"name":{"type":"string","minLength":1,"maxLength":80},"description":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}]}},"required":["dimension","name"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_update_taxonomy_value","title":"updateTaxonomyValue","description":"Rename, describe, approve or archive a Value on an open Dimension (angle, persona, offer, pain, format, visual); `id` from meta_list_taxonomy. Archive instead of deleting: archived Values stop counting as evidence and are never re-proposed by the classifier (`status: approved` brings one back); to fold a duplicate into another use meta_merge_taxonomy_values. Omitting `id` still creates a Value — prefer meta_create_taxonomy_value. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"dimension":{"type":"string","enum":["angle","persona","offer","pain","format","visual"]},"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string","minLength":1,"maxLength":80},"description":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}]},"status":{"type":"string","enum":["draft","approved","archived"]}},"required":["dimension"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_merge_taxonomy_values","title":"mergeTaxonomyValues","description":"Fold one Value into another on the same open Dimension: every creative that carried `fromId` now carries `intoId`, and `fromId` is deleted. Use it when two names mean one idea (\"0% tax\" and \"zero tax\") — split names split the evidence. Irreversible; not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"dimension":{"type":"string","enum":["angle","persona","offer","pain","format","visual"]},"fromId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"intoId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["dimension","fromId","intoId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_save_swipe","title":"saveSwipe","description":"Save a reference ad to the swipe file from a link: a Meta Ad Library ad URL, a TikTok video, an Instagram post/reel, or a direct image/video URL. The media is copied into our storage (source URLs expire). Not money-moving; tagged as a write because it stores data.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"url":{"type":"string","format":"uri"},"tags":{"maxItems":20,"type":"array","items":{"type":"string"}}},"required":["url"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_generate_draft","title":"generateDraft","description":"Generate a static that replicates a swipe's or an asset's format, from its recipe. Pass swaps for the replaceable slots (product, brand, price…) and copy overrides, or a full prompt. Spends OUR generation credits, not ad spend; the result lands in the library as an 'ai' asset and is not launched. Poll meta_list_drafts for the outcome.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"subject":{"type":"string","enum":["asset","swipe"]},"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"swaps":{"description":"Slot → replacement, keyed as the recipe names them, e.g. { product: \"…\" }.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"copy":{"type":"object","properties":{"headline":{"type":"string"},"subhead":{"type":"string"},"cta":{"type":"string"},"proof":{"type":"string"}}},"direction":{"type":"string","maxLength":500},"prompt":{"description":"A full prompt, replacing the rendered one. Use meta_get_recipe to see it first.","type":"string","maxLength":8000},"ratio":{"type":"string","enum":["1:1","4:5","9:16","16:9"]},"quality":{"default":"draft","type":"string","enum":["draft","final"]},"testId":{"description":"The Test this draft is made for; the draft and its asset are linked to it.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"briefId":{"description":"The brief this draft is made from (meta_list_briefs); linked after.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["subject","id"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_transcribe_creative","title":"transcribeCreative","description":"Transcribe one library VIDEO: a model listens to the whole file once and the transcript — language, and what is said with the second each line starts — is stored on the upload and returned (meta_get_creative returns it afterwards). Written once, never overwritten: an upload that already has one returns it unchanged — except a stored transcript whose timings are impossible (lines faster than anyone speaks), which meta_get_creative hides and this replaces. Spoken words only; on-screen text is not transcribed. Refuses a static, an ad with no file in the library, and a file over the classifier's 18MB inline cap — it never guesses. A video with no speech is stored as hasSpeech false. Spends OUR model credits, not ad spend. Not money-moving; tagged as a write because it mutates stored data.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"assetId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The library upload's id (meta_list_creatives)."}},"required":["assetId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_sync_now","title":"syncNow","description":"Pull the last N days of ad-level insights and objects from Meta into the warehouse. Not money-moving; tagged as a write because it mutates stored data.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"days":{"default":3,"type":"integer","minimum":1,"maximum":90}}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_backfill_insights","title":"backfillInsights","description":"Fill the daily warehouse back in time, so meta_get_overview / meta_get_ad_performance / meta_get_strategy_rollup can answer for any dated window (\"how did March do\"), not only the recent sync window. Runs in the background, one month per step, walking back from the oldest day held to `since` — default: where the account's spend began (from the history), capped at Meta's 37 months. Asking again resumes; it never re-reads a finished month. Progress shows in meta_get_overview's `coverage`. Costs one Meta insights read per month; on the hourly quota it waits and resumes. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"since":{"description":"How far back, YYYY-MM-DD. Optional.","type":"string"}}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_set_thresholds","title":"setThresholds","description":"Change what meta_suggest_next and the Ads report judge against. `goalEvent` is the account's goal — every ad is reported and judged on that event (Results, cost per result) instead of the one its ad set was bought for; null goes back to auto. `campaignGoals` overrides it per campaign id ({ event, target? }; null removes one). `costPerResult` sets the target cost per result per event — null removes a target so the account's history baseline applies again. `funnelSteps` is the funnel Home and meta_get_overview report, in order (e.g. link_clicks → view_content → website_leads → add_to_cart, or impressions → video_3s → thruplays → link_clicks for video; 2–6 distinct steps); null goes back to the goal's default. The scalars tune the ROAS path: minSpendValidate (judge nothing below), cpaCut, roasScale, roasBreakEven. Amounts are in the account currency. Returns the thresholds now in force. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"goalEvent":{"anyOf":[{"type":"string","enum":["add_to_cart","form_lead","website_lead","conversation","purchase","view_content","link_click"]},{"type":"null"}]},"campaignGoals":{"type":"object","propertyNames":{"type":"string","minLength":1},"additionalProperties":{"anyOf":[{"type":"object","properties":{"event":{"type":"string","enum":["add_to_cart","form_lead","website_lead","conversation","purchase","view_content","link_click"]},"target":{"type":"number","exclusiveMinimum":0}},"required":["event"]},{"type":"null"}]}},"costPerResult":{"type":"object","propertyNames":{"type":"string","enum":["form_lead","conversation","add_to_cart","purchase","view_content","registration","website_lead","link_click","none"]},"additionalProperties":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}]}},"funnelSteps":{"anyOf":[{"minItems":2,"maxItems":6,"type":"array","items":{"type":"string","enum":["impressions","video_3s","thruplays","clicks","link_clicks","landing_page_views","view_content","leads","form_leads","website_leads","registrations","add_to_cart","checkouts","purchases","conversations"]}},{"type":"null"}]},"minSpendValidate":{"type":"number","exclusiveMinimum":0},"minSpendScale":{"type":"number","exclusiveMinimum":0},"cpaCut":{"type":"number","exclusiveMinimum":0},"roasBreakEven":{"type":"number","exclusiveMinimum":0},"roasEarlyKill":{"type":"number","exclusiveMinimum":0},"roasScale":{"type":"number","exclusiveMinimum":0}}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_pull_account_history","title":"pullAccountHistory","description":"Pull every ad's LIFETIME insights and its creative (copy, destination, CTA, audience) from Meta into the history table, archived and deleted ads included. Replaces the stored snapshot. When Meta's hourly quota is used up the pull is scheduled instead (`status: queued`, `retryInMin`) and runs by itself — the stored history stays readable meanwhile. Not money-moving; tagged as a write because it mutates stored data.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_list_pages_and_pixels","title":"listPagesAndPixels","description":"LIVE Meta call: the ad account this session is on (`adAccountId` — it follows the workspace active in the web app, so check it before launching), the Facebook Pages (each with its linked Instagram account) and the Pixels it can use, plus the workspace defaults. An account often has several — pass the chosen pageId / pixelId to meta_launch_ads.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_list_lead_forms","title":"listLeadForms","description":"LIVE Meta call: the instant (lead) forms on the Page, newest first — id, name, status (only ACTIVE takes ads), locale, every question with its key, type, label and options (the keys are the field names a lead arrives under, i.e. what the CRM maps on), privacy policy and lead count. Needs the System User to hold the Page with ad access. Pass a form's id as copy.leadFormId to meta_launch_ads.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"pageId":{"description":"Omit for the workspace's default Page.","type":"string","pattern":"^\\d+$"},"status":{"default":"ACTIVE","type":"string","enum":["ACTIVE","ARCHIVED","all"]}}},"annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"meta_pull_account_defaults","title":"pullAccountDefaults","description":"Read the audience (countries, age, gender) and CTA / link / URL tags back from the most recent launches on Meta, repair the launch records, and save them as the account's launch defaults. Use after fixing ads in Ads Manager.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_launch_ads","title":"launchAds","description":"Create ads PAUSED: pick or create the campaign and ad set, upload each creative from a public https URL or a library assetId (or `media`: a 9x16 + a 4x5/1x1 as ONE ad, the 9:16 in Stories and Reels), build the creative with every Advantage+ enhancement opted out, and record a launch. Nothing spends until meta_activate. For instant-form ads: campaign objective OUTCOME_LEADS, adSet.leadForm, copy.leadFormId (meta_list_lead_forms / meta_create_lead_form), no link. Ad names must be canonical: id__locale__format__persona__angle__concept__variant. pageId / pixelId default to the workspace's; meta_list_pages_and_pixels lists the choices. With a launch preset (meta_list_presets), only creatives are required: campaign, adSet and copy default to the preset's (presetId, or the workspace default), and a success makes that preset the default. `strategyCautions` in the result lists what in the copy meta_get_strategy does not back (numbers it does not state, claims to confirm, the voice's person); show them to the operator before meta_activate. Pass briefId and testId when the ads come from a brief or run for a Test.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"presetId":{"description":"The launch preset (meta_list_presets) that fills whatever this call leaves out — campaign, adSet, copy. Omitted: the workspace default preset, used only when one of the three is missing.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"campaign":{"description":"Omit to take the preset's: its campaign by name, or a new CBO campaign.","anyOf":[{"type":"object","properties":{"existingId":{"type":"string","description":"A campaign id from meta_list_campaigns."}},"required":["existingId"]},{"type":"object","properties":{"name":{"type":"string","minLength":1},"objective":{"type":"string","enum":["OUTCOME_SALES","OUTCOME_LEADS","OUTCOME_TRAFFIC","OUTCOME_APP_PROMOTION","OUTCOME_AWARENESS","OUTCOME_ENGAGEMENT"]},"dailyBudget":{"type":"number","exclusiveMinimum":0,"description":"Daily budget in the account currency, e.g. 50 = 50.00."}},"required":["name","objective","dailyBudget"]}]},"adSet":{"description":"Omit for a new ad set with the preset's audience and destination.","anyOf":[{"type":"object","properties":{"existingId":{"type":"string","description":"An ad set id from meta_list_campaigns."}},"required":["existingId"]},{"type":"object","properties":{"name":{"type":"string","minLength":1},"countries":{"minItems":1,"type":"array","items":{"type":"string","minLength":2,"maxLength":2},"description":"ISO 3166-1 alpha-2 codes."},"ageMin":{"type":"integer","minimum":13,"maximum":65},"ageMax":{"type":"integer","minimum":13,"maximum":65},"placements":{"type":"string","enum":["facebook_instagram","automatic"],"description":"facebook_instagram (default): Facebook + Instagram only — no Audience Network, Messenger, Threads or WhatsApp. automatic: Meta's Advantage+ placements, Audience Network included."},"conversionEvent":{"description":"Omit for a traffic ad set (optimises for link clicks). Locked after publish.","type":"string","enum":["PURCHASE","INITIATE_CHECKOUT","ADD_TO_CART","LEAD","COMPLETE_REGISTRATION","START_TRIAL","SUBSCRIBE"]},"leadForm":{"description":"An instant-form ad set: the ads open a Meta lead form (copy.leadFormId) instead of a website. Needs a campaign with objective OUTCOME_LEADS; no conversionEvent. LEAD_GENERATION = every submitted form; QUALITY_LEAD = Meta's conversion leads, which only learns when CRM stages are sent back.","type":"object","properties":{"optimization":{"default":"LEAD_GENERATION","type":"string","enum":["LEAD_GENERATION","QUALITY_LEAD"]}}}},"required":["name","countries"]}]},"creatives":{"minItems":1,"maxItems":20,"type":"array","items":{"anyOf":[{"type":"object","properties":{"name":{"type":"string","minLength":1},"mediaUrl":{"type":"string","format":"uri","description":"A public https URL Meta can fetch."}},"required":["name","mediaUrl"]},{"type":"object","properties":{"name":{"type":"string","minLength":1},"assetId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"A library upload (meta_list_creatives): launched from its stored original and linked to it."}},"required":["name","assetId"]},{"type":"object","properties":{"name":{"type":"string","minLength":1},"media":{"minItems":2,"maxItems":2,"type":"array","items":{"type":"object","properties":{"ratio":{"type":"string","enum":["4x5","1x1","9x16"]},"url":{"type":"string","format":"uri"},"assetId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["ratio"]},"description":"ONE ad from two files: a 9x16 (Stories and Reels) and a 4x5 or 1x1 (every other placement), each by url or library assetId. The name carries no ratio."}},"required":["name","media"]}]}},"copy":{"description":"Omit to take the preset's: the angle's approved messaging (when the preset writes from the recipe) or its fallback copy, with its destination.","type":"object","properties":{"primaryText":{"type":"string","minLength":1,"maxLength":5000},"headline":{"type":"string","minLength":1,"maxLength":40},"description":{"type":"string","maxLength":200},"cta":{"default":"LEARN_MORE","type":"string","enum":["LEARN_MORE","SHOP_NOW","SIGN_UP","SUBSCRIBE","DOWNLOAD","GET_OFFER","GET_QUOTE","CONTACT_US","APPLY_NOW"]},"link":{"description":"The website. Omit for an instant-form ad.","type":"string","format":"uri"},"urlTags":{"description":"Query string appended to the link, e.g. utm_source=meta.","type":"string"},"leadFormId":{"description":"The instant form the ad opens (meta_list_lead_forms). Needs an instant-form ad set; the CTA must be one Meta offers on a form (LEARN_MORE, SIGN_UP, GET_QUOTE, APPLY_NOW, DOWNLOAD, SUBSCRIBE).","type":"string","pattern":"^\\d+$"}},"required":["primaryText","headline"]},"pageId":{"description":"The Facebook Page the ads publish under. Omit for the workspace default.","type":"string","pattern":"^\\d+$"},"pixelId":{"description":"The Pixel for conversion tracking. Omit for the workspace default.","type":"string","pattern":"^\\d+$"},"testId":{"description":"The Test these ads run for: the launch and its ads are linked to it. Still PAUSED.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"briefId":{"description":"The brief these ads were made from: the launch is linked to it, and the brief goes live when an ad first delivers. Still PAUSED.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["creatives"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_save_preset","title":"savePreset","description":"Create a launch preset, or update one (presetId). `config` is laid over the stored config (or the defaults), group by group — pass only what changes. Not money-moving: it spends nothing; meta_launch_ads reads it. A workspace's first preset becomes its default; makeDefault moves the default. Launchable today: an instant form or a website destination, Advantage+ audience off, CBO (one campaign budget = ad sets × dailyPerAdset). `problems` in the result says what still stops it from launching.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"presetId":{"description":"Omit to create a preset.","type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"description":"Required to create. Also a good campaign name.","type":"string","minLength":1,"maxLength":120},"config":{"type":"object","properties":{"target":{"type":"object","properties":{"mode":{"type":"string","enum":["new","existing"],"description":"new: each batch creates ad sets (and the campaign, by name) from this preset. existing: every ad goes into adSetId, which keeps its own audience, budget, placements and optimisation."},"campaignId":{"anyOf":[{"type":"string","pattern":"^\\d+$"},{"type":"null"}],"description":"existing: the campaign that holds adSetId."},"adSetId":{"anyOf":[{"type":"string","pattern":"^\\d+$"},{"type":"null"}],"description":"existing: the ad set the ads go into."},"campaignName":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}],"description":"existing: shown, never sent."},"adSetName":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}],"description":"existing: shown, never sent."}}},"destination":{"type":"object","properties":{"type":{"type":"string","enum":["form","website","whatsapp"]},"formId":{"anyOf":[{"type":"string","pattern":"^\\d+$"},{"type":"null"}],"description":"form: the instant form the ads open."},"url":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}],"description":"website: the landing page, without a query string."},"utmTemplate":{"type":"string","maxLength":500,"description":"website: the URL tags every ad carries. Meta macros like {{ad.name}} resolve."},"conversionEvent":{"anyOf":[{"type":"string","enum":["PURCHASE","INITIATE_CHECKOUT","ADD_TO_CART","LEAD","COMPLETE_REGISTRATION","START_TRIAL","SUBSCRIBE"]},{"type":"null"}],"description":"website: the pixel event the ad sets optimise for. Null = link clicks."}}},"audience":{"type":"object","properties":{"countries":{"maxItems":25,"type":"array","items":{"type":"string","pattern":"^[A-Z]{2}$"}},"ageMin":{"type":"integer","minimum":13,"maximum":65},"ageMax":{"type":"integer","minimum":13,"maximum":65},"languages":{"maxItems":10,"type":"array","items":{"type":"string","pattern":"^[a-z]{2}$"},"description":"Saved with the preset. Not sent to Meta as targeting yet."},"advantageAudience":{"type":"boolean","description":"Let Meta go beyond the audience. Launches keep it off; true is not launchable yet."}}},"budget":{"type":"object","properties":{"dailyPerAdset":{"anyOf":[{"type":"number","exclusiveMinimum":0,"maximum":1000000},{"type":"null"}],"description":"Daily budget per ad set, account currency, major units (150 = 150.00)."},"control":{"type":"string","enum":["ABO","CBO"],"description":"CBO: one campaign budget, ad sets × the per-ad-set budget. ABO is stored but not launchable yet."},"split":{"type":"string","enum":["batch","angle"],"description":"angle: one ad set per angle in the batch. batch: one ad set for everything."}}},"copy":{"type":"object","properties":{"aiFromRecipe":{"type":"boolean","description":"Write each ad's copy from its angle's approved messaging (Research). Falls back to the copy below."},"primaryText":{"type":"string","maxLength":5000},"headline":{"type":"string","maxLength":40},"cta":{"type":"string","enum":["LEARN_MORE","SHOP_NOW","SIGN_UP","SUBSCRIBE","DOWNLOAD","GET_OFFER","GET_QUOTE","CONTACT_US","APPLY_NOW"]},"language":{"type":"string","pattern":"^(auto|[a-z]{2})$","description":"auto = the creative's own locale; otherwise the locale for files with no name."}}},"naming":{"type":"object","properties":{"campaign":{"type":"string","maxLength":200,"description":"The campaign the batches launch into, by name: reused when it exists, else created."},"pattern":{"type":"string","maxLength":40,"description":"The ad-name id for files dropped without a canonical name: {MMDD}, {YYMMDD}."}}}}},"makeDefault":{"type":"boolean"}}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_save_report_view","title":"saveReportView","description":"Save an Ads report (/app/ads) as a named view, or update one (`view` = its slug). `query` is the report's URL state as `{ key: value }` strings (or a `?key=value` string) — period / since / until, group (creative, ad, copy, landing, campaign, adset, country, concept, or a tag Dimension), f (filters, `field:op:value` joined by `~`), m (metrics, comma-separated), sort (`metric.asc|desc`), view (grid / bar / line / table), vs=prev (week over week); defaults are dropped. Spends nothing and stores no numbers: a view is re-asked live (meta_get_report_view). `shared` (default true) shows it to the whole workspace; a private view only to its creator. `makeDefault` makes it what the bare page opens on (and shares it). Workspace templates (meta_list_report_views) cannot be changed — save a copy.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"view":{"description":"An existing saved view's slug to update. Omit to create one.","type":"string","minLength":1,"maxLength":64},"name":{"description":"Required to create.","type":"string","minLength":1,"maxLength":120},"path":{"description":"The report page. Default: the Ads report.","type":"string","enum":["/app/creatives","/app/compare"]},"query":{"description":"The report URL state. Omit on an update to keep it.","anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},{"type":"string"}]},"template":{"description":"The template it starts from (its prompts follow it).","type":"string"},"shared":{"type":"boolean"},"makeDefault":{"type":"boolean"}}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_create_lead_form","title":"createLeadForm","description":"Create an instant (lead) form on the Page. Not money-moving: it spends nothing until an ad opens it. A published form cannot be edited — a change is a new form. Ask for an EMAIL, PHONE or WHATSAPP_NUMBER; give every CUSTOM question a snake_case key the CRM maps on, and make multiple-choice option values match the labels the CRM expects. `higherIntent` (default true) adds a review screen before submit: fewer, better leads.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"locale":{"description":"Meta's form locale, e.g. EN_US, PL_PL. Default: the Page's.","type":"string","pattern":"^[A-Za-z]{2}_[A-Za-z]{2}$"},"questions":{"minItems":1,"maxItems":15,"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["FULL_NAME","FIRST_NAME","LAST_NAME","EMAIL","WORK_EMAIL","PHONE","WHATSAPP_NUMBER","CITY","COUNTRY","COMPANY_NAME","JOB_TITLE","CUSTOM"]},"key":{"description":"CUSTOM only, required: the field name the answer arrives under — what the CRM maps on. Prefilled types arrive as email, phone_number, full_name…","type":"string","pattern":"^[a-z][a-z0-9_]{0,63}$"},"label":{"description":"CUSTOM only, required: the question.","type":"string","minLength":1,"maxLength":200},"options":{"description":"CUSTOM only: multiple choice. `value` is the text the lead carries.","maxItems":20,"type":"array","items":{"type":"object","properties":{"key":{"type":"string","minLength":1,"maxLength":64},"value":{"type":"string","minLength":1,"maxLength":100}},"required":["key","value"]}}},"required":["type"]}},"privacyPolicy":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"linkText":{"type":"string","maxLength":70}},"required":["url"]},"intro":{"description":"The intro screen.","type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":60},"style":{"default":"paragraph","type":"string","enum":["paragraph","list"]},"content":{"minItems":1,"maxItems":5,"type":"array","items":{"type":"string","minLength":1,"maxLength":300}}},"required":["title","content"]},"thankYou":{"description":"The screen after submit.","type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":60},"body":{"type":"string","minLength":1,"maxLength":300},"buttonType":{"default":"NONE","type":"string","enum":["VIEW_WEBSITE","CALL_BUSINESS","WHATSAPP","NONE"]},"buttonText":{"type":"string","maxLength":30},"websiteUrl":{"type":"string","format":"uri"},"phone":{"description":"E.164, for CALL_BUSINESS and WHATSAPP.","type":"string"}},"required":["title","body"]},"higherIntent":{"default":true,"type":"boolean"},"pageId":{"description":"Omit for the workspace's default Page.","type":"string","pattern":"^\\d+$"}},"required":["name","questions","privacyPolicy"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_send_test_lead","title":"sendTestLead","description":"Send a TEST lead through an instant form: Meta delivers it to the lead webhook like a real one, so it runs the whole chain (CRM, first-touch WhatsApp…). Use it to prove the chain before activating — and put the OPERATOR's own phone and email in it, never a customer's. Meta keeps one test lead per form: pass the previous test lead's id as replaceLeadId to delete it first. `answers` maps field names (email, phone_number, full_name, or a CUSTOM key) to the value.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"formId":{"type":"string","pattern":"^\\d+$"},"answers":{"type":"object","propertyNames":{"type":"string","minLength":1},"additionalProperties":{"type":"string"}},"replaceLeadId":{"type":"string","pattern":"^\\d+$"},"pageId":{"type":"string","pattern":"^\\d+$"}},"required":["formId","answers"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_activate","title":"activate","description":"MONEY-MOVING. Flip a launch's ads, ad set and campaign to ACTIVE. Only call after the human explicitly said to activate this launch.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"launchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["launchId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_relink_launch","title":"relinkLaunch","description":"Change the CTA, destination URL, URL tags and/or ad text (primary text, headline, description) on every ad of a launch after the fact. Omitted fields keep the launch's copy; the ad ids stay the same. Rebuilds each ad's creative (Meta creatives are immutable) and repoints the ad: active ads go back through review, the post's likes and comments do not carry over, and Meta treats it as a significant edit (learning restarts). Change link and text in ONE call so the ads are reviewed once.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"launchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"cta":{"type":"string","enum":["LEARN_MORE","SHOP_NOW","SIGN_UP","SUBSCRIBE","DOWNLOAD","GET_OFFER","GET_QUOTE","CONTACT_US","APPLY_NOW"]},"link":{"type":"string","format":"uri"},"urlTags":{"description":"Replaces the tags; empty string clears them.","type":"string"},"primaryText":{"type":"string","minLength":1,"maxLength":5000},"headline":{"type":"string","minLength":1,"maxLength":40},"description":{"description":"Replaces the description; empty string clears it.","type":"string","maxLength":200}},"required":["launchId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_pause_launch","title":"pauseLaunch","description":"Pause a launch's ads (the ad set and campaign are left alone — other ads may share them).","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"launchId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["launchId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_set_ad_status","title":"setAdStatus","description":"Pause or resume ONE ad by its Meta ad id (from meta_get_ad_performance or meta_suggest_next) — how a `cut` verdict is acted on. Only the ad changes; its ad set and campaign are left alone. PAUSED stops spend. ACTIVE is MONEY-MOVING: only call it after the human explicitly said to resume this ad. Returns effectiveStatus, which stays ADSET_PAUSED / CAMPAIGN_PAUSED when a parent is off.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"adId":{"type":"string","pattern":"^\\d+$"},"status":{"type":"string","enum":["ACTIVE","PAUSED"]}},"required":["adId","status"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_update_ad_set_targeting","title":"updateAdSetTargeting","description":"Change an EXISTING ad set's placements and/or age range (ad set ids from meta_list_campaigns). Only the fields passed change; geo, interests and the rest of Meta's targeting are kept. A significant edit: the ad set re-enters learning, so put every targeting change for an ad set in ONE call, and confirm the ad set and values with the human first. Returns before / after.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"adSetId":{"type":"string","pattern":"^\\d+$"},"placements":{"type":"string","enum":["facebook_instagram","automatic"],"description":"facebook_instagram (default): Facebook + Instagram only — no Audience Network, Messenger, Threads or WhatsApp. automatic: Meta's Advantage+ placements, Audience Network included."},"ageMin":{"type":"integer","minimum":13,"maximum":65},"ageMax":{"type":"integer","minimum":13,"maximum":65}},"required":["adSetId"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}},{"name":"meta_update_strategy","title":"updateStrategy","description":"Change the workspace's brand & strategy (Settings → Brand & strategy). `patch` holds only the fields to change: product, offer, icp (text; null clears), pains / dos / donts (lists — each REPLACES the list, so read meta_get_strategy first and send the whole list), proofPoints ([{ text, source }] — replaces the list; only claims the brand makes, with where it makes them), capacity ({ formats: [{ name, perWeek }] }). The goal and its target are refused here — they are meta_set_thresholds'. `mode: suggest` stores each field as a pending suggestion the operator accepts or dismisses instead of writing it (use it for anything you inferred rather than were told). Every write is attributed to the agent and shown on the page. Not money-moving.","inputSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"patch":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Only the fields to change."},"mode":{"default":"write","type":"string","enum":["write","suggest"]}},"required":["patch"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true}}]}