Skip to main content
Glama

app-store-connect-mcp

一个 MCP 服务器,用于 Apple 的两个商业 API —— App Store Connect(1,263 个操作)和 App Store Server API / StoreKit 2(30 个操作)—— 通过五个工具实现,私钥存储在 macOS 钥匙串中,具有后果的写入操作需要显式确认。

1,293 operations · 5 tools · key never on disk · verified against the live APIs

为何如此构建

已有多个 App Store Connect MCP 服务器。每个都解决了部分问题;此方案取各者之长,弃其之短。

方式

保留

舍弃

手工封装工具

每个端点一个 MCP 工具

带类型、可发现的参数

70–900 个工具定义,>10 万 token,Apple 发布新版本时立刻过时

代码模式

LLM 编写 JS,服务器 eval 执行

两个工具,约 1k token,全覆盖

在持有签名密钥的进程中执行生成的代码

元工具

searchcall 带参数

相同的上下文优势,无需代码执行

此服务器采用第三种。覆盖率是 Apple 规范本身的属性,而非取决于某人封装了多少端点;并且模型永远无法在可以修改定价的进程内运行代码。

关于沙箱

代码模式的前提是生成的 JavaScript 在 Node 的 vm 中安全运行。事实并非如此。Node 自己的文档指出 vm 不是安全机制,任何作为全局对象注入的主机对象都会通过其自身的原型链暴露主机领域:

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

已针对该沙箱的忠实复现进行验证:它返回了主机环境。timeout 选项也无济于事——它仅限制同步执行,因此 async 忙循环会永远运行并耗尽事件循环。

参数化调度获得了相同的覆盖范围和相同的 token 成本,且无需可逃逸的解释器。

Related MCP server: App Store Connect MCP Server

凭据

私钥应存放在钥匙串中。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

钥匙串条目可以存储裸 PEM,或 base64 编码的 JSON:

{ "issuerID": "…", "keyID": "…", "privateKeyPEM": "-----BEGIN PRIVATE KEY-----\n…" }

推荐使用信封形式:标识符与密钥材料一同传输,因此 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
)"

安装

git clone https://github.com/abd3lraouf-studios/app-store-connect-mcp
cd app-store-connect-mcp
npm install && npm run build
{
  "mcpServers": {
    "app-store-connect": {
      "command": "node",
      "args": ["/path/to/app-store-connect-mcp/dist/index.js"],
      "env": {
        "ASC_KEY": "keychain:my-asc-key",
        "ASC_BUNDLE_ID": "com.example.app"
      }
    }
  }
}

仅当调用 App Store Server API 时,才需要 ASC_BUNDLE_ID——Apple 拒绝没有 bid 声明的 Server API token。

工具

工具

用途

asc_status

验证凭据,报告可达性和剩余速率限制配额。当任何操作失败时先运行此工具——它可以将错误的密钥与错误的请求区分开来。

asc_search_endpoints

按关键词、方法、标签或风险等级搜索两个 API。返回 operationId 并说明每个操作属于哪个工具。

asc_describe_endpoint

参数、请求体模式(包含真实字段名)、风险等级。

asc_call

读取操作。 路径和查询参数、分页、两个 API。

asc_write

所有更改数据的操作。 确认、dry_run、两个 API。

读取和写入是分开的工具,因为 Claude Code 会忽略标准的 destructiveHint 注解,但会尊重 _meta["anthropic/requiresUserInteraction"]——并且该标志是每个工具独立的。单个调度器无法为每个操作更改此标志。asc_write 携带此标志,因此即使在 bypassPermissions 下,写入操作也会提示用户。这比进程内的防护门(可通过 --no-confirm 关闭)提供了更强的保证。

资源

模型可以通过 @asc: 主动拉取的参考材料:

资源

内容

asc://cookbook

Apple 返回成功响应但实际含义与表面不同的情况——分页、alpha-3 地区代码、被拒绝的 sort、gzip 压缩的报告

asc://enums

所有 90 个枚举字段,从 Apple 的规范自动生成,因此不会过时

asc://risk

每个风险等级的含义及其可逆性

asc://sources

每个 API 描述的来源及时间

asc-response://…

溢出存储——见下文

如果结果太大无法内联返回,不会被截断。列表会修剪到适合的大小,同时说明截断情况及如何缩小请求范围,完整响应会作为资源保留,客户端可以在不消耗上下文的情况下读取。在序列化 JSON 中间截断会使模型得到无法解析的内容;静默截断更糟,因为部分列表会被视为完整列表。

提示词

四个工作流,可通过 /mcp__asc__<name> 使用:

release-readiness · pricing-audit · review-triage · testflight-status

每个工作流链式调用多个请求——用斜杠命令包装一个请求只是同义词,而非工作流——每个工作流都编码了陷阱,例如 sortcustomerReviews 上会被拒绝,以及审核文本是不可信的输入。

写入安全

HTTP 方法不能很好地反映后果:PATCH /v1/subscriptionPricesPATCH /v1/appInfos/{id} 都是写入操作,但只有前者会改变对客户的收费,并且两者都不会因重复执行而撤销。操作带有风险等级:

等级

数量

含义

READ

797

无变化。

WRITE

238

更改数据。

REVENUE

61

定价、订阅、权益。

DESTRUCTIVE

132

删除操作。

RELEASE

12

构建、提交、发布内容。

ACCESS

12

可访问账户的用户。

INFRASTRUCTURE

11

证书、标识符、回调 URL。

