mcpField
A
app-store-connect-mcp

app-store-connect-mcp

本地服务
github.com/abd3lraouf-studios开发工具08 周前更新

关于 app-store-connect-mcp

app-store-connect-mcp 面向管理 Apple 应用的团队,提供 App Store Connect 和 App Store Server API 的 MCP 接口。它结合端点搜索、分级读写、敏感写入确认及 StoreKit 2 签名验证。

主要功能

  1. 01搜索并查看 API 操作说明
  2. 02分离读取与写入工具
  3. 03敏感写入要求确认
  4. 04组合常见的多步 API 流程
  5. 05验证 StoreKit 2 签名
  6. 06提供资源和斜杠命令工作流

适用场景

  1. 01检查应用发布准备情况
  2. 02查看或调整应用定价
  3. 03上传 App Store 截图
  4. 04获取分析与订阅数据

MCP 相关

此服务通过 MCP 工具、资源和工作流开放 Apple API 操作。MCP 客户端可搜索端点并执行读取或写入;高风险写入可要求操作人员确认。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"abd3lraouf-studios-app-store-connect": {
"command": "npx",
"args": [
"-y",
"@abd3lraouf/app-store-connect-mcp"
],
"env": {
"ASC_KEY": "<ASC_KEY>",
"ASC_ISSUER_ID": "<ASC_ISSUER_ID>",
"ASC_KEY_ID": "<ASC_KEY_ID>",
"ASC_BUNDLE_ID": "<ASC_BUNDLE_ID>",
"ASC_APP_APPLE_ID": "<ASC_APP_APPLE_ID>"
}
}
}
}
启动命令npx -y @abd3lraouf/app-store-connect-mcp
需要配置的环境变量
ASC_KEY密钥keychain:<service> (recommended), or a path to your AuthKey .p8
ASC_ISSUER_IDIssuer ID. Not needed if stored in the keychain envelope.
ASC_KEY_ID密钥API key ID. Not needed if stored in the keychain envelope.
ASC_BUNDLE_IDRequired for App Store Server API calls and to verify Apple's signatures.
ASC_APP_APPLE_IDNumeric Apple ID. Apple requires it to verify Production signatures.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@abd3lraouf/app-store-connect-mcp1.3.0

工具

13

收录的工具列表 · 更新于 2 周前

此工具无需参数。

详细介绍

App Store Connect MCP 服务

让 Claude 使用你的 App Store Connect 账户,而不把定价权限交给它。 一个覆盖 App Store Connect API 和 App Store Server API (StoreKit 2)的 MCP 服务——通过 13 个工具提供 1,293 项操作,适用于 Claude Code、Claude Desktop、 Cursor 以及任何支持模型上下文协议的产品。

npm CI Tests Coverage Licence

Operations Tools MCP Node Platform Install size

1,293 operations · 13 tools · key never on disk · Apple signatures verified
flowchart LR
    A["Claude<br/>Cursor · any MCP client"] -->|"search · call · write"| B["app-store-connect-mcp<br/>13 tools"]
    B --> C{"risk tier"}
    C -->|"READ · 811 ops"| D["Apple<br/>App Store Connect API"]
    C -->|"WRITE · 482 ops"| E["ask a human first"]
    E -->|approved| D
    E -->|declined| F["nothing is sent"]
    B --> G["App Store Server API<br/>StoreKit 2 · signatures verified"]

    style E fill:#ffe8b3,stroke:#c98a00,color:#000
    style F fill:#ffd6d6,stroke:#c00,color:#000
    style D fill:#d6f5d6,stroke:#2a2,color:#000
    style G fill:#d6f5d6,stroke:#2a2,color:#000

别安装这个

真的。消磨下午时光有更便宜的方式,以下几类人现在就该关掉这个标签页:

你想要一个只管办事的 Agent。 它会停下来,在更改价格、删除内容或更改账户访问权限前征求同意——而且问的是你,不是它自己。如果你觉得这很碍事,确实如此。这就是它的设计。

