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

一个模型上下文协议 (MCP) 服务器,封装了完整的 Apple Search Ads(现为 Apple Ads)广告系列管理 API v5。包含 74 个类型化工具,与 v5 文档中的每个端点一一对应 — 包括广告系列、广告组、广告、创意、自定义产品页、关键词、否定关键词、报告、展示份额报告、预算订单、ACL、地理位置/应用搜索、应用元数据、拒绝原因审计 — 此外还提供了一个用于访问未来任何端点的原始透传接口。

API 生命周期: Apple Ads (Search Ads) v5 是当前的生产环境 API。v5 将于 2027 年 1 月 26 日停止服务,届时将由 2026 年夏季推出的全新“Apple Ads Platform API”取代。本服务器针对 v5.0 → v5.5 版本。

快速安装

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

然后通过一行命令在 Claude Code 中注册:

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

设置

1. 获取 API 凭证

Apple Ads UI 将凭证分散在两个屏幕中。账户设置中的 API 选项卡仅用于管理第三方服务提供商的访问权限;对于您自己的程序化访问,流程首先需要通过 用户管理 (User Management)

a) 邀请 API 用户

app-ads.apple.com账户设置 (Account Settings) → 用户管理 (User Management) → 邀请用户 (Invite User)

  • 电子邮件:您控制的任何地址(可以是您自己的;Apple 要求 API 用户使用独立的 Apple ID)

  • 角色:选择一个具有 API 权限的角色(例如 API 账户经理

  • 发送邀请,然后从受邀邮箱中接受邀请

b) 在本地生成密钥对

在处理邀请的同时,在您的机器上生成一个 ES256 密钥对。请确保它是 PKCS#8 格式 — Apple 的 .p8 示例和旧版的 openssl ecparam 输出均不是 PKCS#8 格式,jose 库无法加载它们。

# 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

asa-private.p8 保存在安全的地方(例如 ~/.apple-search-ads/,并执行 chmod 600)。您只需将公钥部分粘贴到 Apple 即可。

c) 生成 API 客户端

退出登录并以受邀的 API 用户身份(而非管理员账户)重新登录。前往 账户设置 (Account Settings) → API。您将看到一个带有公钥 (Public Key) 文本区域的 客户端凭证 (Client Credentials) 屏幕 — 该屏幕仅对拥有 API 角色的用户可见。

  1. 粘贴 asa-public.pem 的内容(包含 -----BEGIN PUBLIC KEY----- / -----END PUBLIC KEY----- 标记)。

  2. 点击 生成 API 客户端 (Generate API Client)

  3. 复制 Apple 显示给您的三个值:客户端 ID (Client ID)团队 ID (Team ID)密钥 ID (Key ID) — 这些值之后不会再次显示。

2. 安装

npm install
npm run build

3. 配置

.env.example 复制为 .env 并填写,或者通过您的 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(PEM 内容内联,如果通过 JSON 注入则需包含 \n 转义)作为 ASA_PRIVATE_KEY_PATH 的替代方案。

4. 连接到您的 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"
      }
    }
  }
}

身份验证