默认情况下,底部五个等级会返回确认令牌而非执行操作。该令牌通过哈希绑定到具体的操作、路径、查询和请求体,因此无法通过低成本调用获取令牌后用于高成本调用。令牌一次性使用,五分钟内有效。

--read-only    block every write        --confirm     confirm every write
--no-confirm   never confirm            (default)     confirm the five tiers above

当客户端支持引导时,asc_write 直接询问用户,显示方法、路径、请求体和等级。否则,它会回退到通过哈希绑定到具体操作、路径、查询和请求体的确认令牌,因此为低成本调用颁发的令牌不能用于高成本调用。声明支持引导但未能提供的客户端会回退,而不是直接通过。dry_run 会报告确切的请求,但不会发送。

传输层

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

HTTP 绑定到 127.0.0.1,并且没有 bearer token 则拒绝启动。此进程持有可以更改 App Store 定价的密钥;不应在没有认证的情况下监听。绑定到非回环地址会发出警告,最好与 TLS 终止代理或 SSH 隧道配合使用。

与 Apple 保持同步

npm run fetch:specs   # re-download both descriptions
npm run build         # recompile the operation index
npm run verify        # drift check + live calls against both APIs

两个 API 的来源不同,这是必要的:

  • App Store Connect — Apple 发布了一个真实的 OpenAPI 3.0 文档。它被下载并编译成精简索引(360KB,相比于 3.3MB 的规范),以便搜索保持快速,并且仅在描述一个操作时才打开完整文档。

  • App Store Server — Apple 发布任何 OpenAPI 文档;文档是纯文本形式。权威的机器可读描述是 Apple 自己的客户端 apple/app-store-server-library-node,其中每个端点都是一个直接的 makeRequest 调用。fetch:specs 从该源码的固定发布标签中解析出端点集,而 verify 将其与 src/storekit.ts 中的目录进行差异比较。

该目录中有两个细节与文档暗示的内容相矛盾,并且两者都是关键:

  • 主机是 api.storekit.apple.com / api.storekit-sandbox.apple.com。旧的 api.storekit.itunes.apple.com 名称不再提供此 API。

  • 批量续订扩展状态路径的段顺序为 {productId}/{requestIdentifier}——而不是相反。

验证

npm run verify 是只读操作,并会发起真实调用。上次运行时间:

1. Catalogue drift — src/storekit.ts vs Apple’s client
  ✓ all 30 Apple endpoints present in the catalogue
  ✓ no endpoints in the catalogue that Apple does not define

2. App Store Connect API — live
  ✓ apps_getCollection → 2 apps
  ✓ apps_getInstance / builds / appStoreVersions → HTTP 200
  ✓ pagination walked 3 pages
  ✓ bogus id → structured 404

3. App Store Server API (StoreKit 2) — live
  ✓ storekit token carries bid;  connect token correctly omits it
  ✓ getTransactionInfo / getAllSubscriptionStatuses / getTransactionHistory v2
      → authenticated and routed (Apple errorCode 4000006)
  ✓ getNotificationHistory (30d window) → HTTP 200

14 passed, 0 failed

StoreKit 探测使用故意无效的交易 ID。信号是回复的结构:一个结构化的 Apple errorCode 证明请求已通过身份验证并被路由,而 401 则证明未通过身份验证。

健壮性

  • 超时和重试。 读取操作在 408/429/5xx 错误时重试;写入操作仅在 429 错误时重试,此时 Apple 在处理请求之前已拒绝。写入操作若失败不明确,则报告为不明确且绝不重新发送——重复的 POST 比报告失败更糟糕。

  • 速率限制。 根据文档记录的每小时限制和未记录的每分钟限制进行节流,并根据 Apple 自己的 x-rate-limit 头部进行校正,该头部会考虑共享密钥的其他客户端。x-request-id 会提供给 Apple 支持。

  • 主机锁定。 每个 URL(包括 links.next 分页游标)都会根据 Apple 的三个 API 主机白名单进行检查。游标是服务器提供的输入;盲目跟随会将 bearer token 带到它命名的任何主机。

  • 响应整形。 移除 links 和仅包含链接的 relationships,保留 links.next——在真实价格点列表上,体积减小超过 60%。

  • 生命周期。 stdio 服务器在 stdin 遇到 EOF 和接收到信号时退出,而不是作为持有签名密钥的孤儿进程残留。

已知限制

  • JWS 响应被解码,但未验证。 StoreKit 负载由 Apple 签名到达;验证链需要 Apple 的根证书。解码后的值出现在 *_decoded 字段中,并标记为未验证。未检查签名前,请勿将其视为购买凭证。

  • 风险等级基于方法与路径的模式匹配。 它故意保持谨慎,但在执行写入操作前,请阅读 asc_describe_endpoint,不要仅依赖等级。

  • 钥匙串存储仅限 macOS。 在其他平台上,请使用具有严格权限的文件路径。

  • --no-confirm 完全禁用防护门。它专为 CI 设计;对于交互式代理来说,这是一个糟糕的默认设置。

许可证

MIT

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Let ChatGPT, Claude & Cursor use your Mac: email, calendar, iMessage, Teams, files. Local, free.

  • Search, read, and write your Apple Notes from ChatGPT/Claude via a local Mac agent + MCP relay.

  • Manage your NanoCart store from any AI agent: products, orders, coupons, subscribers, reports.

View all MCP Connectors

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/abd3lraouf-studios/app-store-connect-mcp'

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