你想让每个端点都成为独立工具。 有些服务会注册 890 个工具。你的服务还没回答一个问题,光工具定义就会占用六位数的上下文。这个服务只注册 11 个工具,其余操作通过搜索查找。

tool definitions loaded into context, before you ask anything

  one tool per endpoint   ███████████████████████████████████   >100k tokens
  this server             ▌                                       ~1k tokens

你用的是 Windows 或 Linux,却想用 Keychain。 Keychain 存储仅支持 macOS。其他系统可以使用文件路径,但这个工具最适合 macOS 环境。

你想让它帮你撰写 App Store 文案。 它会获取你的评论和本地化内容,但不会凭空编写营销文案并发布,也没有任何选项可以让它这么做。

你打算将它用于商业产品。 请先阅读许可协议。内部使用免费,但转售不行。

还在继续看?那接下来的内容大概适合你。


它拒绝做的事

这里大部分工程工作都用在克制上,因此从这里开始最坦诚。

它不会运行生成的代码。 覆盖庞大 API 的优雅方式,是让模型编写 JavaScript,再在沙箱中 eval。Node 的 vm 不是沙箱——它自己的文档也这么说——而任何传入的宿主对象都会通过原型链泄露整个运行环境:

spec.constructor.constructor('return process.env.HOME')()   // → /Users/you

这是对一个真实上线的 MCP 服务沙箱的复现,它会返回你的主目录。15 秒超时也无济于事:它只限制同步代码,因此 async 循环会永远运行。此服务分发的是参数,而不是代码。覆盖范围相同,令牌成本相同,没有任何东西可供逃逸。

它不会让写入操作伪装成读取操作。 读取和写入是独立的工具。asc_write 携带 _meta["anthropic/requiresUserInteraction"],Claude Code 即使在 bypassPermissions 模式下也会遵守。模型无法花言巧语绕过它;只有操作人员可以通过使用 --no-confirm 启动服务来做到这一点——这会同时移除标志、提示和令牌,适用于无人值守的运行。

它不会替你决定定价意图。 preserve_current_price 是必填参数,没有默认值。Apple 将其默认设为 false——这意味着现有订阅者会被转移到新价格。将其设为必填,可以让这个决定明确呈现出来,供人查看。

它不会为了回答一个问题而创建持续义务。 获取分析数据需要报告请求,而 accessType: ONGOING 是你账户上的持续义务,不是查询。该工具会读取报告;不会悄悄创建报告。

它不会假装已清理你的评价。 客户评价由陌生人撰写,并会原样进入模型的上下文。包含评价内容的结果会首先附上说明,指出这些内容是需要报告的数据,而不是要遵循的指令。它有意不筛除注入短语——攻击者会不断迭代这种对抗游戏,而通过这类筛选会让人误以为它能提供实际上无法保证的安全性。

它不会在未检查的情况下告诉你签名没问题。 请见下文。


安装

Claude Code,一行命令:

claude mcp add --scope user app-store-connect \
  --env ASC_KEY=keychain:my-asc-key \
  --env ASC_BUNDLE_ID=com.example.app \
  --env ASC_APP_APPLE_ID=1234567890 \
  -- npx -y @abd3lraouf/app-store-connect-mcp

无需克隆或构建。或者,如果你想先阅读源码,也可以从源码安装:

git clone https://github.com/abd3lraouf-studios/app-store-connect-mcp
cd app-store-connect-mcp && npm install && npm run build

或者,适用于 Claude Desktop、Cursor 等:

{
  "mcpServers": {
    "app-store-connect": {
      "command": "npx",
      "args": ["-y", "@abd3lraouf/app-store-connect-mcp"],
      "env": {
        "ASC_KEY": "keychain:my-asc-key",
        "ASC_BUNDLE_ID": "com.example.app",
        "ASC_APP_APPLE_ID": "1234567890"
      }
    }
  }
}

然后询问它 “检查 App Store Connect 连接”——这会运行 asc_status,通过一个轻量级请求验证你的凭据,并在有任何缺失时准确告诉你缺少什么。

你的密钥应存放在 Keychain 中

