Skip to main content
Glama

App Store Connect MCP

An MCP server for Apple's App Store Connect API. It lets Claude, Claude Code and other AI agents work with your apps' metadata, App Store versions and review submissions, builds and TestFlight, customer reviews, sales and finance reports, Xcode Cloud, devices and team members.

  • 36 tools. Task-shaped tools cover the common workflows. Three generic tools (search_endpoints, describe_endpoint, api_request) reach the rest of Apple's 1,300+ endpoints through the bundled OpenAPI spec.

  • Runs locally with npx. Your private key stays on your machine and is only used to sign short-lived tokens for api.appstoreconnect.apple.com.

  • Optional read-only mode hides every tool that changes data.

Requirements

  • Node.js 24 or later

  • An App Store Connect team API key

Related MCP server: appstore-connect-mcp

Create an API key

  1. In App Store Connect, go to Users and Access → Integrations → App Store Connect API.

  2. Click Generate API Key (or +). Give it a name and pick a role:

    • App Manager covers most tools: metadata, versions, TestFlight, reviews and Xcode Cloud.

    • Reports need a role with report access: Sales or Finance for get_sales_report, Finance for get_finance_report.

    • If a tool returns a 403 error, the key's role doesn't allow that request.

  3. Download the AuthKey_XXXXXXXXXX.p8 file. Apple only lets you download it once.

  4. Note the Key ID (shown next to the key) and the Issuer ID (shown above the list of keys).

Set up

The server reads three environment variables:

Variable

Value

APP_STORE_CONNECT_ISSUER_ID

Your Issuer ID, e.g. 57246542-96fe-1a63-e053-0824d011072a

APP_STORE_CONNECT_KEY_ID

Your Key ID, e.g. 2X9R4HXF34

APP_STORE_CONNECT_PRIVATE_KEY

The contents of the .p8 file, as text

APP_STORE_CONNECT_READ_ONLY

Optional. true hides all write tools

The private key can be pasted as a normal multi-line PEM, as a single line with \n escapes (as JSON configs need), or as just the base64 body without the BEGIN/END lines.

Claude Code

claude mcp add app-store-connect --scope user \
  -e APP_STORE_CONNECT_ISSUER_ID=your-issuer-id \
  -e APP_STORE_CONNECT_KEY_ID=your-key-id \
  -e APP_STORE_CONNECT_PRIVATE_KEY="$(cat ~/Downloads/AuthKey_XXXXXXXXXX.p8)" \
  -- npx -y @octopusthink/app-store-connect-mcp

Leave out --scope user to add it to the current project only. Run /mcp inside Claude Code to check it connected.

Claude Desktop

Open Settings → Developer → Edit Config and add the server to claude_desktop_config.json:

{
  "mcpServers": {
    "app-store-connect": {
      "command": "npx",
      "args": ["-y", "@octopusthink/app-store-connect-mcp"],
      "env": {
        "APP_STORE_CONNECT_ISSUER_ID": "your-issuer-id",
        "APP_STORE_CONNECT_KEY_ID": "your-key-id",
        "APP_STORE_CONNECT_PRIVATE_KEY": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49...\n-----END PRIVATE KEY-----"
      }
    }
  }
}

JSON strings can't contain real line breaks, so the key's newlines become \n. This command prints your key in that form:

awk 'NF { sub(/\r/, ""); printf "%s\\n", $0 }' ~/Downloads/AuthKey_XXXXXXXXXX.p8

Restart Claude Desktop after saving.

Other MCP clients

Run npx -y @octopusthink/app-store-connect-mcp as a stdio server with the environment variables above.

What you can ask

  • "Which of my apps have a version waiting for review?"

  • "Show me this week's 1- and 2-star reviews for Example and draft replies."

  • "Create version 2.1 of Example, use the latest build, and set the release notes to …"

  • "Add build 2.1 (57) to the Beta Testers group and set the test notes."

  • "Invite sam@example.com to the Internal QA TestFlight group."

  • "How many units did we sell yesterday?" (needs your vendor number)

  • "Start an Xcode Cloud build of the Release workflow on main."

  • "Set up a phased release for the current version." (through api_request)

Tools

Tools marked ✏️ change data. They are annotated as such, so MCP clients can ask you before running them.

Apps: list_apps, get_app

App Store versions and metadata

  • list_app_store_versions, list_version_localizations, list_app_info_localizations

  • ✏️ create_app_store_version: new version for a platform

  • ✏️ update_version_localization: description, keywords, what's new, promotional text, URLs (adds the locale if missing)

  • ✏️ update_app_info_localization: name, subtitle, privacy URLs

  • ✏️ select_build_for_version: attach a build

  • ✏️ submit_for_review: submit to App Review

