Skip to main content
Glama
AppVisionOS

Apple Ads MCP

apple-search-ads-mcp

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

Ein Model Context Protocol (MCP) Server, der die vollständige Apple Search Ads (jetzt Apple Ads) Campaign Management API v5 kapselt. 74 typisierte Tools, 1:1-Abbildung auf jeden dokumentierten v5-Endpunkt — Kampagnen, Anzeigengruppen, Anzeigen, Creatives, benutzerdefinierte Produktseiten, Keywords, negative Keywords, Berichte, Impression-Share-Berichte, Budgetaufträge, ACLs, Geo-/App-Suche, App-Metadaten, Audits von Ablehnungsgründen — plus ein Raw-Passthrough für zukünftige Endpunkte.

API-Lebenszyklus: Apple Ads (Search Ads) v5 ist die aktuelle Produktions-API. v5 wird am 26. Januar 2027 zugunsten der neuen "Apple Ads Platform API", die im Sommer 2026 erscheint, eingestellt. Dieser Server zielt auf v5.0 → v5.5 ab.

Schnellinstallation

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

Dann mit einer Zeile bei Claude Code registrieren:

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

Einrichtung

1. API-Zugangsdaten abrufen

Die Apple Ads-Benutzeroberfläche teilt die Zugangsdaten auf zwei Bildschirme auf. Der Tab API in den Kontoeinstellungen verwaltet nur den Zugriff für Drittanbieter; für Ihren eigenen programmatischen Zugriff führt der Weg zuerst über die Benutzerverwaltung.

a) API-Benutzer einladen

Unter app-ads.apple.comKontoeinstellungen → Benutzerverwaltung → Benutzer einladen:

  • E-Mail: Jede Adresse, die Sie kontrollieren (kann Ihre eigene sein; Apple erfordert eine separate Apple ID für den API-Benutzer)

  • Rolle: Wählen Sie eine mit API-Berechtigungen (z. B. API Account Manager)

  • Senden Sie die Einladung und akzeptieren Sie diese dann im Posteingang des eingeladenen Benutzers

b) Schlüsselpaar lokal generieren

Während die Einladung bearbeitet wird, generieren Sie ein ES256-Schlüsselpaar auf Ihrem Rechner. Stellen Sie sicher, dass es PKCS#8 ist — Apples .p8-Beispiele und die ältere openssl ecparam-Ausgabe sind kein PKCS#8 und jose kann diese nicht laden.

# 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

Bewahren Sie asa-private.p8 an einem sicheren Ort auf (z. B. ~/.apple-search-ads/, chmod 600). Sie fügen nur die öffentliche Hälfte bei Apple ein.

c) API-Client generieren

Melden Sie sich ab und als eingeladener API-Benutzer (nicht als Admin-Konto) wieder an. Gehen Sie zu Kontoeinstellungen → API. Sie sehen einen Bildschirm Client-Zugangsdaten mit einem Textfeld für den öffentlichen Schlüssel — dies erscheint nur für Benutzer, die die API-Rolle innehaben.

  1. Fügen Sie den Inhalt von asa-public.pem ein (mit den Markierungen -----BEGIN PUBLIC KEY----- / -----END PUBLIC KEY-----).

  2. Klicken Sie auf API-Client generieren.

  3. Kopieren Sie die drei Werte, die Apple Ihnen anzeigt: Client ID, Team ID, Key ID — diese erscheinen später nicht mehr.

2. Installation

npm install
npm run build

3. Konfiguration

Kopieren Sie .env.example nach .env und füllen Sie es aus, oder übergeben Sie Umgebungsvariablen über Ihren 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 call

ASA_PRIVATE_KEY (PEM-Inhalt inline, mit \n-Escapes, falls über JSON injiziert) wird als Alternative zu ASA_PRIVATE_KEY_PATH unterstützt.

4. In Ihren MCP-Client einbinden

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

Authentifizierung

