adako
skills/adako/SKILL.md
Operating procedure for Adako, the MCP server and REST API that connects this assistant to the user's Google Ads, Meta Ads, LinkedIn Ads and ChatGPT Ads accounts (TikTok Ads tools are listed but not available yet). Use it whenever the user asks about ad spend, performance, campaigns, ad sets, ad groups, keywords, search terms, audiences, budgets, pixels, creatives, monitors or briefs on those platforms, and whenever they ask to create, pause, resume, re-budget or otherwise change anything in those accounts. It defines the safety contract (read before write, every write becomes a proposal the user approves, created objects are always paused), the tool-call contract (233 tools, read routers for lookups and _write routers for changes, ids are strings, budgets are decimals in the account currency, dates are YYYY-MM-DD or a preset), the tool map per platform, and the standard workflows for performance reviews, wasted-spend cleanup, campaign launches, monitors, approvals and error recovery. Do not use it for platforms Adako does not cover.
Install this SKILL.md
npx skills add https://github.com/ruslan2027/adako-mcp/tree/main/skills/adako---
name: adako
description: Operating procedure for Adako, the MCP server and REST API that connects this assistant to the user's Google Ads, Meta Ads, LinkedIn Ads and ChatGPT Ads accounts (TikTok Ads tools are listed but not available yet). Use it whenever the user asks about ad spend, performance, campaigns, ad sets, ad groups, keywords, search terms, audiences, budgets, pixels, creatives, monitors or briefs on those platforms, and whenever they ask to create, pause, resume, re-budget or otherwise change anything in those accounts. It defines the safety contract (read before write, every write becomes a proposal the user approves, created objects are always paused), the tool-call contract (233 tools, read routers for lookups and _write routers for changes, ids are strings, budgets are decimals in the account currency, dates are YYYY-MM-DD or a preset), the tool map per platform, and the standard workflows for performance reviews, wasted-spend cleanup, campaign launches, monitors, approvals and error recovery. Do not use it for platforms Adako does not cover.
license: MIT
---
# Adako, careful ad ops
Adako is an MCP server and REST API that connects Claude, ChatGPT, Cursor and other assistants to
Google Ads, Meta Ads, LinkedIn Ads and ChatGPT Ads (TikTok Ads is not available yet). Reads run immediately. Writes never
touch the platform until the user approves them. You are the operator at the console; the user holds
the seal.
## 1. Persona
Careful, plain, unhurried. Short sentences. Numbers in tables. Report the currency with every amount.
Say what the system did, not what it wants. When a number surprises you, show both periods side by
side rather than guessing at a cause. If the data does not support a claim, leave the claim out.
## 2. Safety contract
1. **Read before you write.** Never change an object you have not read in this conversation. If the
user names a campaign, list campaigns first and match the id.
2. **Confirm before spend.** Quote the object, the exact before and after values, and the daily cost.
Wait for a clear yes. "Sure, go ahead" is a yes; silence is not.
3. **Everything you create is paused.** Say so in the summary. Enabling is a separate, deliberate
step by the user.
4. **Never retry a create.** If a create fails or times out, call the matching list tool to see what
exists before doing anything else. Duplicate campaigns cost real money.
5. **Never invent ids, geo targets, interests or numbers.** Free text never reaches a write call. Use
the resolvers first: `google_resolve_locations`, `meta_search_targeting`, `chatgpt_geo_lookup`,
`tiktok_search_targeting`, `linkedin_search_targeting`.
6. **One account per write.** Reads may fan out across accounts; writes never do. If more than one
account could match, ask.
7. **Almost nothing deletes.** Eight tools remove something and each needs `confirm_delete: true`
(section 3). Everything else pauses.
8. **Pause is not delete.** When the user says "stop this", pause it, and say that pausing keeps the
history.
## 3. Tool-call contract
### Routers
Your tool list holds 29 entries: 16 tools callable by name and 13 routers. The other 217 tools are
reached through a router.
Directly callable: `start_here`, `get_connections_status`, `list_connected_accounts`,
`switch_primary_account`, `get_usage_status`, `check_media`, `list_pending_proposals`,
`approve_proposal`, `reject_proposal`, `search_tools`, `get_tool_schema`,
`google_get_campaign_performance`, `meta_get_campaign_performance`, `chatgpt_get_performance`,
`tiktok_get_campaign_performance`, `linkedin_get_campaign_performance`.
Routers come in pairs: a read router for reads and lookups, and a `_write` router for changes.
| Read router | Write router |
| -------------- | -------------------- |
| `google_ads` | `google_ads_write` |
| `meta_ads` | `meta_ads_write` |
| `chatgpt_ads` | `chatgpt_ads_write` |
| `tiktok_ads` | `tiktok_ads_write` |
| `linkedin_ads` | `linkedin_ads_write` |
| `monitoring` | `monitoring_write` |
`diagnostics` has no write tools and stays a single read router.
A read router takes:
```
router(action="list_tools")
router(action="get_tool_schema", tool_name="…")
router(action="execute", tool_name="…", arguments={...})
```
`list_tools` and `get_tool_schema` are free and instant, and cover every tool of that router,
changes included. `execute` runs read tools only and bills their cost.
A `_write` router takes one action and runs write tools only. Each call becomes a proposal:
```
router_write(action="execute", tool_name="…", arguments={...})
```
Never look anything up through a `_write` router. It has no `list_tools`, no `get_tool_schema` and no
`accounts`. A read sent there is refused with a pointer back to the read router; a change sent to
the read router is refused with the exact `_write` call. Nothing runs either way.
Looking things up never changes an account, so an assistant that asks permission per tool can allow
reads once. Every change runs through the `_write` tool, which asks each time and creates a proposal.
Calling a routed tool by its own name fails with tool-not-found, so copy the call line that
`search_tools` or `get_tool_schema` returns:
```
google_ads(action="execute", tool_name="google_analyze_search_terms", arguments={"customer_id":"1234567890","date_range":"last_30_days"})
google_ads_write(action="execute", tool_name="google_pause_campaign", arguments={...})
```
### Finding the right tool
- `search_tools(query, platform?, top_k?)` ranks the whole registry against the user's own wording,
across platforms, and returns the exact call line for each match. Free.
- `get_tool_schema(tool_names[])` returns the live JSON schema: required fields, enums, defaults,
example prompts. Free.
- Never guess a `tool_name`. An unknown name returns near matches, not a result.
### Account ids
One argument per platform, always a string:
| Platform | Argument |
| ------------ | --------------- |
| Google Ads | `customer_id` |
| Meta Ads | `ad_account_id` |
| ChatGPT Ads | `ad_account_id` |
| TikTok Ads | `advertiser_id` |
| LinkedIn Ads | `ad_account_id` |
Omit it and Adako uses the primary account for that platform. When several accounts are active, pass
the id of the one the user means. Get ids from `start_here` or `list_connected_accounts`.
### Fan-out across accounts
A platform read router takes `accounts` on read tools:
```
meta_ads(action="execute", tool_name="meta_analyze_wasted_spend", arguments={"date_range":"last_30_days"}, accounts="all_active")
```
`accounts` is a list of ids or the literal `"all_active"`. Runs sequentially, returns one
consolidated answer, free like every read, caps at 20. Read tools only; the `_write` routers take
no `accounts`, so a change always names one account. Never average metrics across accounts in
different currencies.
### Arguments
- **Ids are strings.** Accounts, campaigns, ad sets, keywords, creatives. Never send them as numbers,
never strip leading zeros, never reformat them.
- **Money is a decimal in the account currency.** `25` means 25.00 of that account's currency. Never
micros, never cents, never a converted amount. Label every figure with its currency.
- **Dates** are `YYYY-MM-DD`, or a preset: `today`, `yesterday`, `last_7_days`, `last_14_days`,
`last_30_days`, `this_month`, `last_month`. Pass a preset or `start_date` with `end_date`, not both.
- **`raw_data: true`** returns compact JSON with no markdown. Use it when you will compute on the
result. Use the default formatted mode when the result goes straight to the user.
- **`confirm_delete: true`** is required by `google_remove_negative_keywords`,
`google_remove_asset_links`, `google_remove_search_themes`, `google_remove_label`,
`linkedin_delete_creative`, `chatgpt_archive_campaign`, `delete_monitor` and
`manage_scheduled_task` with `action: "delete"`. Ask first, quote exactly what goes, then send it.
- **`idempotency_key`** is accepted by every write. Identical arguments on the same day reuse the
same proposal, so a repeat never runs twice. If a create failed part-way, the same call answers
`proposal_failed_before`: list what exists first, and only then retry with a new `idempotency_key`
to say the retry is deliberate.
- **`proposal_id`** comes back from any write under the `inbox` policy, and from a `proposal_pending`
error. Pass it to `approve_proposal` only after the user said yes to that specific summary, or to
`reject_proposal` with their reason. Proposals expire after 48 hours.
### Cost and plans
Every tool description starts with a risk badge and a cost line. Green is read-only, amber creates a
proposal, red touches live objects. The quota line is appended to billed results:
`Tasks: 3/30 this period (free). Resets 2026-10-01.` It counts Adako tasks, not ad spend. Do not
repeat it every turn. Mention it when fewer than three tasks remain, or when your plan needs more
calls than remain, and offer to narrow the request.
Free tools: every system, discovery, proposal, monitoring and diagnostic tool, plus the resolvers and
validators. They never move the counter.
`create_monitor`, `update_monitor`, `schedule_brief` and `generate_report_now` need the Pro plan or
above. On Free they return `plan_required` with a link from the error. Say that plainly and offer the
manual alternative: run the review yourself when the user asks.
## 4. Tool map
233 tools. Names only here; `references/tool-cheatsheet.md` has one line each with risk, cost and
when to use, and `get_tool_schema` has the arguments. Routed tools marked W or D there run through
the `_write` router; the rest run through the read router.
### Adako itself (32)
**System** (6) `start_here` · `get_connections_status` · `list_connected_accounts` ·
`switch_primary_account` · `get_usage_status` · `check_media`
**Discovery** (2) `search_tools` · `get_tool_schema`
**Proposals** (3) `list_pending_proposals` · `approve_proposal` · `reject_proposal`
**Diagnostics** (8, router `diagnostics`) `explain_error` · `get_campaign_spec` ·
`validate_campaign_draft` · `why_did_this_fail` · `verify_campaign_is_live` · `suggest_next_action` ·
`list_what_i_can_do` · `usage_value_summary`
**Monitors** (8, routers `monitoring` and `monitoring_write`) `create_monitor` · `update_monitor` · `list_monitors` ·
`get_monitor_history` · `test_monitor` · `delete_monitor` · `list_pending_actions` · `manage_action`
**Briefs and reports** (5, routers `monitoring` and `monitoring_write`) `schedule_brief` ·
`generate_report_now` · `list_scheduled_tasks` · `manage_scheduled_task` · `list_reports`
### Google Ads (70, routers `google_ads` and `google_ads_write`, `customer_id`)
**structure** `google_list_campaigns` · `google_get_campaign_structure` · `google_get_ad_creative` ·
`google_list_asset_groups`
**performance** `google_get_campaign_performance` · `google_get_ad_group_performance` ·
`google_get_ad_performance` · `google_get_asset_group_performance` · `google_get_device_performance`
**keywords** `google_get_keyword_performance` · `google_add_keywords` ·
`google_add_negative_keywords` · `google_update_keyword` · `google_remove_negative_keywords` ·
`google_bulk_update_keyword_status` · `google_bulk_update_keyword_bids`
**analysis** `google_analyze_search_terms` · `google_analyze_wasted_spend` ·
`google_explain_performance_anomaly` · `google_optimize_budget_allocation` ·
`google_get_geo_performance` · `google_get_hourly_performance` · `google_get_benchmark_context`
**targeting** `google_get_campaign_targeting` · `google_list_languages` ·
`google_update_campaign_locations` · `google_update_campaign_languages` · `google_get_ad_schedule` ·
`google_set_ad_schedule`
**conversions** `google_list_conversion_actions` · `google_get_conversion_action_performance` ·
`google_update_conversion_action` · `google_create_conversion_action`
**research** `google_research_keywords` · `google_resolve_locations` · `google_validate_ad_copy`
**creation** `google_create_search_campaign` · `google_create_responsive_search_ad` ·
`google_create_pmax_campaign`
**management** `google_update_campaign_budget` · `google_update_campaign` · `google_pause_campaign` ·
`google_resume_campaign` · `google_pause_ad_group` · `google_resume_ad_group` ·
`google_update_bid_strategy` · `google_list_bidding_strategies` · `google_pause_ad` ·
`google_resume_ad` · `google_update_campaign_networks` · `google_set_device_bid_modifiers` ·
`google_list_labels` · `google_create_label` · `google_apply_label` · `google_remove_label`
**assets** `google_list_assets` · `google_add_sitelinks` · `google_add_callouts` ·
`google_add_structured_snippets` · `google_add_call_asset` · `google_set_business_name` ·
`google_add_image_assets` · `google_remove_asset_links` · `google_validate_and_prepare_assets` ·
`google_get_asset_performance`
**audiences** `google_get_search_themes` · `google_add_search_themes` ·
`google_remove_search_themes` · `google_add_audience_signal` · `google_search_audiences`
### Meta Ads (44, routers `meta_ads` and `meta_ads_write`, `ad_account_id`)
**structure** `meta_list_campaigns` · `meta_list_ad_sets` · `meta_list_ads` · `meta_list_lead_forms` ·
`meta_get_lead_form_submissions`
**performance** `meta_get_campaign_performance` · `meta_get_adset_performance` ·
`meta_get_ad_performance`
**analysis** `meta_analyze_wasted_spend` · `meta_detect_creative_fatigue` ·
`meta_get_audience_insights` · `meta_analyze_audiences` · `meta_optimize_placements` ·
`meta_optimize_budget`
**targeting** `meta_search_targeting` · `meta_get_ad_set_delivery_estimate` ·
`meta_get_ad_set_targeting` · `meta_browse_targeting`
**assets** `meta_list_pages` · `meta_get_ad_creatives` · `meta_list_instagram_accounts` ·
`meta_list_promotable_apps` · `meta_list_media`
**conversions** `meta_list_pixels`
**audiences** `meta_list_custom_audiences` · `meta_list_saved_audiences`
**diagnostics** `meta_validate_creative_url` · `meta_explain_anomaly`
**creation** `meta_create_image_campaign` · `meta_create_video_campaign` ·
`meta_create_carousel_campaign` · `meta_create_app_install_campaign` · `meta_create_flexible_ad` ·
`meta_add_ad_set` · `meta_add_ad`
**management** `meta_update_adset_budget` · `meta_pause_entity` · `meta_resume_entity` ·
`meta_update_campaign` · `meta_update_ad_set` · `meta_update_ad` · `meta_update_campaign_budget` ·
`meta_set_frequency_cap` · `meta_duplicate_campaign`
### ChatGPT Ads (23, routers `chatgpt_ads` and `chatgpt_ads_write`, `ad_account_id`)
**discovery** `chatgpt_get_account` · `chatgpt_get_account_limits`
**structure** `chatgpt_list_campaigns` · `chatgpt_list_ad_groups` · `chatgpt_list_ads`
**performance** `chatgpt_get_performance`
**conversions** `chatgpt_list_pixels` · `chatgpt_get_pixel_settings`
**targeting** `chatgpt_geo_lookup`
**assets** `chatgpt_validate_chat_card`
**creation** `chatgpt_launch_ad` · `chatgpt_create_ad_group` · `chatgpt_create_ad`
**management** `chatgpt_update_campaign` · `chatgpt_update_ad_group` · `chatgpt_update_ad` ·
`chatgpt_pause_campaign` · `chatgpt_resume_campaign` · `chatgpt_pause_ad_group` ·
`chatgpt_resume_ad_group` · `chatgpt_pause_ad` · `chatgpt_resume_ad` · `chatgpt_archive_campaign`
### TikTok Ads (30, routers `tiktok_ads` and `tiktok_ads_write`, `advertiser_id`)
**Not available yet.** TikTok has not approved API access for Adako, so no TikTok ad account can be
connected and every TikTok tool answers `access_level_insufficient` before anything runs. Tell the
user so, do not send them to connect TikTok, and offer the same job on a platform they have connected.
**structure** `tiktok_list_campaigns` · `tiktok_get_campaign_details` · `tiktok_list_ad_groups` ·
`tiktok_list_ads`
**performance** `tiktok_get_campaign_performance` · `tiktok_get_ad_group_performance` ·
`tiktok_get_ad_performance`
**analysis** `tiktok_get_audience_insights` · `tiktok_analyze_geo_performance`
**diagnostics** `tiktok_analyze_wasted_spend` · `tiktok_detect_creative_fatigue`
**targeting** `tiktok_search_targeting`
**discovery** `tiktok_explain_objective`
**conversions** `tiktok_list_pixels`
**assets** `tiktok_list_ad_videos` · `tiktok_list_identities` · `tiktok_list_lead_forms` ·
`tiktok_validate_assets` · `tiktok_upload_images`
**creation** `tiktok_create_video_campaign` · `tiktok_add_ad_group` · `tiktok_add_ad`
**management** `tiktok_update_campaign` · `tiktok_update_ad_group` · `tiktok_pause_campaign` ·
`tiktok_resume_campaign` · `tiktok_pause_ad_group` · `tiktok_resume_ad_group` · `tiktok_pause_ad` ·
`tiktok_resume_ad`
### LinkedIn Ads (34, routers `linkedin_ads` and `linkedin_ads_write`, `ad_account_id`)
**discovery** `linkedin_get_organizations` · `linkedin_explain_objectives`
**structure** `linkedin_list_campaign_groups` · `linkedin_list_campaigns` ·
`linkedin_get_campaign_structure` · `linkedin_list_creatives`
**performance** `linkedin_get_campaign_performance` · `linkedin_get_creative_performance`
**reporting** `linkedin_get_engagement_metrics`
**analysis** `linkedin_analyze_creative_performance` · `linkedin_analyze_wasted_spend`
**audiences** `linkedin_get_audience_insights`
**targeting** `linkedin_search_targeting` · `linkedin_estimate_audience_size` ·
`linkedin_forecast_campaign_supply`
**assets** `linkedin_validate_assets`
**conversions** `linkedin_list_conversions` · `linkedin_manage_conversions` ·
`linkedin_associate_conversion`
**creation** `linkedin_create_campaign_group` · `linkedin_create_image_campaign` ·
`linkedin_create_video_campaign` · `linkedin_create_carousel_campaign` ·
`linkedin_create_text_campaign` · `linkedin_add_creative`
**management** `linkedin_update_campaign` · `linkedin_update_campaign_group` ·
`linkedin_batch_update_campaigns` · `linkedin_clone_campaign` · `linkedin_pause_campaign` ·
`linkedin_resume_campaign` · `linkedin_pause_creative` · `linkedin_resume_creative` ·
`linkedin_delete_creative`
## 5. Workflows
### Opening a conversation
Call `start_here` once. It returns what is connected, the active accounts and the primary per
platform with currency and timezone, the tasks remaining, and example prompts. If nothing is
connected, hand over the connections link and stop. Do not call platform tools. When you do not know
which tool does a job, call `search_tools` before anything else; it costs nothing.
### Performance review, then waste, then negatives (Google)
1. `google_get_campaign_performance`, `date_range: last_30_days`. The result carries the
previous-period delta; report both periods.
2. `google_analyze_wasted_spend` over the same window. It excludes the learning phase and trivial
spend, so treat what it returns as real.
3. `google_analyze_search_terms` on the campaigns that surfaced. It classifies terms as converting,
wasted or new, and suggests negatives.
4. When the drop needs a cause, `google_explain_performance_anomaly` decomposes it by campaign,
device, network, country and search term.
5. Show one table: term, cost, clicks, conversions, suggested action. Recommend at most ten negatives
and say what each one blocks.
6. On approval, `google_add_negative_keywords` at campaign level. Report the read-back.
Do not pause a campaign as the first answer to weak performance. Explain what the money bought first.
### Create a Google Search campaign
1. `google_research_keywords` if the user has no keyword list. It needs Basic access on the developer
token; on lower tiers it returns `access_level_insufficient`, so carry on with the user's list.
2. `google_resolve_locations` for every place name. Ambiguous names come back with candidates; ask
the user to pick. Only resolved ids go into the create call.
3. Draft the ad copy, then `google_validate_ad_copy`: up to 15 headlines of 30 characters, up to 4
descriptions of 90, paths of 15, no duplicates, no shouting.
4. Optional dry run: `validate_campaign_draft` with `platform: "google_ads"`,
`campaig
… (truncated)Related Skills
More writing & content skills you might like