Apple 只允许你下载 .p8 一次。磁盘上的明文副本就是一份可能泄露的副本。

ASC_KEY=keychain:my-asc-key          # recommended
ASC_KEY=/path/to/AuthKey.p8          # works, but plaintext
ASC_PRIVATE_KEY='-----BEGIN…'        # discouraged: ps -E exposes it

将其存储为 base64 JSON,让标识符与密钥材料一同保存——这样 ASC_KEY_ID 就不会与它所标识的密钥不同步;这种不匹配只会以含糊的 401 错误显现:

security add-generic-password -s my-asc-key -a api -w "$(
  jq -nc --arg i "$ISSUER" --arg k "$KEYID" --arg p "$(cat AuthKey.p8)" \
    '{issuerID:$i,keyID:$k,privateKeyPEM:$p}' | base64
)"

十三种工具

五种核心工具,涵盖所有操作:

工具
asc_status凭据、连通性、剩余速率限制额度。出现任何故障时,先运行此工具——它能区分是密钥错误还是请求错误。
asc_search_endpoints按关键词、方法、标签或风险等级搜索两个 API 中的 1,293 个操作。
asc_describe_endpoint参数、包含真实字段名称的请求体架构、风险等级。
asc_call**读取。**路径和查询参数、分页,支持两个 API。
asc_write**所有会更改数据的操作。**需确认,支持 dry_run。

八种复合工具,用于原始 API 无法通过单次调用完成的链式操作。仅仅省去一次请求的工具不会纳入——它们需要永远跟上 Apple 的变化,而且并未提供 asc_call 不具备的功能:

工具合并的操作
asc_pricing_get将约 175 次查询合并为少数几次,适用于订阅和一次性购买。币种属于销售地区,而非价格行,所以手动读取价格会得到含糊的数字。
asc_pricing_set相同的操作链,再加上写入,并明确要求做出订阅者决策。
asc_preflight_version六种资源 → GO / NO-GO,每个缺项都会标明可修复它的操作。
asc_listing_screenshots每个地区一个请求 → 四次,通过 included 实现。
asc_upload_screenshotApple 的预留 → 按偏移量 PUT → 使用 MD5 提交的流程,跨越两个主机。
asc_upload_iap_screenshot为应用内购买的审核截图执行相同流程——这是导致 IAP 一直处于 MISSING_METADATA 状态的那个字段。
asc_availability_set每个销售地区执行一次 PATCH(最多 175 次;Apple 没有批量端点),然后重新读取每个地区,并报告哪些操作未生效。
asc_analytics_report五个步骤 → 签名 URL → gunzip → 数据行,并拼接所有分段。
为什么 asc_upload_screenshot 无法通过一次 API 调用完成

Apple 的资源流程跨越两个主机,最后还要校验校验和;如果校验和有误,流程会静默失败——上传会一直停在 AWAITING_UPLOAD,看起来就像什么也没发生。uploadOperations 在 Apple 的 OpenAPI 文档中仅作为 fields[] 枚举中的一个值出现,因此 Agent 读取规范时,虽然能看到这个字段,但仍无法知道必须对它执行操作。

sequenceDiagram
    participant M as Claude
    participant S as this server
    participant A as App Store Connect
    participant U as Apple asset host

    M->>S: asc_upload_screenshot(set, file)
    S->>A: POST /v1/appScreenshots (fileName, fileSize)
    A-->>S: id + uploadOperations[]
    loop each byte range
        S->>U: PUT bytes at offset, Apple's headers
        Note over S,U: pre-signed URL — no bearer token sent
    end
    S->>A: PATCH uploaded=true + MD5 checksum
    A-->>S: assetDeliveryState
    S-->>M: state, and how to clean up if it failed

此外,还有四种资源(@asc:cookbook、@asc:enums、@asc:risk、@asc:sources)和通过斜杠命令调用的四个工作流: /mcp__asc__release-readiness、pricing-audit、review-triage、 testflight-status。


写入安全