Der Server handhabt den OAuth 2.0 Client-Credentials-Flow mit einer ES256 JWT-Client-Assertion:

  1. Signieren Sie ein JWT mit Ihrem privaten .p8-Schlüssel (Header: kid=Key ID, alg=ES256; Payload: iss=Team ID, sub=Client ID, aud=https://appleid.apple.com).

  2. Senden Sie es per POST an https://appleid.apple.com/auth/oauth2/token mit grant_type=client_credentials und scope=searchadsorg.

  3. Verwenden Sie das zurückgegebene 1-Stunden-Zugriffstoken mit Authorization: Bearer … und X-AP-Context: orgId=… bei jedem API-Aufruf.

Das Token wird im Speicher bis ca. 30 s vor Ablauf zwischengespeichert, sodass Sie eine Assertion signieren und ein Token pro Stunde austauschen. Bei 401 erzwingt der Server eine Aktualisierung und versucht es einmal erneut. Bei 429/5xx wird das Tempo gedrosselt (unter Beachtung von Retry-After), bis zu 3 Mal.

Tool-Inventar (74 Tools)

Konto & Zugriff (2)

org_acls, me_user — ohne Organisationskontext aufrufen, um herauszufinden, was Ihr Token tun kann.

Entdeckung (3)

search_apps, search_geo, geo_lookup

App-Metadaten (6)

apps_get, apps_locale_details, apps_eligibilities_find, apps_assets_find, creative_app_preview_devices, countries_or_regions_list

Benutzerdefinierte Produktseiten (3)

cpp_list, cpp_get, cpp_locale_details

Kampagnen (6)

campaigns_create, campaigns_get, campaigns_list, campaigns_find, campaigns_update, campaigns_delete

Anzeigengruppen (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 kapseln eine Referenz auf eine benutzerdefinierte Produktseite, eine Standard-Produktseite oder ein Creative-Set. Anzeigen werden über creativeId an Creatives gebunden.

Anzeigen (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 — Anzeigengruppen-Bereich (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 — Kampagnen-Bereich (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

Berichte (7)

Tool

Endpunkt

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

Alle akzeptieren 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-Berichte (3) — asynchron

custom_reports_create → gibt reportId zurück. Mit custom_reports_get abfragen, bis state=COMPLETED. Mit custom_reports_list auflisten.

Budgetaufträge (4) — nur LOC-Konten

budget_orders_create, budget_orders_get, budget_orders_list, budget_orders_update. v5 hat kein Löschen für Budgetaufträge.

Audit von Ablehnungsgründen (2)

product_page_reasons_find, product_page_reasons_get — schreibgeschützte Überprüfung, warum Apples Prüfer Creatives abgelehnt haben.

Notausgang (1)

apple_search_ads_request — jeden Pfad mit jeder Methode aufrufen. Authentifizierung und Organisationskontext werden weiterhin für Sie gehandhabt.

Selektoren

*_find-Tools akzeptieren Apples Selektor-Grammatik:

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

Operatoren: EQUALS, NOT_EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, GREATER_THAN, LESS_THAN, IN, NOT_IN, CONTAINS_ALL, CONTAINS_ANY, BETWEEN. values ist immer ein Array.

End-to-End-Beispiel

Ein Workflow, den Sie vollständig über Claude steuern können:

  1. org_acls → die orgId auswählen.

  2. search_apps für Ihre App → die adamId abrufen.

  3. campaigns_create mit dieser adamId, Tagesbudget, US-Targeting, adChannelType=SEARCH, supplySources=["APPSTORE_SEARCH_RESULTS"], billingEvent=TAPS.

  4. adgroups_create innerhalb der Kampagne mit defaultBidAmount={amount:"1.00",currency:"USD"} und pricingModel=CPC.

  5. targeting_keywords_create mit einer Reihe von {text, matchType, bidAmount}-Zeilen.

  6. cpp_list → eine productPageId auswählen → creatives_create mit type=CUSTOM_PRODUCT_PAGE, um eine creativeId zu erstellen → ads_create, um sie an die Anzeigengruppe zu binden.

  7. Warten Sie ein paar Tage. reports_campaigns für die Top-Level-Daten, dann reports_search_terms_in_campaign, um neue Keywords / negative Keywords zu sammeln.

  8. custom_reports_create für Impression-Share / Share-of-Voice bei Ihren Top-Suchanfragen.

Bekannte Hinweise (v5-Besonderheiten)

  • Kein Legacy-Creative-Set CRUD. Apple hat es in v5 entfernt; erstellen Sie stattdessen eine creatives-Zeile und referenzieren Sie diese von ads.creativeId.

  • Kein App-Kategorien-Endpunkt. Verwenden Sie apps_get und lesen Sie primaryGenre / secondaryGenre.

  • Kein Geo-Targeting nach Postleitzahlen. Geo-Entitäten in v5 sind nur Country / AdminArea / Locality.

  • Keine organisationsweite Suche nach Keywords oder Suche nach Keywords auf Anzeigengruppenebene. Apple begrenzt die Suche nach Targeting-Keywords auf Kampagnenebene (/campaigns/{id}/adgroups/targetingkeywords/find) und fasst sie über Anzeigengruppen hinweg zusammen; filtern Sie nach adGroupId im Selektor, um die Suche einzugrenzen.

  • Kein DELETE bei Budgetaufträgen. Aktualisieren Sie diese, löschen Sie sie nicht.

  • Zielgruppen, Prognosen, Conversion-Events sind NICHT in v5 enthalten — diese befinden sich in separaten Apple-APIs (AdServices Attribution etc.).

Lokale Entwicklung

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

Verwenden Sie apple_search_ads_request, um jeden Endpunkt direkt zu debuggen — es gibt den Raw-Envelope zurück, sodass Sie die genaue Antwortform sehen können, die Apple zurückgegeben hat.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AppVisionOS/apple-search-ads-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server