Install
$ agentstack add mcp-akoskomuves-appstoreconnect-mcp ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
appstoreconnect-mcp
[](https://www.npmjs.com/package/@akoskomuves/appstoreconnect-mcp) [](https://github.com/akoskomuves/appstoreconnect-mcp/actions/workflows/ci.yml) [](LICENSE)
A Model Context Protocol server for the Apple App Store Connect API. Drives apps, subscriptions, pricing, and more from any MCP-compatible client (Claude Code, Claude Desktop, Cursor, Windsurf).
The first published surface is subscription pricing — including a Purchasing Power Parity rebalance flow that's already been used to schedule 120 production price changes across 65 territories on a real iOS app. New ASC domains (TestFlight, sales, screenshots, IAPs) are designed to plug in one file at a time; see [Roadmap](#roadmap).
Install (zero-config)
npx @akoskomuves/appstoreconnect-mcp init
The wizard:
- Opens App Store Connect → Keys so you can download a
.p8(skipped if you already have one). - Copies the key to
~/.appstore/withchmod 600. - Asks for your Issuer ID and (auto-detected) Key ID.
- Verifies auth with a real API call before writing anything.
- Detects which MCP clients you have installed — Claude Code, Claude Desktop, Cursor, Windsurf — and registers itself in the ones you pick.
When something looks off later, run a read-only diagnostic:
npx @akoskomuves/appstoreconnect-mcp doctor
Manual install
If you'd rather wire it up by hand, add to ~/.claude.json (Claude Code), claude_desktop_config.json (Claude Desktop), or your client's equivalent:
{
"mcpServers": {
"appstoreconnect": {
"command": "npx",
"args": ["-y", "@akoskomuves/appstoreconnect-mcp"],
"env": {
"ASC_ISSUER_ID": "...",
"ASC_KEY_ID": "...",
"ASC_PRIVATE_KEY_PATH": "~/.appstore/AuthKey_XXXXXXXXXX.p8"
}
}
}
}
Or via Claude Code's CLI:
claude mcp add appstoreconnect \
-e ASC_ISSUER_ID=... \
-e ASC_KEY_ID=... \
-e ASC_PRIVATE_KEY_PATH=~/.appstore/AuthKey_XXXXXXXXXX.p8 \
-- npx -y @akoskomuves/appstoreconnect-mcp
Configure
Generate an App Store Connect API key at App Store Connect → Users and Access → Integrations → Keys. Pricing writes need the Admin role; read-only operations work with App Manager.
| Variable | What | | --- | --- | | ASC_ISSUER_ID | Issuer UUID from the Keys page | | ASC_KEY_ID | 10-character Key ID | | ASC_PRIVATE_KEY_PATH | Path to your downloaded AuthKey_XXXXXXXXXX.p8 file (~ is expanded) |
The .p8 file is a private key — never commit it. Recommended: ~/.appstore/AuthKey_XXXXXXXXXX.p8 outside any repo.
Optional: In-App Purchase signing key
Only needed for the asc_sign_* tools (subscription offer redemption signing). Issue a second key at App Store Connect → Users and Access → Integrations → In-App Purchase — this is a separate key from the ASC API key above, generated on a different tab of the same page.
| Variable | What | | --- | --- | | ASC_IAP_ISSUER_ID | Issuer UUID from the In-App Purchase keys tab (different from ASC_ISSUER_ID) | | ASC_IAP_KEY_ID | 10-character Key ID for the IAP key | | ASC_IAP_PRIVATE_KEY_PATH | Path to the IAP signing .p8 (~ is expanded) |
The server starts fine without these — only the asc_sign_* tools refuse with a setup message if they're missing. Set one or two but not all three and the server rejects with a clear error. Run appstoreconnect-mcp doctor to verify the key loads as a valid ES256 PKCS#8.
Optional: vendor number (sales + finance reports)
Only used by asc_get_sales_report / asc_get_finance_report. Your vendor number is account-level, shown at App Store Connect → Payments and Financial Reports next to your team name (a numeric string like 85123456).
| Variable | What | | --- | --- | | ASC_VENDOR_NUMBER | Default vendor number for sales/finance report downloads |
Without it the two report tools still work — they just need vendorNumber passed per call (and their error message tells you where to find it). Note: downloading sales/finance reports requires an API key with the Admin, Finance, or Sales role.
Tools
Apps
asc_list_apps— list apps (filter bybundleId)asc_get_app— fetch one app by ID
Subscriptions
asc_list_subscription_groups— groups for an appasc_list_subscriptions— auto-renewable subscriptions in a groupasc_list_subscription_prices— current price schedule per subscriptionasc_list_subscription_price_points— valid price points for a subscription in a territory. PassnearAmountto narrow the response to the nearest tiers around a target price.
Subscription pricing (writes)
asc_post_subscription_price— schedule a price change for one territoryasc_delete_subscription_price— cancel a pending scheduled change
App pricing (paid non-subscription apps)
asc_list_app_prices— current price schedule for an app, splitting manual overrides from auto-derived prices and surfacing the base territoryasc_list_app_price_points— valid Apple price tiers for an app in a given territory (~600+ tiers per territory). PassnearAmount(target price) and optionalnearCount(default 10) to narrow the response to the nearest tiers — Apple does not support a near-amount filter server-side, so the full list is still paginated but only the nearest tiers are surfaced.asc_post_app_price_schedule— replace the entire price schedule (whole-schedule replace, NOT a merge — matches Apple's API). Pre-flight refuses unless at least one entry targets the base territory with nostartDate, and requires explicitacknowledgeReplacesAll: true. A separateacknowledgeDeletesScheduledIfBaseChangesack is required when changing the base territory (Apple wipes pending scheduled changes on base-change). Apps have no grandfather mechanism — new schedules activate atomically at each entry'sstartDate.
In-app purchases (consumables, non-consumables, non-renewing subs)
asc_list_iaps— list IAPs for an app (v2 surface only — auto-renewable subscriptions are covered by the Subscriptions tools above). Filterable byinAppPurchaseTypeandstate. If this returns zero rows for an app you know has IAPs, the IAPs may be legacy-only and need to be migrated in the App Store Connect web UI before they appear here.asc_get_iap— fetch a single IAP by ID.asc_list_iap_prices— current price schedule for an IAP (same shape as app prices: manual overrides + auto-derived + base territory).asc_list_iap_price_points— valid Apple price tiers for an IAP in a given territory. SamenearAmount/nearCountnarrowing as the app and subscription price-point tools.asc_post_iap_price_schedule— replace the entire IAP price schedule (same whole-schedule replace semantics asasc_post_app_price_schedule:acknowledgeReplacesAll: true, base-territory entry with nostartDate, base-change ack required). No grandfather mechanism — same as apps.
Subscription introductory offers
Introductory offers target new subscribers — the discounted "first window" before the regular price kicks in.
asc_list_subscription_introductory_offers— list intro offers (free trial / pay-as-you-go / pay-up-front) configured for a subscription, across territories. Apple's "all territories" wildcard (a single offer with noterritory) surfaces asTERR=(all)in the table.asc_get_subscription_introductory_offer— fetch one offer by ID.asc_post_subscription_introductory_offer— create an offer. ThreeofferModes:FREE_TRIAL(no price; omitpricePointId),PAY_AS_YOU_GO(charge the offer price each period fornumberOfPeriodsperiods),PAY_UP_FRONT(single charge for the whole duration). PassterritoryIdto target one market, or omit it for Apple's "all territories" wildcard (uses the literal price point in every market — no auto-FX). Server-side validation refusesPAY_*withoutpricePointId,PAY_AS_YOU_GOwithoutnumberOfPeriods, andendDate ≤ startDate— Apple's error is surfaced inline otherwise.asc_patch_subscription_introductory_offer— narrow update path: onlystartDate,endDate, andpricePointIdcan change after creation. To change mode / duration / periods, delete and re-create.asc_delete_subscription_introductory_offer— delete a pending or active offer. Apple refuses to delete one that is currently redeemable; PATCHendDateto today to stop it instead.
Subscription promotional offers
Promotional offers target existing or lapsed subscribers — opposite eligibility from intro offers, set by the resource type itself (no per-offer flag). Apple caps active promo offers at 10 per subscription. After creation, only the per-territory prices can be edited — name, offerCode, offerMode, duration, and numberOfPeriods are immutable.
asc_list_subscription_promotional_offers— list promo offers configured for a subscription.asc_get_subscription_promotional_offer— fetch a single offer, including its per-territory prices.asc_list_subscription_promotional_offer_prices— list per-territory price rows attached to an offer (territory + currency + amount + price-point ID).asc_post_subscription_promotional_offer— create an offer (name+offerCode+ mode + duration + all per-territory prices) in one atomic POST. Pre-flights Apple's 10-offer cap andofferCodecollisions, refusing with a clear remedy message instead of letting Apple 409.asc_patch_subscription_promotional_offer_prices— update the offer's per-territory prices. Apple's wire semantic is replace (the new prices array becomes the post-state, dropping any territory not listed); the tool'smode: 'replace' | 'add' | 'remove'parameter hides the footgun —'add'reads current prices and merges,'remove'reads and filters.asc_delete_subscription_promotional_offer— DELETE → 204.
Subscription offer signing (in-app redemption)
The cryptographic signer that makes promo/intro offers redeemable in your iOS app via StoreKit. Uses a separate signing key from the ASC API key — issued at App Store Connect → Users and Access → Integrations → In-App Purchase. See the [optional config section](#optional-in-app-purchase-signing-key) for env vars. Built on Apple's official @apple/app-store-server-library.
asc_sign_promotional_offer_legacy— legacy ECDSA-concatenated signature used by StoreKit 1'sSKPaymentDiscountand the original StoreKit 2Product.PurchaseOption.promotionalOffer(offerID:keyID:nonce:signature:timestamp:)API. Returns the base64 signature plus the nonce, timestamp, and keyId for the caller to pass to StoreKit. Auto-generates a UUID nonce and current timestamp; both overridable for testing.asc_sign_promotional_offer— JWS v2 format introduced at WWDC 2025 (back-deployed to iOS 15). Use with StoreKit 2's newer promotional-offer purchase options. Returns the JWS compact serialization directly.transactionId(the customer'sappTransactionId) is optional but strongly recommended.asc_sign_introductory_offer_eligibility— JWS v2 withaud="introductory-offer-eligibility". Lets you override StoreKit's default introductory-offer eligibility check (e.g. grant a returning customer another trial). New in WWDC 2025.
All signatures are valid for 24 hours from signing time — re-sign per redemption attempt rather than pre-signing and caching.
Territories
asc_list_territories— all 175 App Store territories
PPP rebalancing
ppp_load_index— return the bundled Apple Music Individual-plan price snapshot used as the PPP signalppp_compute_proposal— compute a proposed per-territory price schedule (read-only dry-run; uses Apple Music ratios as implied PPP-FX, snaps to valid Apple price points, applies a configurable round strategy and floor). PassresourceType: "subscription"(default) withsubscriptionId,resourceType: "app"withappIdfor paid apps,resourceType: "iap"withiapId,resourceType: "introductoryOffer"withsubscriptionIdplusofferMode/duration(andnumberOfPeriodsforPAY_AS_YOU_GO), orresourceType: "promotionalOffer"withsubscriptionIdplusofferMode/duration/promoOfferName/promoOfferCode(andnumberOfPeriodsforPAY_AS_YOU_GO).ppp_apply_proposal— recompute and apply the proposal against ASC after confirming via MCP elicitation (orconfirm: truefor unattended use). Refuses if any row drops by more thanmaxDropPct(default 90%); skips territories where ASC billing currency ≠ Apple Music currency.- For subscriptions: per-territory
subscriptionPricesPOSTs, paced atmaxConcurrency(default 2), retrying 429s automatically; existing subscribers grandfathered whenpreserveCurrentPrice: true(default). - For apps and IAPs: a single whole-schedule-replace POST (one HTTP call, atomic). Apps/IAPs have no grandfather mechanism — new prices activate at each entry's
startDate. RequiresacknowledgeDeletesScheduledIfBaseChanges: truewhen changing the base territory (Apple wipes pending scheduled changes on base-change). - For introductory offers: per-territory
subscriptionIntroductoryOffersPOSTs, paced atmaxConcurrency. The Δ column compares the snapped offer price against the current regular sub price in that territory, so-50%means the offer is half off the sub.FREE_TRIALis rejected (no price to compute — useasc_post_subscription_introductory_offerwithterritoryIdomitted for a single global free trial). Intro offers are additions, not replacements — Apple returns 409 if an active offer already exists for a(sub, territory)cell, and those rows show asfailedin the result table. - For promotional offers: one atomic POST to
/v1/subscriptionPromotionalOfferscreates the offer + all per-territory PPP-snapped prices in a single request. Create-only — refuses ifofferCodecollides with an existing offer or the sub is at Apple's 10-offer cap.FREE_TRIALrejected (no price to compute). Same Δ-vs-current-sub-price reporting as intro offers.
Response shape
Every list/get tool returns a compact text table by default — designed for an LLM to read without burning context. Every tool also accepts:
raw: true— return the full JSON:API payload (data,included,links,meta) for debugging or advanced use.maxItems: number— cap auto-pagination (default 500–1000 depending on the tool). The MCP followslinks.nextand merges + dedupesincludedresources across pages.
Sparse fieldsets (fields[type]=...) are applied per tool to avoid pulling unused attributes. The whole 175-territory price schedule comes back in one paginated call (200/page) at roughly 1/10th the size of the unfiltered payload.
Production behavior
A few details worth knowing before running ppp_apply_proposal against a live App Store Connect account:
- Rate limit handling. Apple throttles POST endpoints around 50/min.
client.requesthonoursRetry-Afterheaders and falls back to exponential backoff (2s → 60s, capped, up to 6 retries). A 60-territory rebalance pacing through retries finishes in about 2 minutes wall time with zero manual intervention. - Currency-mismatch skip. If the bundled Apple Music index lists a territory in one currency (say BHD) but ASC bills your subscription in another (USD), the PPP-FX ratio breaks dimensionally. The proposal marks those rows
currency-mismatch (asc=USD, am=BHD)and excludes them from the apply set. Common in Gulf USD-billed markets (BHR, KWT, OMN). Set those manually if you want to. - Sanity floor.
floorFactor(
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: akoskomuves
- Source: akoskomuves/appstoreconnect-mcp
- License: MIT
- Homepage: https://www.npmjs.com/package/@akoskomuves/appstoreconnect-mcp
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.