Apple Ads MCP
The Apple Ads MCP server provides full programmatic access to the Apple Search Ads Campaign Management API v5 through 74 typed tools, enabling complete ad campaign lifecycle management, reporting, and account administration.
Account & Access
org_acls— Discover accessible organizations;me_user— Retrieve API user info
App & Geo Discovery
search_apps— Search App Store for targetable apps;search_geo/geo_lookup— Search and resolve geo entities (countries, admin areas, localities)
App Metadata & Custom Product Pages
Fetch app metadata, localized details, eligibility records, assets, preview devices, and supported countries/regions
List, get, and inspect locale details for Custom Product Pages (
cpp_list,cpp_get,cpp_locale_details)
Campaigns — Full CRUD: create, get, list, find (with selector filters), update, and delete campaigns (budget, targeting regions, ad channels, billing events)
Ad Groups — Full CRUD including campaign-scoped and org-wide search; configure bids, pricing models, targeting dimensions (age, gender, location, device), and automated keyword discovery
Creatives — Create, list, get, and find creatives referencing Default/Custom Product Pages or Creative Sets
Ads — Full CRUD with campaign-scoped and org-wide search; link ads to specific creatives
Keywords
Targeting keywords: Bulk-create (up to 1000), get, list, find, bulk-update, and bulk-delete with match types and bids
Ad-group negative keywords: Bulk CRUD at the ad group level
Campaign negative keywords: Bulk CRUD at the campaign level (apply to all ad groups)
Performance Reports
Campaign, ad group, keyword, search-term, and ad-level reports
Support
granularity(HOURLY/DAILY/WEEKLY/MONTHLY) andgroupBy(country, device, age, gender)
Impression Share Reports — Create, poll (custom_reports_get), and list async Share-of-Voice reports
Budget Orders (LOC accounts) — Create, get, list, and update line-of-credit budget orders (no delete in v5)
Rejection Reason Audit — Find and fetch reasons why creatives were rejected by Apple's review team
Escape Hatch — apple_search_ads_request calls any v5 API endpoint directly with authentication and org context handled automatically
Provides tools for managing Apple Search Ads campaigns, ad groups, keywords, creatives, reports, and more through the Apple Ads Campaign Management API v5.
apple-search-ads-mcp
A Model Context Protocol (MCP) server that wraps the full Apple Search Ads (now Apple Ads) Campaign Management API v5. 74 typed tools, 1:1 mapping to every documented v5 endpoint — campaigns, ad groups, ads, creatives, custom product pages, keywords, negative keywords, reports, impression-share reports, budget orders, ACLs, geo/app search, app metadata, rejection-reason audits — plus a raw passthrough for any future endpoints.
API lifecycle: Apple Ads (Search Ads) v5 is the current production API. v5 sunsets January 26, 2027 in favour of the new "Apple Ads Platform API" arriving Summer 2026. This server targets v5.0 → v5.5.
Quick install
git clone https://github.com/AppVisionOS/apple-search-ads-mcp.git
cd apple-search-ads-mcp
npm install
npm run buildThen register with Claude Code in one line:
claude mcp add apple-search-ads --scope user \
-e ASA_CLIENT_ID=SEARCHADS.xxxx \
-e ASA_TEAM_ID=SEARCHADS.xxxx \
-e ASA_KEY_ID=xxxx \
-e ASA_PRIVATE_KEY_PATH=/absolute/path/to/asa-private.p8 \
-e ASA_ORG_ID=1234567 \
-- node $(pwd)/dist/index.jsRelated MCP server: aapl-ads-mcp
Setup
1. Get API credentials
The Apple Ads UI splits credentials across two screens. The API tab inside Account Settings only manages access for third-party service providers; for your own programmatic access, the flow goes through User Management first.
a) Invite an API user
In app-ads.apple.com → Account Settings → User Management → Invite User:
Email: any address you control (can be your own; Apple requires a separate Apple ID for the API user)
Role: pick one with API permissions (e.g. API Account Manager)
Send the invite, then accept it from the invited inbox
b) Generate the key pair locally
While the invite is being processed, generate an ES256 key pair on your machine. Make sure it's PKCS#8 — Apple's .p8 examples and the older openssl ecparam output are not PKCS#8 and jose can't load them.
# CORRECT — produces PKCS#8 (-----BEGIN PRIVATE KEY-----)
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out asa-private.p8
openssl ec -in asa-private.p8 -pubout -out asa-public.pem
# If you already produced traditional EC (-----BEGIN EC PRIVATE KEY-----), convert it:
# openssl pkcs8 -topk8 -nocrypt -in asa-private.p8 -out asa-private-pkcs8.p8Keep asa-private.p8 somewhere safe (e.g. ~/.apple-search-ads/, chmod 600). You'll only paste the public half into Apple.
c) Generate the API client
Sign out and sign back in as the invited API user (not the admin account). Go to Account Settings → API. You'll see a Client Credentials screen with a Public Key textarea — this only appears for users who hold the API role.
Paste the contents of
asa-public.pem(with the-----BEGIN PUBLIC KEY-----/-----END PUBLIC KEY-----markers).Click Generate API Client.
Copy the three values Apple shows you: Client ID, Team ID, Key ID — these don't reappear later.
2. Install
npm install
npm run build3. Configure
Copy .env.example to .env and fill it in, or pass env vars through your MCP client.
ASA_CLIENT_ID=SEARCHADS.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
ASA_TEAM_ID=SEARCHADS.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
ASA_KEY_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
ASA_PRIVATE_KEY_PATH=/absolute/path/to/private-key.p8
ASA_ORG_ID=1234567 # optional default; can be overridden per callASA_PRIVATE_KEY (PEM contents inline, with \n escapes if injected via JSON) is supported as an alternative to ASA_PRIVATE_KEY_PATH.
4. Wire into your MCP client
{
"mcpServers": {
"apple-search-ads": {
"command": "node",
"args": ["/absolute/path/to/apple-search-ads-mcp/dist/index.js"],
"env": {
"ASA_CLIENT_ID": "SEARCHADS.xxxx...",
"ASA_TEAM_ID": "SEARCHADS.xxxx...",
"ASA_KEY_ID": "xxxx...",
"ASA_PRIVATE_KEY_PATH": "/absolute/path/to/private-key.p8",
"ASA_ORG_ID": "1234567"
}
}
}
}Authentication
The server handles OAuth 2.0 client-credentials flow with an ES256 JWT client assertion:
Sign a JWT with your
.p8private key (header:kid=Key ID,alg=ES256; payload:iss=Team ID,sub=Client ID,aud=https://appleid.apple.com).POST it to
https://appleid.apple.com/auth/oauth2/tokenwithgrant_type=client_credentialsandscope=searchadsorg.Use the returned 1-hour access token with
Authorization: Bearer …andX-AP-Context: orgId=…on every API call.
The token is cached in memory until ~30 s before expiry, so you sign one assertion and exchange one token per hour. On 401 the server force-refreshes and retries once. On 429/5xx it backs off (honouring Retry-After) up to 3 times.
Tool inventory (74 tools)
Account & access (2)
org_acls, me_user — call without an org context to discover what your token can do.
Discovery (3)
search_apps, search_geo, geo_lookup
App metadata (6)
apps_get, apps_locale_details, apps_eligibilities_find, apps_assets_find, creative_app_preview_devices, countries_or_regions_list
Custom Product Pages (3)
cpp_list, cpp_get, cpp_locale_details
Campaigns (6)
campaigns_create, campaigns_get, campaigns_list, campaigns_find, campaigns_update, campaigns_delete
Ad groups (7)
adgroups_create, adgroups_get, adgroups_list, adgroups_find_in_campaign, adgroups_find_org_wide, adgroups_update, adgroups_delete
Creatives (4)
creatives_create, creatives_list, creatives_get, creatives_find — creatives wrap a Custom Product Page, Default Product Page, or Creative Set reference. Ads bind to creatives via creativeId.
Ads (7)
ads_create, ads_get, ads_list, ads_find_in_campaign, ads_find_org_wide, ads_update, ads_delete
Targeting keywords (7)
targeting_keywords_create, targeting_keywords_get, targeting_keywords_list, targeting_keywords_find, targeting_keywords_update, targeting_keywords_delete (bulk), targeting_keywords_delete_single
Negative keywords — ad-group scope (6)
adgroup_negative_keywords_create, adgroup_negative_keywords_get, adgroup_negative_keywords_list, adgroup_negative_keywords_find, adgroup_negative_keywords_update, adgroup_negative_keywords_delete
Negative keywords — campaign scope (6)
campaign_negative_keywords_create, campaign_negative_keywords_get, campaign_negative_keywords_list, campaign_negative_keywords_find, campaign_negative_keywords_update, campaign_negative_keywords_delete
Reports (7)
Tool | Endpoint |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
All accept startTime, endTime, optional granularity (HOURLY/DAILY/WEEKLY/MONTHLY), optional groupBy (adminArea / ageRange / countryCode / countryOrRegion / deviceClass / gender / locality), selector, returnRowTotals, returnGrandTotals, returnRecordsWithNoMetrics, timeZone (UTC | ORTZ).
Impression Share Reports (3) — async
custom_reports_create → returns reportId. Poll with custom_reports_get until state=COMPLETED. List with custom_reports_list.
Budget Orders (4) — LOC accounts only
budget_orders_create, budget_orders_get, budget_orders_list, budget_orders_update. v5 has no delete for budget orders.
Rejection-reason audit (2)
product_page_reasons_find, product_page_reasons_get — read-only inspection of why Apple's reviewers rejected creatives.
Escape hatch (1)
apple_search_ads_request — call any path with any method. Auth and org context are still handled for you.
Selectors
*_find tools accept Apple's selector grammar:
{
"conditions": [
{ "field": "status", "operator": "EQUALS", "values": ["ENABLED"] },
{ "field": "countriesOrRegions", "operator": "CONTAINS_ANY", "values": ["US", "GB"] }
],
"fields": ["id", "name", "status"],
"orderBy": [{ "field": "name", "sortOrder": "ASCENDING" }],
"pagination": { "limit": 100, "offset": 0 }
}Operators: EQUALS, NOT_EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, GREATER_THAN, LESS_THAN, IN, NOT_IN, CONTAINS_ALL, CONTAINS_ANY, BETWEEN. values is always an array.
End-to-end example
A workflow you can drive entirely through Claude:
org_acls→ pick theorgId.search_appsfor your app → grab theadamId.campaigns_createwith that adamId, daily budget, US targeting,adChannelType=SEARCH,supplySources=["APPSTORE_SEARCH_RESULTS"],billingEvent=TAPS.adgroups_createinside the campaign withdefaultBidAmount={amount:"1.00",currency:"USD"}andpricingModel=CPC.targeting_keywords_createwith a batch of{text, matchType, bidAmount}rows.cpp_list→ pick a productPageId →creatives_createwithtype=CUSTOM_PRODUCT_PAGEto mint a creativeId →ads_createto bind it to the ad group.Wait a few days.
reports_campaignsfor top-line, thenreports_search_terms_in_campaignto harvest new keywords / negatives.custom_reports_createfor impression-share / share-of-voice on your top searches.
Known surface notes (v5 quirks)
No legacy creative-set CRUD. Apple removed it in v5; create a
creativesrow instead and reference it fromads.creativeId.No app categories endpoint. Use
apps_getand readprimaryGenre/secondaryGenre.No postal-code geo targeting. Geo entities in v5 are Country / AdminArea / Locality only.
No org-wide find for keywords or ad-group-scoped keyword find. Apple scopes targeting-keyword find at the campaign level (
/campaigns/{id}/adgroups/targetingkeywords/find) and rolls up across ad groups; filter byadGroupIdin the selector to narrow.No DELETE on budget orders. Update them, don't delete them.
Audiences, forecasting, conversion events are NOT in v5 — those live in separate Apple APIs (AdServices Attribution etc.).
Local development
npm run dev # tsc --watch
npm run typecheck # one-shot type check
npm run build # compile to dist/Use apple_search_ads_request to debug any endpoint directly — it returns the raw envelope so you can see the exact response shape Apple returned.
Available Tools
74 toolsadgroup_negative_keywords_createC
Bulk-create negative keywords on an ad group.
Inputs: campaignId (required), adGroupId (required), keywords (required), orgId.
adgroup_negative_keywords_deleteB
Bulk-delete ad-group-level negative keywords by ID.
Inputs: campaignId (required), adGroupId (required), keywordIds (required), orgId.
adgroup_negative_keywords_findB
Find ad-group-level negative keywords across all ad groups in a campaign with a selector.
Inputs: campaignId (required), selector (required), orgId.
adgroup_negative_keywords_getB
Fetch a single ad-group-level negative keyword by ID.
Inputs: campaignId (required), adGroupId (required), keywordId (required), orgId.
adgroup_negative_keywords_listB
List ad-group-level negative keywords (paginated).
Inputs: campaignId (required), adGroupId (required), limit, offset, +1 more.
adgroup_negative_keywords_updateC
Bulk-update ad-group-level negative keywords. Each entry must include id.
Inputs: campaignId (required), adGroupId (required), keywords (required), orgId.
adgroups_createB
Create an ad group within a campaign. Bid + targeting live here, not on the campaign.
Inputs: campaignId (required), name (required), startTime (required), defaultBidAmount (required), +9 more.
adgroups_deleteC
Delete an ad group.
Inputs: campaignId (required), adGroupId (required), orgId.
adgroups_find_in_campaignA
Find ad groups within a single campaign using a selector.
Inputs: campaignId (required), selector (required), orgId.
adgroups_find_org_wideA
Find ad groups across the entire org with a selector.
Inputs: selector (required), orgId.
adgroups_getC
Fetch a single ad group.
Inputs: campaignId (required), adGroupId (required), orgId.
adgroups_listC
List all ad groups in a campaign (paginated).
Inputs: campaignId (required), limit, offset, orgId.
adgroups_updateC
Update an ad group. Pass only the fields you want to change.
Inputs: campaignId (required), adGroupId (required), adGroup (required), orgId.
ads_createB
Create an ad inside an ad group. Ads bind a Creative (creativeId) to the ad group; the creative itself can wrap a Custom Product Page, Default Product Page, or Creative Set reference.
Inputs: campaignId (required), adGroupId (required), ad (required), orgId.
ads_deleteC
Delete an ad.
Inputs: campaignId (required), adGroupId (required), adId (required), orgId.
ads_find_in_campaignA
Find ads across all ad groups in a campaign with a selector.
Inputs: campaignId (required), selector (required), orgId.
ads_find_org_wideB
Find ads across the entire org with a selector.
Inputs: selector (required), orgId.
ads_getC
Fetch a single ad by ID.
Inputs: campaignId (required), adGroupId (required), adId (required), orgId.
ads_listB
List all ads in an ad group.
Inputs: campaignId (required), adGroupId (required), limit, offset, +1 more.
ads_updateB
Update an ad — typically status, name, or repointing to a different creativeId.
Inputs: campaignId (required), adGroupId (required), adId (required), ad (required), +1 more.
apple_search_ads_requestA
Escape hatch: call any Apple Search Ads endpoint by method + path. Authentication and org context are handled for you. Use only if no dedicated tool covers the endpoint you need.
Inputs: method (required), path (required), query, body, +2 more.
apps_assets_findB
Find App Store screenshots / app-preview assets for an app — returns assetGenIds you can use to author creatives or audit rejected assets.
Inputs: adamId (required), selector (required), orgId.
apps_eligibilities_findA
Find app-eligibility records by selector (filterable by supplySource, countryOrRegion, deviceClass, state).
Inputs: adamId (required), selector (required), orgId.
apps_getC
Fetch App Store metadata for an app: appName, developerName, primaryGenre, secondaryGenre, iconPictureUrl, availableStorefronts, deviceClasses, etc.
Inputs: adamId (required), orgId.
apps_locale_detailsB
Get localized default product-page details for an app (subtitle, short description, screenshots, app preview) per locale.
Inputs: adamId (required), orgId.
budget_orders_createB
Create a budget order (LOC accounts only). Wraps Apple's {bo, orgIds} envelope.
Inputs: name (required), budget (required), startDate (required), endDate (required), +8 more.
budget_orders_getB
Fetch a single budget order by ID.
Inputs: budgetOrderId (required), orgId.
budget_orders_listB
List all budget orders in the org (paginated).
Inputs: limit, offset, orgId.
budget_orders_updateC
Update a budget order. Most fields are editable post-creation; status is read-only. v5 has no delete endpoint for budget orders.
Inputs: budgetOrderId (required), bo (required), orgIds, orgId.
campaign_negative_keywords_createB
Bulk-create campaign-level negative keywords (apply across all ad groups).
Inputs: campaignId (required), keywords (required), orgId.
campaign_negative_keywords_deleteC
Bulk-delete campaign-level negative keywords by ID.
Inputs: campaignId (required), keywordIds (required), orgId.
campaign_negative_keywords_findB
Find campaign-level negative keywords within a single campaign with a selector.
Inputs: campaignId (required), selector (required), orgId.
campaign_negative_keywords_getB
Fetch a single campaign-level negative keyword by ID.
Inputs: campaignId (required), keywordId (required), orgId.
campaign_negative_keywords_listC
List campaign-level negative keywords (paginated).
Inputs: campaignId (required), limit, offset, orgId.
campaign_negative_keywords_updateC
Bulk-update campaign-level negative keywords.
Inputs: campaignId (required), keywords (required), orgId.
campaigns_createB
Create a new campaign. The minimum useful body specifies adamId, name, countriesOrRegions, adChannelType, supplySources, billingEvent, and a budget.
Inputs: name (required), adamId (required), countriesOrRegions (required), adChannelType (required), +14 more.
campaigns_deleteB
Permanently delete a campaign. Cannot be undone.
Inputs: campaignId (required), orgId.
campaigns_findA
Search campaigns with a selector — supports conditions (EQUALS/IN/CONTAINS/...), orderBy, and pagination.
Inputs: selector (required), orgId.
campaigns_getB
Fetch a single campaign by ID.
Inputs: campaignId (required), orgId.
campaigns_listA
List all campaigns in the org (paginated). For richer filtering use campaigns_find.
Inputs: limit, offset, orgId.
campaigns_updateA
Update a campaign. Pass only the fields you want to change. Use clearGeoTargetingOnCountryOrRegionChange=true if you change countriesOrRegions.
Inputs: campaignId (required), campaign (required), clearGeoTargetingOnCountryOrRegionChange, orgId.
countries_or_regions_listA
List supported countries / regions with their default and supported product-page languages.
Inputs: orgId.
cpp_getB
Fetch a single Custom Product Page by ID.
Inputs: adamId (required), productPageId (required), orgId.
cpp_listC
List Custom Product Pages for an app.
Inputs: adamId (required), orgId.
cpp_locale_detailsB
List the locales available for a Custom Product Page (with localized assets per locale).
Inputs: adamId (required), productPageId (required), orgId.
creative_app_preview_devicesA
List supported app-preview device-size mappings (e.g. IPHONE_61, IPAD_129). Used when authoring creatives or interpreting screenshot/preview metadata.
Inputs: orgId.
creatives_createC
Create a creative (a reference to a default product page, custom product page, or creative set). Ads bind to creatives via creativeId.
Inputs: name (required), adamId (required), type (required), productPageId, +2 more.
creatives_findC
Find creatives across the org with a selector.
Inputs: selector (required), orgId.
creatives_getB
Fetch a single creative by ID.
Inputs: creativeId (required), orgId.
creatives_listB
List all creatives in the org (paginated).
Inputs: limit, offset, orgId.
custom_reports_createB
Create an Impression Share (Share of Voice) report — async. Returns a reportId you poll with custom_reports_get until state=COMPLETED.
Inputs: name (required), startTime (required), endTime (required), granularity, +3 more.
custom_reports_getA
Fetch a single Impression Share report — poll until state=COMPLETED to read rows (rank, impressionShare, lowImpressionShare, highImpressionShare, searchPopularity).
Inputs: reportId (required), orgId.
custom_reports_listB
List all Impression Share reports created in the org.
Inputs: limit, offset, orgId.
geo_lookupA
Resolve geos by raw IDs. Each request item is { id: 'CountryCode|adminArea|locality', entity: 'Country|AdminArea|Locality' }. Useful when a report returns geo IDs you want named.
Inputs: requests (required), orgId.
me_userA
Return information about the calling API user (userId, parentOrgId).
Inputs: no named parameters.
org_aclsA
List all org-level ACLs (orgs your API user can access, with orgName / currency / paymentModel / roleNames). Use this to discover the orgId for ASA_ORG_ID. Does not require X-AP-Context.
Inputs: no named parameters.
product_page_reasons_findB
Find ad-creative rejection reasons (filterable by adamId, productPageId, assetGenId, countryOrRegion, languageCode, supplySource, reasonLevel). Use this to audit why a creative was rejected by Apple's review team.
Inputs: selector (required), orgId.
product_page_reasons_getB
Fetch a single rejection reason by ID.
Inputs: productPageReasonId (required), orgId.
reports_adgroupsC
Ad-group-level report within a single campaign.
Inputs: campaignId (required), startTime (required), endTime (required), granularity, +7 more.
reports_ads_in_campaignB
Ad-level performance (per Custom Product Page / creative variation) rolled up across the campaign.
Inputs: campaignId (required), startTime (required), endTime (required), granularity, +7 more.
reports_campaignsA
Campaign-level performance report. Returns rows with impressions, taps, installs, spend, CPT/CPM/CPI, conversion rate, etc. Pass groupBy to pivot by country, device, age, gender.
Inputs: startTime (required), endTime (required), granularity, timeZone, +6 more.
reports_keywords_in_adgroupC
Keyword report scoped to a single ad group.
Inputs: campaignId (required), adGroupId (required), startTime (required), endTime (required), +8 more.
reports_keywords_in_campaignC
Keyword report rolled up across all ad groups in one campaign.
Inputs: campaignId (required), startTime (required), endTime (required), granularity, +7 more.
reports_search_terms_in_adgroupC
Search-terms report scoped to a single ad group.
Inputs: campaignId (required), adGroupId (required), startTime (required), endTime (required), +8 more.
reports_search_terms_in_campaignB
Search-terms report rolled up across all ad groups in a campaign. Reveals what users actually typed — harvest new keywords or negatives from here.
Inputs: campaignId (required), startTime (required), endTime (required), granularity, +7 more.
search_appsA
Search the App Store for apps to target / advertise. Returns adamId, name, developerName, and country availability. You need adamId to create campaigns.
Inputs: query (required), returnOwnedApps, limit, offset, +1 more.
search_geoB
Search geo entities by name (Country / AdminArea / Locality). Pass countrycode (lowercase, Apple's quirk) to scope an admin-area or locality search to one country.
Inputs: query (required), entity (required), countrycode, limit, +2 more.
targeting_keywords_createB
Bulk-create targeting (positive) keywords on an ad group. Pass up to 1000 per call.
Inputs: campaignId (required), adGroupId (required), keywords (required), orgId.
targeting_keywords_deleteC
Bulk-delete targeting keywords by ID.
Inputs: campaignId (required), adGroupId (required), keywordIds (required), orgId.
targeting_keywords_delete_singleB
Delete a single targeting keyword by ID (uses Apple's REST DELETE variant).
Inputs: campaignId (required), adGroupId (required), keywordId (required), orgId.
targeting_keywords_findA
Find targeting keywords across all ad groups in a campaign with a selector. Apple does not expose a per-ad-group find — filter by adGroupId in the selector if needed.
Inputs: campaignId (required), selector (required), orgId.
targeting_keywords_getC
Fetch a single targeting keyword by ID.
Inputs: campaignId (required), adGroupId (required), keywordId (required), orgId.
targeting_keywords_listB
List targeting keywords on an ad group (paginated).
Inputs: campaignId (required), adGroupId (required), limit, offset, +1 more.
targeting_keywords_updateB
Bulk-update targeting keywords (status, bid, text, matchType). Each entry must include id.
Inputs: campaignId (required), adGroupId (required), keywords (required), orgId.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 74 tools
Each tool targets a distinct resource and action, with clear prefixes like adgroups_, campaigns_, targeting_keywords_, etc., so there is no ambiguity between tools.
All tool names follow a consistent snake_case verb_noun pattern (e.g., adgroups_create, campaigns_list, custom_reports_create), with very few deviations like delete_single, which is still clear.
With 74 tools, the count is high but appropriate for the comprehensive Apple Search Ads API covering many resources and operations. Each tool serves a specific purpose, though the number exceeds typical well-scoped servers.
The tool set covers all major workflows: CRUD for campaigns, ad groups, ads, keywords, negatives, creatives, budget orders; reporting; app and geo search; org management. The escape hatch handles any missing endpoints, ensuring no dead ends.
Maintenance
Related MCP Connectors
Google Ads MCP server — manage campaigns, keywords, and metrics.
Marketo MCP server for AI. 130 tools to operate Marketo from Claude, Cursor, or ChatGPT.
Hosted MCP server for marketing agencies: connect Google Ads, GA4, Search Console, Meta, LinkedIn and more to Claude or ChatGPT. Pull reports and make changes via OAuth login, no setup.
Apple Search Ads MCP: campaign analytics, bid management, and attribution tracking.
Related MCP Servers
- AlicenseBqualityCmaintenanceMCP server for Meta Marketing API v25.0 — 123 tools for Facebook & Instagram ad campaign management134397 npm94MIT
- AlicenseAqualityDmaintenanceApple Search Ads API v5 (read-only). Campaigns, ad groups, keywords, performance reports.91MIT
- AlicenseBqualityDmaintenanceTyped MCP server for OpenAI Ads and ChatGPT Ads via the Advertiser API. Supports account, campaign, ad group, ad, creative, audience, insight, and conversion tools with readonly mode and guarded writes.124MIT
- AlicenseAqualityDmaintenanceMCP server that wraps the Meta Marketing API (Graph API v25.0) as semantic tools for LLM agents.181MIT