Skip to main content
Glama
Apple Ads MCP

Apple Ads MCP

by AppVisionOS

apple-search-ads-mcp

CI npm version npm downloads License: MIT Node MCP Glama MCP server

Un servidor del Protocolo de Contexto de Modelos (MCP) que envuelve la API completa de gestión de campañas de Apple Search Ads (ahora Apple Ads) v5. 74 herramientas tipadas, mapeo 1:1 a cada endpoint documentado de la v5: campañas, grupos de anuncios, anuncios, creatividades, páginas de producto personalizadas, palabras clave, palabras clave negativas, informes, informes de cuota de impresiones, órdenes de presupuesto, ACLs, búsqueda geo/app, metadatos de apps, auditorías de motivos de rechazo, además de un passthrough directo para cualquier endpoint futuro.

Ciclo de vida de la API: Apple Ads (Search Ads) v5 es la API de producción actual. La v5 dejará de estar disponible el 26 de enero de 2027 en favor de la nueva "Apple Ads Platform API" que llegará en el verano de 2026. Este servidor apunta a la v5.0 → v5.5.

Instalación rápida

git clone https://github.com/AppVisionOS/apple-search-ads-mcp.git
cd apple-search-ads-mcp
npm install
npm run build

Luego regístralo con Claude Code en una línea:

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.js

Related MCP server: aapl-ads-mcp

Configuración

1. Obtener credenciales de API

La interfaz de usuario de Apple Ads divide las credenciales en dos pantallas. La pestaña API dentro de la Configuración de la cuenta solo gestiona el acceso para proveedores de servicios externos; para tu propio acceso programático, el flujo pasa primero por Gestión de usuarios.

a) Invitar a un usuario de API

En app-ads.apple.com → Configuración de la cuenta → Gestión de usuarios → Invitar usuario:

  • Correo electrónico: cualquier dirección que controles (puede ser la tuya; Apple requiere un Apple ID separado para el usuario de la API)

  • Rol: elige uno con permisos de API (p. ej., API Account Manager)

  • Envía la invitación y luego acéptala desde la bandeja de entrada invitada

b) Generar el par de claves localmente

Mientras se procesa la invitación, genera un par de claves ES256 en tu máquina. Asegúrate de que sea PKCS#8; los ejemplos .p8 de Apple y la salida antigua de openssl ecparam no son PKCS#8 y jose no puede cargarlos.

# 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.p8

Guarda asa-private.p8 en un lugar seguro (p. ej., ~/.apple-search-ads/, chmod 600). Solo pegarás la mitad pública en Apple.

c) Generar el cliente de API

Cierra sesión y vuelve a iniciarla como el usuario de API invitado (no la cuenta de administrador). Ve a Configuración de la cuenta → API. Verás una pantalla de Credenciales de cliente con un área de texto para la Clave pública; esto solo aparece para los usuarios que tienen el rol de API.

  1. Pega el contenido de asa-public.pem (con los marcadores -----BEGIN PUBLIC KEY----- / -----END PUBLIC KEY-----).

  2. Haz clic en Generar cliente de API.

  3. Copia los tres valores que te muestra Apple: ID de cliente, ID de equipo, ID de clave; estos no vuelven a aparecer más tarde.

2. Instalación

npm install
npm run build

3. Configuración

Copia .env.example a .env y rellénalo, o pasa las variables de entorno a través de tu cliente MCP.

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 call

ASA_PRIVATE_KEY (contenido PEM en línea, con escapes \n si se inyecta vía JSON) es compatible como alternativa a ASA_PRIVATE_KEY_PATH.

4. Conectar a tu cliente MCP

{
  "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"
      }
    }
  }
}

Autenticación