Builds and TestFlight

  • list_builds, get_build, list_beta_groups, list_beta_testers

  • ✏️ add_build_to_beta_groups, set_build_test_notes, submit_build_for_beta_review

  • ✏️ invite_beta_tester, remove_beta_tester_from_groups

Customer reviews

  • list_customer_reviews, including any response already posted

  • ✏️ respond_to_review, delete_review_response

Reports: get_sales_report, get_finance_report

Xcode Cloud

  • list_ci_products, list_ci_workflows, list_ci_build_runs, get_ci_build_run

  • ✏️ start_ci_build

Provisioning and team

  • list_bundle_ids, list_devices, list_users

  • ✏️ register_device

Everything else

  • search_endpoints: keyword search over every endpoint in Apple's OpenAPI spec

  • describe_endpoint: parameters, allowed values and the full request body schema for one endpoint

  • ✏️ api_request: call any endpoint, with optional pagination. GET only in read-only mode.

List tools return a nextCursor when there are more results; pass it back as cursor to get the next page. Responses are flattened from Apple's JSON:API format to save tokens.

Read-only mode

Set APP_STORE_CONNECT_READ_ONLY=true to remove every write tool and limit api_request to GET requests. This mode is enforced by the server. App Store Connect itself enforces only the key's role, so also give the key the narrowest role that covers what you need.

Security

  • The private key is read from the environment and never logged or returned by any tool.

  • Tokens are signed locally (ES256, 19-minute lifetime) and only sent to https://api.appstoreconnect.apple.com. The server refuses requests to any other host, including pagination URLs passed in by the model.

  • Write tools carry MCP annotations (readOnlyHint: false, plus destructiveHint for deletions and submissions) so clients can ask for confirmation.

  • Use the narrowest role that covers what you need, and revoke the key in App Store Connect if it leaks.

Development

npm install
npm test            # unit tests and a stdio end-to-end test
npm run lint        # Biome
npm run typecheck   # TypeScript 7
npm run build       # compiles to dist/
npm run inspect     # opens the MCP Inspector against the built server
npm run dev         # runs src/index.ts directly with Node's type stripping

npm run update-spec downloads the latest App Store Connect OpenAPI spec from Apple into spec/openapi.json.gz, which search_endpoints and describe_endpoint read.

The code is organized as follows:

  • src/config.ts: environment variables and private key parsing

  • src/auth.ts: JWT signing

  • src/client.ts: the HTTP client, with retries, errors, pagination and gzip reports

  • src/format.ts: JSON:API flattening

  • src/spec.ts: endpoint search and description over the bundled spec

  • src/tools/: one file per area, all registered in src/tools/index.ts

To add a tool, define it with defineTool in the relevant file and add it to that file's exported list. Set write: true for anything that changes data.

Releasing

Pushing a version tag such as 1.2.3 (no v prefix) runs .github/workflows/release.yml, which runs the full CI checks, confirms the tag matches the package.json version, and publishes to npm. Versions with a prerelease suffix, such as 1.3.0-beta.1, are published under the next dist-tag, so npx users stay on the latest stable release.

The workflow uses npm trusted publishing: npm accepts GitHub's short-lived OIDC token from this workflow, so no npm token is stored in GitHub.

One-time setup

  1. Publish the first version by hand. Trusted publishing is configured per package, so the package has to exist on npm first. From a clean checkout of the version you want to release, run:

    npm login
    npm publish

    npm publish runs the lint, typecheck, tests and build first. package.json already sets "access": "public" for the scoped package. Don't push a tag for this version: the workflow would try to publish it again, and npm rejects duplicate versions.

  2. Add the trusted publisher. On npmjs.com, open the package's Settings → Trusted publishing, choose GitHub Actions, and enter:

    • Organization: octopusthink

    • Repository: app-store-connect-mcp

    • Workflow filename: release.yml

    • Environment: npm

  3. Optional: lock it down.

    • In the package's Settings → Publishing access on npm, choose Require two-factor authentication and disallow tokens. The workflow keeps working, because it doesn't use a token.

    • In this repository's Settings → Environments → npm on GitHub, add required reviewers so every release waits for approval.

Provenance attestations are only generated for public repositories. They'll start appearing automatically if this repository is made public.

Each release

npm version patch   # or minor, major, prerelease --preid beta
git push --follow-tags

npm version bumps package.json, commits, and creates the matching tag, such as 1.2.4. The project's .npmrc sets tag-version-prefix="", so npm doesn't add its usual v. Pushing the tag starts the release.

License

MIT

Related MCP Connectors

Related MCP Servers