HTTP 方法并不能很好地代表操作后果。PATCH /v1/subscriptionPrices 和 PATCH /v1/appInfos/{id} 都是写入操作;只有其中一个会改变客户的 收费金额,而且重复执行都无法撤销。因此,每项操作都有一个等级(数量 统计自 App Store Connect;StoreKit 2 另增加 14 个读取操作和 16 个写入操作):

等级数量
READ797不会产生更改。
WRITE238会更改数据。
REVENUE61定价、订阅、权益。
DESTRUCTIVE132删除操作。
RELEASE12构建、提交、发布内容。
ACCESS12谁可以访问账户。
INFRASTRUCTURE11证书、标识符、回调 URL。
flowchart TD
    A["asc_write called"] --> B{"--read-only?"}
    B -->|yes| Z["blocked"]
    B -->|no| N{"--no-confirm?"}
    N -->|yes| S["send it"]
    N -->|no| C{"risk tier"}
    C -->|"WRITE"| S["send it"]
    C -->|"REVENUE · DESTRUCTIVE<br/>INFRASTRUCTURE · ACCESS · RELEASE"| D{"client supports<br/>elicitation?"}
    D -->|yes| E["ask the person<br/>method · path · body · tier"]
    D -->|no| F["issue a token<br/>hash-bound to this exact request"]
    E -->|accepted| S
    E -->|declined| Z
    F --> G["caller repeats the call<br/>with the token"]
    G --> S

    style Z fill:#ffd6d6,stroke:#c00,color:#000
    style E fill:#ffe8b3,stroke:#c98a00,color:#000
    style F fill:#ffe8b3,stroke:#c98a00,color:#000
    style S fill:#d6f5d6,stroke:#2a2,color:#000

等级最低的五类操作会在运行前询问确认。如果你的客户端支持征询, 它会直接向你询问,并显示方法、路径、请求体和等级。否则,它会发放一个 确认令牌,该令牌通过哈希绑定到确切的操作、路径、查询参数和请求体—— 因此,为低风险调用获取的令牌不能用于高风险调用。声称支持征询却未能 完成征询的客户端会回退处理,而不会直接放行。

--read-only    block every write       --confirm     confirm every write
--no-confirm   never confirm           (default)     confirm the five tiers above
dry_run: true  report the exact request without sending it (a parameter of asc_write)

--no-confirm 是无人值守模式,而且是完全无人值守:不会弹出征询提示, 不会要求确认令牌,写入工具也不再声明 requiresUserInteraction,因此 Claude Code 也不会因此暂停。否则,无人值守运行 就会拿到无法回应的确认请求。


签名验证

解码 JWS 能告诉你字节内容是什么。验证则能告诉你这些内容确实由 Apple 签署。在这里,这一区别比大多数场景都重要,因为这些载荷是判断 “此人是否为付费订阅者?”的证据——而解码后未经验证的交易,恰恰就是伪造 交易的样子。

每个签名字段都会根据 Apple Root CA - G3 进行检查;该证书随附在 certs/ 中,因此网络故障不会导致验证被关闭。证书链验证、过期检查、吊销检查 以及 Bundle 和环境检查都交由 Apple 自己的库处理,因为这些环节正是看似合理的 实现会接受恶意输入的地方。

验证结果按字段分别给出,而不是按响应整体给出——在两百条历史记录中 出现一个错误签名,才是需要关注的情况:

"signedTransactionInfo_decoded":      { "productId": "premium.monthly" },
"signedTransactionInfo_verification": { "verified": true }

无法运行验证时,载荷仍会解码,且每个字段都会说明这一情况。 保持沉默才是危险的结果。


对比

方案保留的优势不足之处
手动封装的工具每个端点对应一个工具参数有类型,易于发现70–900 个工具定义、超过 100k 个 token;Apple 一发布新版本就会过时
Code Mode模型编写 JS,服务端通过 eval 执行两个工具、约 1k 个 token、全面覆盖在持有签名密钥的进程中运行生成的代码
元工具search → 使用参数进行 call同样节省上下文,不执行代码—

