appstore-api-mcp 1.12.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,117 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/) and the project uses
5
5
  [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [1.16.0] - 2026-10-07
8
+
9
+ ### Added — App Store marketing & growth (recent ASC features)
10
+ - **Custom Product Pages:** `list_custom_product_pages`, `get_custom_product_page`,
11
+ `create_custom_product_page`, `list/create_custom_product_page_version(s)`,
12
+ `list/create/update_custom_product_page_localization(s)`.
13
+ - **Product Page Optimization (A/B, appStoreVersionExperiments v2):**
14
+ `list_ppo_experiments`, `get_ppo_experiment`, `create_ppo_experiment`,
15
+ `start_ppo_experiment`, `stop_ppo_experiment`, `list/create_experiment_treatment(s)`,
16
+ `create_experiment_treatment_localization`. (Experiment *results* are UI-only —
17
+ the API exposes no metrics endpoint.)
18
+ - **Asset Library:** `get_asset_library`, `list_asset_library_images/videos`,
19
+ `upload_asset_library_image`, `assign_asset_placement` (reuse an asset on a
20
+ product page / event / treatment), `delete_asset_placement`.
21
+ - **Webhooks** (WWDC25): `list/get/create/update/delete_webhook`,
22
+ `list_webhook_deliveries`, `ping_webhook` — event callbacks for version/build/
23
+ TestFlight-feedback state, instead of polling.
24
+ - **Subscription offer codes** (promo-code replacement): `list_subscription_offer_codes`,
25
+ `create_subscription_offer_code`, `create_offer_code_one_time_use`,
26
+ `create_offer_code_custom`, `list_offer_code_codes`.
27
+ - **In-App Events:** `list/get/create_app_event`, `create_app_event_localization`.
28
+ - **Game Center challenges:** `list_game_center_challenges`, `get_game_center_challenge`.
29
+ - **Screenshots/previews** now attach to Custom Product Page and PPO treatment
30
+ localizations too: `create_screenshot_set` / `create_app_preview_set` accept
31
+ `customProductPageLocalizationId` / `treatmentLocalizationId`.
32
+
33
+ ## [1.15.0] - 2026-10-05
34
+
35
+ ### Added — submission flow (from 5 field reports of real submissions)
36
+ - **Build ↔ version ↔ review loop** (the biggest gap; previously `raw_request`):
37
+ `attach_build_to_version`, `get_app_store_version` (incl. attached build),
38
+ `update_app_store_version` (`usesIdfa`, releaseType…), `update_build`
39
+ (per-build `usesNonExemptEncryption` export compliance; `expired`),
40
+ `expire_build`, `get_build`, `wait_for_build_processing`, `next_build_number`.
41
+ - **Review submissions:** `list_review_submissions`, `get_review_submission`,
42
+ `add_review_submission_item`, `cancel_review_submission` (surfaces Apple's
43
+ "can't cancel empty/non-cancellable" cleanly), `get_app_store_review_detail`.
44
+ - **TestFlight:** `get_beta_review_status`, `set_beta_build_notes` ("What to Test").
45
+ - **Screenshots:** `find_incomplete_screenshots` (assets stuck != COMPLETE that
46
+ silently block submission), `reorder_screenshots`, `replace_screenshots` (bulk
47
+ delete + re-upload in order).
48
+ - **Subscriptions:** `list_subscription_groups`, `list_subscriptions`,
49
+ `list_subscription_offers` (**flags overlapping offer date ranges** — the
50
+ sandbox `countMismatch` cause), `create_subscription_group`,
51
+ `create_subscription`, `create_in_app_purchase`.
52
+ - **Territories:** `list_app_territories` (compact appAvailabilityV2 summary).
53
+ - **Diagnostics & orchestrators:** `diagnose_submission` (the exact blockers
54
+ behind submit's opaque 409), `swap_build` (wait→cancel→attach), `release_pipeline`
55
+ (attach→diagnose→submit), `bulk_upsert_localizations` (version + app-info, all
56
+ locales, creates missing ones, whitespace preserved verbatim).
57
+
58
+ ### Fixed
59
+ - `list_builds` ignored `limit` (it paged via `getAll`). Now returns a single
60
+ page capped to `limit`; added `version` / `processingState` filters.
61
+ - `submit_for_review` now pre-flights and, on failure, surfaces the real blockers
62
+ (no attached build, build not VALID, unset export compliance / IDFA, assets
63
+ still processing) instead of Apple's opaque `409 ENTITY_STATE_INVALID`; cleans
64
+ up the half-created empty submission.
65
+ - `create_app_info_localization` upserts instead of failing "already exists"
66
+ (Apple auto-creates the name/subtitle row with the version localization).
67
+ - `release_readiness_check` now verifies a build is attached + VALID, checks
68
+ description/screenshots across **all** locales, and flags assets still processing.
69
+ - `upload_screenshot` returns a compact result (dropped ~700 tokens of signed
70
+ upload URLs per image).
71
+ - `list_app_store_version_localizations` gains `omitLongFields` (return lengths
72
+ instead of full description/promotionalText/whatsNew).
73
+ - `list_analytics_reports` accepts `appId` (uses the app's newest report request)
74
+ instead of crashing on a missing `requestId`.
75
+
76
+ ## [1.14.0] - 2026-10-05
77
+
78
+ ### Added
79
+ - **PPP regional pricing for IAPs & subscriptions.** Bulk-set in-app purchase and
80
+ subscription prices across ~174 territories from a US base price, scaled by
81
+ purchasing-power parity. Logic + the 175-country dataset are ported from the
82
+ MIT-licensed [appstore-ppp-prices](https://github.com/duceum/appstore-ppp-pricing-agent-skill).
83
+ - `list_purchasable_products` — IAPs (v2) + subscriptions with current US prices.
84
+ - `preview_ppp_prices` — read-only dry run: per-territory target table, scaled in
85
+ local currency via Apple's equalizations and snapped to each territory's real
86
+ price grid (ratio-preserving floors of 0.99 / 0.49).
87
+ - `apply_ppp_prices` — applies the prices (IAP = one atomic price-schedule POST;
88
+ subscriptions = per-territory with `preserveCurrentPrice` + future `startDate`,
89
+ clearing pending prices first). **Irreversible**: requires `confirm:true`, is
90
+ gated by `APPSTORE_MCP_ALLOW_PRICE_CHANGES` and read-only mode, and the docs
91
+ mandate previewing first.
92
+ - Per-tier coefficients use embedded defaults; override any tier (premium,
93
+ high_income, upper_middle, lower_middle, emerging) by passing a `coefficients`
94
+ map — the agent reasons about elasticity, no server-side LLM or extra key.
95
+ - New `client.getAllPages()` helper returns side-loaded `included` resources.
96
+
97
+ ## [1.13.0] - 2026-06-13
98
+
99
+ ### Added
100
+ - **iOS CI/CD → TestFlight bootstrap.** Turn a new iOS app into a fastlane +
101
+ GitHub Actions → TestFlight pipeline in one call:
102
+ - `ensure_asc_app` — find the App Store Connect app record for a bundle id
103
+ (find-only; the public API has no `POST /apps`, so it returns guidance when
104
+ the record doesn't exist yet).
105
+ - `bootstrap_ios_cicd` — scaffold the 7 pipeline files (Gemfile, fastlane
106
+ Appfile/Fastfile/.gitignore/SETUP.md, two GitHub Actions workflows) into the
107
+ app's repo, auto-detecting `appDir`/`bundleId`/`teamId`/`scheme`/`target`
108
+ from the `.xcodeproj`. Commits to a branch or opens a PR. Xcode automatic
109
+ ("cloud") signing via `-allowProvisioningUpdates` — no `match` repo.
110
+ - `set_repo_ci_secrets` — push `ASC_KEY_ID` / `ASC_ISSUER_ID` / `ASC_KEY_P8`
111
+ (base64) to the repo's Actions secrets. The API key is read from this
112
+ server's own config, never passed as an argument or returned in output;
113
+ values are piped to `gh secret set` over stdin.
114
+ - `bootstrap_testflight` — one-call orchestrator running all three.
115
+ - GitHub operations shell out to the `gh` CLI (no extra token, no new
116
+ dependency). The bootstrap writers respect read-only / safe mode.
117
+
7
118
  ## [1.12.0] - 2026-06-03
8
119
 
9
120
  ### Added
package/README.md CHANGED
@@ -422,6 +422,7 @@ More: **[docs/SECURITY.md](docs/SECURITY.md)**.
422
422
  | `401`/`403` errors | Wrong issuer/key id, wrong `.p8`, or the key's role lacks permission. |
423
423
  | `409` on metadata update | The version isn't in an editable state — create/select a `PREPARE_FOR_SUBMISSION` version. |
424
424
  | `npx` can't find the package | Ensure Node ≥ 18 and that the package name is published/correct. |
425
+ | `SyntaxError: Unexpected token '&&='` or `npm … not to run on Node.js v14` at startup | `npx` is using an **old Node** still on your `PATH`, not your Node ≥ 18. Check with `npx node --version`. Fix: point `command` at an absolute modern npx (e.g. `/opt/homebrew/opt/node@22/bin/npx`) or add a `PATH` to the server's `env`. See [SETUP.md → multiple Node versions](docs/SETUP.md#multiple-node-versions-the-most-common-startup-crash). |
425
426
  | Tools don't appear | MCP servers load at client startup — restart the client / start a new session. |
426
427
 
427
428
  ---
package/docs/SETUP.md CHANGED
@@ -112,3 +112,58 @@ Then set `ASC_PRIVATE_KEY_BASE64` instead of `ASC_PRIVATE_KEY_PATH`.
112
112
  Create or select a version in `PREPARE_FOR_SUBMISSION` state.
113
113
  - **Token/clock errors** — JWTs are time-based; make sure your system clock is correct.
114
114
  - **`npx` fails to resolve the package** — verify Node ≥ 18 and the published package name.
115
+
116
+ ### Multiple Node versions (the most common startup crash)
117
+
118
+ > **Symptom:** the server fails to connect, and its logs show one of:
119
+ > ```
120
+ > npm v10.x is known not to run on Node.js v14.x
121
+ > SyntaxError: Unexpected token '&&='
122
+ > ```
123
+
124
+ Having Node ≥ 18 *installed* isn't enough — `npx` has to actually **run on it**.
125
+ If you have more than one Node on your machine (nvm, Homebrew, system Node, Xcode's
126
+ bundled Node…), `npx` may resolve to an **old** one earlier on your `PATH`. Modern
127
+ npm then crashes before the server ever reads your credentials, so it looks like an
128
+ auth/config problem when it isn't.
129
+
130
+ **Diagnose** — ask which Node `npx` actually uses (not just `node --version`):
131
+
132
+ ```bash
133
+ npx node --version # if this prints v14.x / anything < 18, that's the bug
134
+ which -a node npx # shows every node/npx on your PATH, in resolution order
135
+ ```
136
+
137
+ **Fix — option A (recommended): pin an absolute, modern npx as the `command`.**
138
+ Find it with `which npx` under your good Node (e.g. `/opt/homebrew/opt/node@22/bin/npx`),
139
+ then use that full path instead of bare `npx`:
140
+
141
+ ```json
142
+ {
143
+ "mcpServers": {
144
+ "appstore-api": {
145
+ "command": "/opt/homebrew/opt/node@22/bin/npx",
146
+ "args": ["-y", "appstore-api-mcp"],
147
+ "env": {
148
+ "ASC_KEY_ID": "YOUR_KEY_ID",
149
+ "ASC_ISSUER_ID": "YOUR_ISSUER_ID",
150
+ "ASC_PRIVATE_KEY_PATH": "/Users/you/.appstoreconnect/AuthKey_XXXXXXXXXX.p8"
151
+ }
152
+ }
153
+ }
154
+ }
155
+ ```
156
+
157
+ **Fix — option B: add a `PATH` to the server's `env`** so its child process resolves
158
+ the right Node first (handy when `command` must stay as bare `npx`):
159
+
160
+ ```json
161
+ "env": {
162
+ "ASC_KEY_ID": "YOUR_KEY_ID",
163
+ "ASC_ISSUER_ID": "YOUR_ISSUER_ID",
164
+ "ASC_PRIVATE_KEY_PATH": "/Users/you/.appstoreconnect/AuthKey_XXXXXXXXXX.p8",
165
+ "PATH": "/opt/homebrew/opt/node@22/bin:/opt/homebrew/bin:/usr/bin:/bin"
166
+ }
167
+ ```
168
+
169
+ After either fix, restart the client (or start a new session) so the server relaunches.
package/docs/TOOLS.md CHANGED
@@ -352,10 +352,91 @@ The agent does the translating; this writes them.
352
352
  Creates a new price schedule from a price point. **Changes live pricing — confirm first.**
353
353
  - `appId` **(required)**, `baseTerritory` **(required)**, `pricePointId` **(required)**, `startDate` (YYYY-MM-DD, optional)
354
354
 
355
+ ## PPP regional pricing (IAP & subscriptions)
356
+
357
+ Bulk-set **in-app purchase / subscription** prices across ~174 territories from a
358
+ US base price, scaled by purchasing-power-parity (PPP). Distinct from
359
+ `set_app_price` (which sets the paid-*app* price). The target price is scaled in
360
+ each territory's **local currency** (via Apple's equalizations) and snapped to a
361
+ real price-point on that territory's grid — not a dollar figure equalized to a
362
+ coarse subset. Ported from the MIT-licensed
363
+ [appstore-ppp-prices](https://github.com/duceum/appstore-ppp-pricing-agent-skill).
364
+
365
+ > **Always `preview_ppp_prices` → show the user the table → `apply_ppp_prices`.**
366
+ > Prices are customer-facing across ~174 territories and **cannot be undone.**
367
+
368
+ Coefficients come from an embedded 175-country table (tiers: `premium`,
369
+ `high_income`, `upper_middle`, `lower_middle`, `emerging`; USA is always the 1.00
370
+ base). There is **no server-side LLM** — reason about the app's elasticity (games =
371
+ high → discount poorer markets more; AI/productivity = low → discount less) and
372
+ pass per-tier overrides. Floors: 0.99 (premium/high_income), 0.49 (others), with
373
+ ratio preservation across multiple products.
374
+
375
+ ### list_purchasable_products
376
+ Every IAP + subscription with its current US price, tagged `IAP`/`SUB`.
377
+ - `appId` **(required)** — use the returned `productId` with the tools below.
378
+
379
+ ### preview_ppp_prices
380
+ Dry run (read-only): the full per-territory price table without writing.
381
+ - `appId`, `productId` **(required)**
382
+ - `usPrice` (override the US base), `coefficients` (per-tier overrides, each 0.1–2.0),
383
+ `exclude` (territory codes, e.g. `["RUS","BLR"]`)
384
+
385
+ ### apply_ppp_prices
386
+ Applies the prices. **Irreversible.** Requires `confirm:true`; blocked in read-only
387
+ mode and when `APPSTORE_MCP_ALLOW_PRICE_CHANGES=false`.
388
+ - `appId`, `productId`, `confirm:true` **(required)**
389
+ - `usPrice`, `coefficients`, `exclude` (same as preview)
390
+ - `preserveCurrentPrice` (subscriptions; default **true** — existing subscribers keep
391
+ their price), `startDate` (subscriptions; `YYYY-MM-DD`, default 2 days out)
392
+ - IAPs are set in one atomic request; subscriptions per-territory (pending price
393
+ changes are cleared first).
394
+
355
395
  ## Product Page Optimization
356
396
 
357
397
  ### list_app_store_version_experiments
358
- - `appId` **(required)** — A/B tests with name, state, traffic proportion, start/end.
398
+ - `appId` **(required)** — A/B tests with name, state, traffic proportion, start/end (legacy v1 list).
399
+
400
+ ## Marketing & growth
401
+
402
+ Recent App Store features — Custom Product Pages, Product Page Optimization (A/B),
403
+ Asset Library, Webhooks, subscription offer codes, In-App Events, Game Center challenges.
404
+
405
+ ### Custom Product Pages
406
+ Alternate product pages (own screenshots/text, each with a unique marketing URL).
407
+ - `list_custom_product_pages(appId)`, `get_custom_product_page(id)`, `create_custom_product_page(appId, name)`
408
+ - `list_custom_product_page_versions(customProductPageId)`, `create_custom_product_page_version(customProductPageId, deepLink?)`
409
+ - `list_custom_product_page_localizations(versionId)`, `create_custom_product_page_localization(versionId, locale, promotionalText?)`, `update_custom_product_page_localization(localizationId, promotionalText)`
410
+ - Screenshots: `create_screenshot_set(customProductPageLocalizationId, displayType)` → `upload_screenshot`.
411
+
412
+ ### Product Page Optimization (A/B, v2)
413
+ - `list_ppo_experiments(versionId)`, `get_ppo_experiment(id)`, `create_ppo_experiment(appId, name, trafficProportion, platform?)`
414
+ - `start_ppo_experiment(id)` / `stop_ppo_experiment(id)` (start/stop via a `started` flag; stop preserves results)
415
+ - `list_experiment_treatments(experimentId)`, `create_experiment_treatment(experimentId, name, appIconName?)`, `create_experiment_treatment_localization(treatmentId, locale)`
416
+ - Screenshots: `create_screenshot_set(treatmentLocalizationId, displayType)`.
417
+ - ⚠️ **Results (conversion %, confidence) are not in the API** — view them in the App Store Connect web UI.
418
+
419
+ ### Asset Library
420
+ Upload media once, reuse across product pages / events / treatments.
421
+ - `get_asset_library(appId)`, `list_asset_library_images(appId, category?)`, `list_asset_library_videos(appId)`
422
+ - `upload_asset_library_image(appId, filePath, category?, referenceName?)` — category `CREATIVE_ASSETS` or `APP_SCREENSHOTS_AND_PREVIEWS`
423
+ - `assign_asset_placement({imageId|videoId}, <one destination localization id>, placementType?)`, `delete_asset_placement(placementId)`
424
+
425
+ ### Webhooks
426
+ Event callbacks instead of polling (≤10 per app).
427
+ - `list_webhooks(appId)`, `get_webhook(id)`, `create_webhook(appId, name, url, eventTypes[], secret, enabled?)`, `update_webhook(id, …)`, `delete_webhook(id)`
428
+ - `list_webhook_deliveries(id)`, `ping_webhook(id)`
429
+ - Common `eventTypes`: `APP_STORE_VERSION_APP_VERSION_STATE_UPDATED`, `BUILD_UPLOAD_STATE_UPDATED`, `BUILD_BETA_DETAIL_EXTERNAL_BUILD_STATE_UPDATED`, `BETA_FEEDBACK_CRASH_SUBMISSION_CREATED`, `BETA_FEEDBACK_SCREENSHOT_SUBMISSION_CREATED`.
430
+
431
+ ### Subscription offer codes (promo-code replacement)
432
+ - `list_subscription_offer_codes(subscriptionId)`, `create_subscription_offer_code(subscriptionId, name, offerMode, duration, numberOfPeriods, customerEligibilities[], offerEligibility, prices[])`
433
+ - `create_offer_code_one_time_use(offerCodeId, numberOfCodes, expirationDate, environment?)`, `create_offer_code_custom(offerCodeId, customCode, numberOfCodes, expirationDate?)`, `list_offer_code_codes(offerCodeId, kind?)`
434
+
435
+ ### In-App Events
436
+ - `list_app_events(appId, eventState?)`, `get_app_event(id)`, `create_app_event(appId, referenceName, …)`, `create_app_event_localization(eventId, locale, …)`
437
+
438
+ ### Game Center challenges (read)
439
+ - `list_game_center_challenges(appId)`, `get_game_center_challenge(id)`
359
440
 
360
441
  ## Code-signing health
361
442
 
@@ -451,7 +532,7 @@ clear error):
451
532
  | --- | --- |
452
533
  | `APPSTORE_MCP_READ_ONLY=true` | block all writes |
453
534
  | `APPSTORE_MCP_ALLOW_RELEASE=false` | block `release_version` / `set_phased_release` |
454
- | `APPSTORE_MCP_ALLOW_PRICE_CHANGES=false` | block `set_app_price` |
535
+ | `APPSTORE_MCP_ALLOW_PRICE_CHANGES=false` | block `set_app_price` / `apply_ppp_prices` |
455
536
  | `APPSTORE_MCP_ALLOW_REVIEW_REPLIES=false` | block public review replies |
456
537
  | `APPSTORE_MCP_ALLOW_EXTERNAL_TESTFLIGHT=false` | block `submit_beta_review` |
457
538
 
@@ -477,6 +558,46 @@ clear error):
477
558
  > See **[RECIPES.md](RECIPES.md)** for copy-paste prompts that chain these into
478
559
  > workflows (prepare-version, release-train-with-gates, review→notes, portfolio audit).
479
560
 
561
+ ## Submission flow (build ↔ version ↔ review)
562
+
563
+ The steps a real submission needs beyond `submit_for_review` — attaching a build,
564
+ fixing the silent blockers behind Apple's opaque `409`, and swapping a build that's
565
+ already in review.
566
+
567
+ ### Build & version
568
+ - `attach_build_to_version` — `versionId` + (`buildId` or `buildNumber`+`appId`). The mandatory pre-submit link.
569
+ - `get_app_store_version(versionId)` — state, releaseType, `usesIdfa`, and the **attached build** (or null).
570
+ - `update_app_store_version(versionId, …)` — `usesIdfa`, `releaseType`, `earliestReleaseDate`, `versionString`, `downloadable`.
571
+ - `update_build` — `usesNonExemptEncryption` (export compliance, **per-build, doesn't carry over**), `expired`. By `buildId` or `buildNumber`+`appId`.
572
+ - `expire_build`, `get_build`, `next_build_number(appId)`.
573
+ - `wait_for_build_processing(appId, buildNumber, timeoutSeconds?)` — polls to VALID/INVALID/FAILED.
574
+
575
+ ### Review submissions
576
+ - `list_review_submissions(appId, state?)`, `get_review_submission(id)`.
577
+ - `add_review_submission_item(reviewSubmissionId, versionId)`.
578
+ - `cancel_review_submission` — by `submissionId` or `appId` (current in-flight); optional `waitSeconds`. Surfaces Apple's refusal on empty/non-cancellable submissions.
579
+ - `get_app_store_review_detail(versionId)` — contact info, demo account, notes.
580
+
581
+ ### TestFlight
582
+ - `get_beta_review_status` (build's `betaReviewState`), `set_beta_build_notes(whatsNew, locale?)` ("What to Test", upsert).
583
+
584
+ ### Screenshots
585
+ - `find_incomplete_screenshots(versionId)` — assets whose `assetDeliveryState != COMPLETE` (silent submit blockers).
586
+ - `reorder_screenshots(screenshotSetId, orderedIds)` — new uploads append last, so re-order after re-upload.
587
+ - `replace_screenshots(screenshotSetId, filePaths[])` — delete all + upload in order, one call.
588
+
589
+ ### Subscriptions
590
+ - `list_subscription_groups(appId)`, `list_subscriptions(groupId)`.
591
+ - `list_subscription_offers(subscriptionId)` — **flags overlapping offer date ranges** (the sandbox `countMismatch` cause).
592
+ - `create_subscription_group`, `create_subscription`, `create_in_app_purchase`. (First-time products still need ticking for review on the version page — the API can't submit them.)
593
+
594
+ ### Diagnostics & orchestrators
595
+ - `diagnose_submission(appId, versionId)` — read-only: the exact blockers behind submit's 409.
596
+ - `swap_build(appId, versionId, buildNumber|buildId)` — wait for processing → cancel in-flight review → attach.
597
+ - `release_pipeline(appId, versionId, buildNumber?, submit?)` — attach → diagnose → (if clean and `submit:true`) submit.
598
+ - `bulk_upsert_localizations(versionId, { locale: {…} })` — version + app-info fields across all locales, creates missing ones; `dryRun` supported.
599
+ - `list_app_territories(appId)` — compact availability summary.
600
+
480
601
  ## Build & ship (macOS + Xcode)
481
602
 
482
603
  These run local Xcode tooling, so they only work on a Mac with Xcode installed.
@@ -503,6 +624,49 @@ in `list_builds` and can be submitted with `submit_for_review`.
503
624
 
504
625
  ---
505
626
 
627
+ ## iOS CI/CD → TestFlight bootstrap
628
+
629
+ Turn a new iOS app into a fastlane + GitHub Actions → TestFlight pipeline in one
630
+ call. Signing is Xcode automatic ("cloud") signing via `-allowProvisioningUpdates`
631
+ — no `match` repo. The GitHub side shells out to the `gh` CLI (install + `gh auth
632
+ login` required; reuses your existing auth, no extra token). The App Store Connect
633
+ API key lives only in this server's environment and is exposed only through these
634
+ high-level actions — never as an argument, never in output.
635
+
636
+ > Create the App Store Connect API key **once at the TEAM level** (App Store
637
+ > Connect → Users and Access → Integrations) so the same three secret values work
638
+ > for every app/repo.
639
+
640
+ ### ensure_asc_app
641
+ Find the App Store Connect app record for a bundle id. **Find-only:** the public
642
+ API cannot create app records (there is no `POST /apps`), so `created` is always
643
+ `false`. If missing, returns `found:false` plus guidance (register the bundle id,
644
+ create the record once in the web UI).
645
+ - `bundleId` **(required)**, `name`, `sku`, `platform`, `primaryLocale`
646
+ - **Returns:** `{ app_id, created, found, bundleId, name }`
647
+
648
+ ### bootstrap_ios_cicd
649
+ Scaffold the 7 pipeline files (`Gemfile`, `fastlane/{Appfile,Fastfile,.gitignore,
650
+ SETUP.md}`, `.github/workflows/{ios-ci.yml,ios-testflight.yml}`). Auto-detects
651
+ `appDir`/`bundleId`/`teamId`/`scheme`/`target` from the repo's `.xcodeproj`.
652
+ - `repoDir` (local clone, default `.`), `repo` (`owner/name` for the PR), `owner`
653
+ - overrides: `appDir`, `bundleId`, `teamId`, `scheme`, `target`
654
+ - `mode`: `pr` (default — branch + push + open PR), `branch`, `commit`, `files`
655
+ - `branch`, `baseBranch`, `dryRun` (preview detected values + rendered files)
656
+
657
+ ### set_repo_ci_secrets
658
+ Push `ASC_KEY_ID`, `ASC_ISSUER_ID`, `ASC_KEY_P8` (base64) to the repo's Actions
659
+ secrets via `gh secret set` (values piped over stdin; `gh` does the libsodium
660
+ sealed-box encryption). Key material is read from this server's env, never echoed.
661
+ - `repo` (`owner/name`), `owner`, `repoDir` (derive `owner/name` from `origin`)
662
+
663
+ ### bootstrap_testflight
664
+ One-call orchestrator: `ensure_asc_app` → `bootstrap_ios_cicd` → `set_repo_ci_secrets`.
665
+ If the app record doesn't exist yet, it still scaffolds + sets secrets and tells
666
+ you to create the record in the web UI. Same options as `bootstrap_ios_cicd`.
667
+
668
+ ---
669
+
506
670
  ## Rate limits
507
671
 
508
672
  App Store Connect allows ~3,500 requests/hour and returns `429` when exceeded.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appstore-api-mcp",
3
- "version": "1.12.0",
3
+ "version": "1.16.0",
4
4
  "description": "MCP server for Apple App Store Connect — edit listings (keywords, descriptions, titles, screenshots), track analytics (downloads, proceeds, subscriptions, retention), run a fleet-wide ASO audit, preview changes with dry-run, and reach the full API. Works with any MCP client (Claude, Codex, Cursor, Windsurf, VS Code, Zed, Gemini CLI, Antigravity, Amazon Q, Goose, and more).",
5
5
  "type": "module",
6
6
  "bin": {