本服务器使用 ES256 JWT 客户端断言处理 OAuth 2.0 客户端凭证流程:

  1. 使用您的 .p8 私钥签署 JWT(头部:kid=密钥 ID,alg=ES256;载荷:iss=团队 ID,sub=客户端 ID,aud=https://appleid.apple.com)。

  2. 将其 POST 到 https://appleid.apple.com/auth/oauth2/token,并设置 grant_type=client_credentialsscope=searchadsorg

  3. 在每次 API 调用时,使用返回的 1 小时访问令牌,并设置 Authorization: Bearer …X-AP-Context: orgId=…

令牌会缓存在内存中,直到过期前约 30 秒,因此每小时只需签署一次断言并交换一次令牌。当收到 401 时,服务器会强制刷新并重试一次。当收到 429/5xx 时,服务器会退避(遵循 Retry-After)最多 3 次。

工具清单 (74 个工具)

账户与访问 (2)

org_acls, me_user — 在没有组织上下文的情况下调用,以查看您的令牌拥有哪些权限。

发现 (3)

search_apps, search_geo, geo_lookup

应用元数据 (6)

apps_get, apps_locale_details, apps_eligibilities_find, apps_assets_find, creative_app_preview_devices, countries_or_regions_list

自定义产品页 (3)

cpp_list, cpp_get, cpp_locale_details

广告系列 (6)

campaigns_create, campaigns_get, campaigns_list, campaigns_find, campaigns_update, campaigns_delete

广告组 (7)

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

创意 (4)

creatives_create, creatives_list, creatives_get, creatives_find — 创意封装了自定义产品页、默认产品页或创意集引用。广告通过 creativeId 绑定到创意。

广告 (7)

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

定向关键词 (7)

targeting_keywords_create, targeting_keywords_get, targeting_keywords_list, targeting_keywords_find, targeting_keywords_update, targeting_keywords_delete (批量), targeting_keywords_delete_single

否定关键词 — 广告组范围 (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

否定关键词 — 广告系列范围 (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

报告 (7)

工具

端点

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

所有报告工具均接受 startTimeendTime、可选的 granularity (HOURLY/DAILY/WEEKLY/MONTHLY)、可选的 groupBy (adminArea / ageRange / countryCode / countryOrRegion / deviceClass / gender / locality)、selectorreturnRowTotalsreturnGrandTotalsreturnRecordsWithNoMetricstimeZone (UTC | ORTZ)。

展示份额报告 (3) — 异步

custom_reports_create → 返回 reportId。使用 custom_reports_get 轮询直到 state=COMPLETED。使用 custom_reports_list 列出报告。

预算订单 (4) — 仅限 LOC 账户

budget_orders_create, budget_orders_get, budget_orders_list, budget_orders_update。v5 不支持删除预算订单。

拒绝原因审计 (2)

product_page_reasons_find, product_page_reasons_get — 只读检查,用于了解 Apple 审核人员为何拒绝创意。

逃生舱 (1)

apple_search_ads_request — 使用任何方法调用任何路径。身份验证和组织上下文仍会自动为您处理。

选择器 (Selectors)

*_find 工具接受 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 }
}

运算符:EQUALS, NOT_EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, GREATER_THAN, LESS_THAN, IN, NOT_IN, CONTAINS_ALL, CONTAINS_ANY, BETWEENvalues 始终是一个数组。

端到端示例

一个可以完全通过 Claude 驱动的工作流:

  1. org_acls → 选择 orgId

  2. search_apps 查找您的应用 → 获取 adamId

  3. 使用该 adamId、每日预算、美国定向、adChannelType=SEARCHsupplySources=["APPSTORE_SEARCH_RESULTS"]billingEvent=TAPS 调用 campaigns_create

  4. 在广告系列内调用 adgroups_create,设置 defaultBidAmount={amount:"1.00",currency:"USD"}pricingModel=CPC

  5. 使用一批 {text, matchType, bidAmount} 行调用 targeting_keywords_create

  6. cpp_list → 选择一个 productPageId → 使用 type=CUSTOM_PRODUCT_PAGE 调用 creatives_create 以生成 creativeId → 调用 ads_create 将其绑定到广告组。

  7. 等待几天。调用 reports_campaigns 获取顶层数据,然后调用 reports_search_terms_in_campaign 以获取新的关键词/否定关键词。

  8. 调用 custom_reports_create 获取热门搜索的展示份额/声量份额。

已知表面说明 (v5 怪癖)

  • 无旧版创意集 CRUD。 Apple 在 v5 中移除了它;请改为创建 creatives 行并从 ads.creativeId 引用它。

  • 无应用分类端点。 请使用 apps_get 并读取 primaryGenre / secondaryGenre

  • 无邮政编码地理定向。 v5 中的地理实体仅限国家/行政区/地区。

  • 无关键词或广告组范围关键词的组织级查找。 Apple 将定向关键词查找范围限定在广告系列级别 (/campaigns/{id}/adgroups/targetingkeywords/find),并汇总跨广告组的数据;在选择器中通过 adGroupId 进行过滤以缩小范围。

  • 预算订单无 DELETE 操作。 请更新它们,不要删除它们。

  • 受众、预测、转化事件 不在 v5 中 — 这些存在于单独的 Apple API(如 AdServices Attribution 等)中。

本地开发

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

使用 apple_search_ads_request 直接调试任何端点 — 它会返回原始信封数据,以便您查看 Apple 返回的确切响应格式。

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