该致谢时就致谢:这里有几个想法改编自阅读 erayendes/app-store-connect-mcp 和 TrialAndErrorAI/appstore-connect-mcp 时获得的启发。没有复制代码。Heimdall 尤其是这个领域中开发最完善的服务; 如果你需要 890 个按配置文件整理的类型化工具,请改用它——它很好, 只是采用了不同的权衡。


验证依据

声明很容易。以下内容都可以核查:

378 tests · 90% line coverage · offline, no credentials, runs on every PR
  • 签名验证的两个方向。 一个拒绝所有内容的验证器看起来和正确的验证器一样可靠,因此,生成一条包含验证器要求的两个 Apple OID 的证书链,可以证明它会走接受路径;而伪造、篡改、错误 Bundle 和错误环境的负载都会被拒绝。
  • 协议版本是实测得出的,而非想当然。 Claude Code 2.1.235 协商使用 MCP 2025-11-25,并声明了 elicitation——我们让它连接到探测服务并记录了结果。这就是此处继续使用 SDK v1 的原因:v2 软件包实现的是 2026-07-28,该版本用 MRTR 取代了 elicitation,而正是 elicitation 让 asc_write 能够询问用户。
  • **使用 MSW,而非 nock,**进行 HTTP 模拟——nock 会修补 node:http,而 Node 的全局 fetch 使用 undici,完全绕过它。因此它实际上什么也拦截不到,而且不会发出任何提示。
  • 有一项测试会启动真实二进制文件,并断言每一行标准输出都能解析为 JSON,因为只要多出一条 console.log,就会破坏 JSON-RPC 通道,而任何进程内测试框架都无法发现这一问题。
npm test              # 378 tests, offline
npm run verify        # 14 read-only checks against the live APIs
npm run fetch:specs   # re-download both API descriptions from Apple

紧跟 Apple 的更新

覆盖范围取决于 Apple 的规范,而不是有人来得及封装多少个端点。

  • App Store Connect——1,263 个操作,规范 v4.4.1。Apple 发布了 OpenAPI 文档;我们会下载并编译成精简索引(360KB,而原始规范为 3.3MB)。
  • App Store Server——30 个操作。Apple 没有为此发布 OpenAPI 文档,因此我们会从 Apple 自己的客户端库中解析端点集合,并固定在指定的发布标签上;每次运行 verify 时,都会将其与此仓库的目录进行差异比较。
  • 枚举表均由生成器生成,共 90 张。其他地方广为转载的一份指南列出了 Apple 并不存在的 eventState 值,还漏掉了两个实际存在的值;通过生成枚举表,这里就不可能出现这种问题。
  • 每周运行的任务会重新获取这两者;如果 Apple 有所变更,就会创建一个分支。

传输方式

node dist/index.js                       # stdio (default)
node dist/index.js --transport http --http-token "$(openssl rand -hex 32)"

HTTP 仅绑定到回环地址,没有 Bearer 令牌就拒绝启动。它还会验证 Host 和 Origin:否则,浏览器页面可以将绑定到回环地址的服务视为同源并访问它,而仅凭令牌无法防御这种情况。

Docker 使用 distroless 镜像构建,并以非 root 用户运行。注意,stdio 需要使用 docker run -i,且不得加上 -t——TTY 会破坏 JSON-RPC 流。


技能

服务可以回答问题,但无法阻止模型从正确答案中得出错误结论——例如,由于地区写成了 US 而不是 USA,结果列表为空;把三十条记录中的一页当作整个账户;或者对销售一次性购买项目的应用声称“没有订阅”。这些情况都没有错误可捕获,因为响应状态是 200。

这类判断封装成了 Claude Code 技能:

npx -p @abd3lraouf/app-store-connect-mcp asc-mcp-skill

它会安装到 ~/.claude/skills/app-store-connect(使用 --scope project 可安装到 ./.claude/skills;使用 --link 可通过符号链接关联一个检出目录,使编辑实时生效)。它不会向 settings.json 添加任何内容。

该技能列出的是在得出结论之前要执行的检查,而非 API 导览。凡是可以推导出来的内容,它都不会手动复制——没有枚举表,也没有端点列表;并且有一项测试会断言,其中的每个工具名称、资源 URI、提示词和枚举形态的值,都仍可追溯到 src/ 或 Apple 的规范。

