App Store Connect MCP server for Claude Code, Claude Desktop and Cursor. 1,293 App Store Connect and StoreKit 2 (App Store Server API) operations behind 13 tools, with macOS Keychain credentials, Apple JWS signature verification and risk-tiered write confirmation.
Strong tool design with excellent descriptions (avg 180 chars, well above baseline 72 chars minimum). All 13 tools have clear, actionable descriptions explaining WHAT, WHEN, and WHY. Input schemas present for all tools with proper type definitions. Naming follows verb_noun convention (asc_status, asc_search_endpoints, asc_call, asc_write). Key strengths: parameter descriptions are detailed with format guidance (e.g., 'ISO alpha-3' for territories); error recovery hints embedded ('Run this first when anything fails'); risk tier documentation. Gaps: output schemas not formally documented in tool definitions (only inferred from descriptions); some parameters lack explicit constraints (e.g., limit defaults and caps mentioned in description but not in schema); no dry-run/confirmation pattern visible in asc_call despite write risk.
Fetch an analytics report as rows. Walks request → report → instance → every segment, downloads the signed URLs, gunzips the TSV and returns parsed rows. Reading only the first segment — the obvious mistake — yields a plausible subset with nothing marking it partial. Call without report_name to list what exists. Never creates a report request: accessType ONGOING is a standing commitment on the account, not a query.
Turn an app's App Store availability on or off, territory by territory. Apple offers no bulk endpoint — appAvailabilities answers 403 "does not allow UPDATE" once the record exists — so this is one PATCH per territory, up to 175 of them. Territories already in the target state are skipped, a failure part-way does not abandon the rest, and every territory is re-read afterwards and compared against the request, because a loop that finishes is not evidence that the store matches what was asked for. Cannot set availableInNewTerritories: that is web-UI only.
Read from Apple's APIs: App Store Connect or App Store Server (StoreKit 2). Dispatch by operationId; every parameter is optional unless the API requires it. Returns the response body, or a list of paginated results.
Full detail for one operation: every parameter, the request body schema with real field names, and its risk tier. Call this before any write.
Output schemas not formally documented in tool definitions. Descriptions mention return structure (e.g., 'returns GO or NO-GO', 'returns parsed rows') but no explicit JSON Schema for response objects. LLMs cannot reliably plan downstream tool calls without knowing response field names and types.
Parameter constraints (limit caps, enum values) documented in descriptions but not in JSON Schema. 'limit caps at 200' and 'Territories are ISO alpha-3' are text hints, not machine-parseable constraints. LLMs may pass invalid values (e.g., limit=500) and require error recovery.
asc_write lacks explicit confirmation/dry-run pattern despite WRITE risk tier. Description mentions 'gated by risk tier and require confirmation' but no dry_run parameter visible in schema. asc_upload_screenshot and asc_upload_iap_screenshot offer dry_run, but asc_write does not, inconsistent safety posture.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 61 | 2026-07-28+ | v2 |
List the screenshot sets and screenshots on a version, with each asset's delivery state. Uses included resources to turn what is otherwise a request per locale per set into a handful.
Answer "can this version actually be submitted?" across build state, export compliance, every localisation, screenshots, review contact details and any open submission. Returns GO or NO-GO with each gap naming the operation that fixes it. Catches the states that stall a release without explaining themselves — a build still PROCESSING, or an unanswered export-compliance question that parks the version at WAITING_FOR_EXPORT_COMPLIANCE.
Read subscription pricing across every territory for an app, with the currency resolved and territories grouped by price so outliers stand out. Collapses a four-hop walk and ~175 lookups into a handful of requests. The currency lives on the territory, not the price row, which is why reading prices by hand tends to produce ambiguous numbers.
Change a subscription price. `preserve_current_price` is required and has no default: true keeps existing subscribers on what they pay now, false moves them at their next renewal. Apple defaults it to false, so leaving it implicit silently re-prices your existing base. Find a price point id with asc_call subscriptions_pricePoints_getToManyRelated.
Find operations across the App Store Connect API and the App Store Server API / StoreKit 2. Search by keyword, method, tag or risk tier; returns operationIds for asc_call and asc_write. Start here rather than guessing a path — some resources are not where the URL pattern implies.
Verify credentials and report what this server can reach, including the remaining rate-limit budget. Run this first when anything fails — it distinguishes a bad key from a bad request.
Upload the App Store review screenshot for an in-app purchase, performing Apple's reserve → upload → commit sequence. This is a different resource from a listing screenshot and is the usual reason an in-app purchase stays in MISSING_METADATA when everything else about it is complete — it is the one required field with no text to type. Apple rejects non-standard aspect ratios: a window capture at 1706x1610 fails IMAGE_BAD_ASPECT_RATIO, while 2880x1800 passes. Validation is asynchronous, so a rejected image commits cleanly and only then reports FAILED.
Upload a screenshot image, performing Apple's full reserve → upload → commit sequence: reserve a slot, PUT each byte range to Apple's asset host with the headers Apple supplies, then commit with an MD5 checksum. The raw API cannot do this in one call, and a wrong checksum or offset does not error — it leaves the asset stuck, which looks like nothing happened.
Write to Apple's APIs: create, update or delete. Dispatch by operationId; every parameter is optional unless the API requires it. Writes are gated by risk tier and require confirmation unless --no-confirm was passed.
Error handling guidance not visible in tool definitions. Descriptions mention 'Run this first when anything fails' (asc_status) but no structured error response schema or recovery hints (e.g., 'If not found, try search_*'). LLMs lack actionable error recovery paths.
Natural identifier resolution (bundle ID, store name, numeric Apple ID) documented in descriptions but implementation details hidden. asc_pricing_get accepts 'Bundle ID, store name, or numeric Apple ID' but no schema shows how to pass these or what happens on ambiguity. LLMs cannot predict resolution order or fallback behavior.