El servidor maneja el flujo de credenciales de cliente OAuth 2.0 con una aserción de cliente JWT ES256:

  1. Firma un JWT con tu clave privada .p8 (encabezado: kid=ID de clave, alg=ES256; carga útil: iss=ID de equipo, sub=ID de cliente, aud=https://appleid.apple.com).

  2. Haz un POST a https://appleid.apple.com/auth/oauth2/token con grant_type=client_credentials y scope=searchadsorg.

  3. Usa el token de acceso de 1 hora devuelto con Authorization: Bearer … y X-AP-Context: orgId=… en cada llamada a la API.

El token se almacena en caché en memoria hasta unos 30 segundos antes de su vencimiento, por lo que firmas una aserción e intercambias un token por hora. En caso de 401, el servidor fuerza la actualización y reintenta una vez. En caso de 429/5xx, espera (respetando Retry-After) hasta 3 veces.

Inventario de herramientas (74 herramientas)

Cuenta y acceso (2)

org_acls, me_user: llama sin un contexto de organización para descubrir qué puede hacer tu token.

Descubrimiento (3)

search_apps, search_geo, geo_lookup

Metadatos de apps (6)

apps_get, apps_locale_details, apps_eligibilities_find, apps_assets_find, creative_app_preview_devices, countries_or_regions_list

Páginas de producto personalizadas (3)

cpp_list, cpp_get, cpp_locale_details

Campañas (6)

campaigns_create, campaigns_get, campaigns_list, campaigns_find, campaigns_update, campaigns_delete

Grupos de anuncios (7)

adgroups_create, adgroups_get, adgroups_list, adgroups_find_in_campaign, adgroups_find_org_wide, adgroups_update, adgroups_delete

Creatividades (4)

creatives_create, creatives_list, creatives_get, creatives_find: las creatividades envuelven una referencia a una Página de producto personalizada, Página de producto predeterminada o Conjunto de creatividades. Los anuncios se vinculan a las creatividades mediante creativeId.

Anuncios (7)

ads_create, ads_get, ads_list, ads_find_in_campaign, ads_find_org_wide, ads_update, ads_delete

Palabras clave de segmentación (7)

targeting_keywords_create, targeting_keywords_get, targeting_keywords_list, targeting_keywords_find, targeting_keywords_update, targeting_keywords_delete (en lote), targeting_keywords_delete_single

Palabras clave negativas: alcance de grupo de anuncios (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

Palabras clave negativas: alcance de campaña (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

Informes (7)

Herramienta

Endpoint

reports_campaigns

POST /reports/campaigns

reports_adgroups

POST /reports/campaigns/{id}/adgroups

reports_keywords_in_campaign

POST /reports/campaigns/{id}/keywords

reports_keywords_in_adgroup

POST /reports/campaigns/{id}/adgroups/{id}/keywords

reports_search_terms_in_campaign

POST /reports/campaigns/{id}/searchterms

reports_search_terms_in_adgroup

POST /reports/campaigns/{id}/adgroups/{id}/searchterms

reports_ads_in_campaign

POST /reports/campaigns/{id}/ads

Todos aceptan startTime, endTime, granularity opcional (HOURLY/DAILY/WEEKLY/MONTHLY), groupBy opcional (adminArea / ageRange / countryCode / countryOrRegion / deviceClass / gender / locality), selector, returnRowTotals, returnGrandTotals, returnRecordsWithNoMetrics, timeZone (UTC | ORTZ).

Informes de cuota de impresiones (3): asíncronos

custom_reports_create → devuelve reportId. Consulta con custom_reports_get hasta que state=COMPLETED. Lista con custom_reports_list.

Órdenes de presupuesto (4): solo cuentas LOC

budget_orders_create, budget_orders_get, budget_orders_list, budget_orders_update. La v5 no tiene eliminación para órdenes de presupuesto.

Auditoría de motivos de rechazo (2)

product_page_reasons_find, product_page_reasons_get: inspección de solo lectura de por qué los revisores de Apple rechazaron las creatividades.

Puerta de escape (1)

apple_search_ads_request: llama a cualquier ruta con cualquier método. La autenticación y el contexto de la organización se siguen manejando por ti.

Selectores

Las herramientas *_find aceptan la gramática de selectores de Apple:

{
  "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 }
}

Operadores: EQUALS, NOT_EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, GREATER_THAN, LESS_THAN, IN, NOT_IN, CONTAINS_ALL, CONTAINS_ANY, BETWEEN. values es siempre una matriz.

Ejemplo de extremo a extremo

Un flujo de trabajo que puedes realizar completamente a través de Claude:

  1. org_acls → elige el orgId.

  2. search_apps para tu app → obtén el adamId.

  3. campaigns_create con ese adamId, presupuesto diario, segmentación en EE. UU., adChannelType=SEARCH, supplySources=["APPSTORE_SEARCH_RESULTS"], billingEvent=TAPS.

  4. adgroups_create dentro de la campaña con defaultBidAmount={amount:"1.00",currency:"USD"} y pricingModel=CPC.

  5. targeting_keywords_create con un lote de filas {text, matchType, bidAmount}.

  6. cpp_list → elige un productPageId → creatives_create con type=CUSTOM_PRODUCT_PAGE para crear un creativeId → ads_create para vincularlo al grupo de anuncios.

  7. Espera unos días. reports_campaigns para resultados generales, luego reports_search_terms_in_campaign para obtener nuevas palabras clave / negativas.

  8. custom_reports_create para cuota de impresiones / cuota de voz en tus búsquedas principales.

Notas sobre la superficie conocida (peculiaridades de la v5)

  • No hay CRUD de conjuntos de creatividades heredados. Apple lo eliminó en la v5; crea una fila en creatives en su lugar y haz referencia a ella desde ads.creativeId.

  • No hay endpoint de categorías de apps. Usa apps_get y lee primaryGenre / secondaryGenre.

  • No hay segmentación geográfica por código postal. Las entidades geográficas en la v5 son solo Country / AdminArea / Locality.

  • No hay búsqueda en toda la organización para palabras clave o búsqueda de palabras clave con alcance de grupo de anuncios. Apple limita la búsqueda de palabras clave de segmentación al nivel de campaña (/campaigns/{id}/adgroups/targetingkeywords/find) y las agrupa en todos los grupos de anuncios; filtra por adGroupId en el selector para restringir.

  • No hay DELETE en órdenes de presupuesto. Actualízalas, no las elimines.

  • Las audiencias, la previsión y los eventos de conversión NO están en la v5; esos residen en APIs de Apple separadas (AdServices Attribution, etc.).

Desarrollo local

npm run dev        # tsc --watch
npm run typecheck  # one-shot type check
npm run build      # compile to dist/

Usa apple_search_ads_request para depurar cualquier endpoint directamente; devuelve el sobre sin procesar para que puedas ver la forma exacta de la respuesta que devolvió Apple.

Available Tools

74 tools
adgroup_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

    B3.3/5.0

    Scored across 74 tools

    Disambiguation5/5

    Each tool targets a distinct resource and action, with clear prefixes like adgroups_, campaigns_, targeting_keywords_, etc., so there is no ambiguity between tools.

    Naming Consistency5/5

    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.

    Tool Count4/5

    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.

    Completeness5/5

    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

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Apple Search Ads API v5 (read-only). Campaigns, ad groups, keywords, performance reports.
      9
      1
      MIT
    • A
      license
      B
      quality
      D
      maintenance
      Typed 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.
      12
      4
      MIT