失败记录

如今,失败只存在于对话记录中的工具结果里。对话结束后,Apple 的 x-request-id——Apple 支持团队会索要的唯一值——也会随之消失,模型尝试过哪些操作却未能找到所需内容的证据同样如此。

现在,两部分都会写入 failures.jsonl:服务会记录自己的 HTTP、网络和被吞掉的失败,技能则记录服务看不到的失败,也就是以 200 状态码返回的解读失败。

npm run triage        # what keeps failing, and what the cookbook never warned about

写入位置依次如下:如果设置了 ASC_FAILURE_LOG_DIR,则写入该目录(不会再写入其他位置——显式指定的目标却悄悄变成另一个位置,还不如没有目标);否则写入此软件包的工作检出目录,即包含 src/ 和 .git/ 的目录,而 npm pack 不会发布这两个目录;否则写入已安装技能自身的目录;最后写入 ~/.claude。

如果机器上既没有检出目录,也没有已安装的技能,除非 ASC_FAILURE_LOG=1 明确启用,否则不会写入任何内容。ASC_FAILURE_LOG=0 会在所有位置禁用日志记录。

绝不会写入的内容:请求头或请求正文——只记录正文的键名,因为 appStoreReviewDetails 的纯文本正文中包含有效的 demoAccountPassword。响应内容会精简为 Apple 的错误对象。预签名资源 URL 会记录为主机名,因为签名位于路径中。JWT、Bearer 令牌、PEM 区块和电子邮件地址的本地部分会作为第二道防线进行脱敏。

记录会通过 O_APPEND 描述符以单次、有大小限制的写入追加,因此服务和技能可以共用一个文件,无需加锁。这项保证依赖 POSIX,在 NFS 上不成立——请将 ASC_FAILURE_LOG_DIR 指向本地磁盘。


已知限制

坦诚说明这些限制,因为你迟早会发现它们:

  • 风险级别是根据方法和路径进行模式匹配的,这种方式刻意保持谨慎,但仍是启发式判断。执行写入前,请先阅读 asc_describe_endpoint。
  • 钥匙串存储仅适用于 macOS。 在其他系统上,请使用权限受限的文件路径。
  • --no-confirm 会禁用所有关卡——令牌、征询和 requiresUserInteraction 标志。此选项供 CI 和无人值守的 Agent 使用;只要有人在场,就不适合作为默认设置。
  • --no-online-checks 会跳过 OCSP 检查,这意味着会接受已撤销的证书。
  • 失败日志的无锁追加依赖 O_APPEND 的原子性,而网络文件系统不保证这一点。npm run triage 会跳过被截断的行,而不是报错,但网络挂载可能导致记录丢失。
  • 签名的接受路径已通过替换信任锚进行验证,而非使用 Apple 的信任锚——要获得真正由 Apple 签名的负载,需要真实的客户交易。证书链逻辑使用的是 Apple 自己的库。

发布

更新版本号、合并,完成。两个注册表都使用工作流自身的 OIDC 身份进行身份验证,因此无需轮换令牌,也无需记住标签:

npm run release:version patch     # or minor, major, or an exact version
git commit -am "Release v1.0.1" && git push

CI 会检测尚未发布到 npm 的版本,运行完整的检查门禁,然后发布到 npm 和 MCP Registry、为提交打标签,并创建 GitHub Release。触发条件是版本号而非标签,因此任务具有幂等性——重新运行不会发布任何内容。

许可证

Business Source License 1.1。可免费用于内部使用、评估和开发;若要将其作为托管或嵌入式服务提供给第三方,或将其重新分发到商业产品中,则需要获得许可。该许可证将于 2030-08-19 转为 Apache-2.0。

此处随附的 Apple OpenAPI 描述和根证书遵循 Apple 的条款,而非本许可证——请参阅 NOTICE。

Apple、App Store、App Store Connect、StoreKit 和 TestFlight 是 Apple Inc. 的商标。本项目与 Apple 无关。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。