asc-mcp
v1.0.4
Published
MCP server for Apple's App Store Connect API - manage iOS, macOS, tvOS, and visionOS apps with AI
Maintainers
Readme
App Store Connect MCP Server
A Model Context Protocol (MCP) server for Apple's App Store Connect API. Manage your iOS, macOS, tvOS, and visionOS apps directly from Claude, Cursor, or any MCP-compatible client.
Features
- App Store Localizations - Full CRUD for version descriptions, keywords, and what's new
- App Management - List and inspect apps across all platforms
- Version Control - Create and manage app store versions
- Beta Testing - Manage TestFlight groups and testers
- Screenshot Management - Upload and organize app screenshots
- Bundle ID Management - Full CRUD for bundle identifiers
- Device Management - List and inspect registered devices
- User Management - List and inspect team users
- Build Management - List and inspect app builds
- Category & Pricing - Browse categories, check pricing and availability
- Secure by Default - ES256 JWT auth with automatic token refresh, credential redaction in logs
Table of Contents
- Quick Start
- Installation
- Configuration
- Available Tools
- Usage Examples
- Security
- Troubleshooting
- Development
- License
Quick Start
# 1. Install
npm install -g asc-mcp
# 2. Set credentials (get from App Store Connect > Users and Access > Keys)
export APP_STORE_CONNECT_KEY_ID="YOUR_KEY_ID"
export APP_STORE_CONNECT_ISSUER_ID="YOUR_ISSUER_ID"
export APP_STORE_CONNECT_P8_PATH="/path/to/AuthKey.p8"
# 3. Add to your MCP client config and start using!Installation
npm (recommended)
npm install -g asc-mcpUsing npx
npx asc-mcpFrom Source
git clone https://github.com/SardorbekR/appstore-connect-mcp.git
cd appstore-connect-mcp
npm install
npm run buildConfiguration
Prerequisites: Get Your Apple API Credentials
- Sign in to App Store Connect
- Go to Users and Access → Integrations → App Store Connect API
- Click Generate API Key (or use existing)
- Select appropriate role (Admin or App Manager recommended)
- Download the .p8 file - you can only download it once!
- Note your Key ID (shown in the keys list)
- Note your Issuer ID (shown at the top of the page)
Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| APP_STORE_CONNECT_KEY_ID | Yes | Your API Key ID (e.g., ABC123DEFG) |
| APP_STORE_CONNECT_ISSUER_ID | Yes | Your Issuer ID (UUID format) |
| APP_STORE_CONNECT_P8_PATH | Yes* | Path to your .p8 private key file |
| APP_STORE_CONNECT_P8_CONTENT | Yes* | Raw content of .p8 key (alternative to path) |
*One of P8_PATH or P8_CONTENT is required.
MCP Client Configuration
Add to your Claude Desktop config file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"app-store-connect": {
"command": "asc-mcp",
"env": {
"APP_STORE_CONNECT_KEY_ID": "YOUR_KEY_ID",
"APP_STORE_CONNECT_ISSUER_ID": "YOUR_ISSUER_ID",
"APP_STORE_CONNECT_P8_PATH": "/absolute/path/to/AuthKey.p8"
}
}
}
}Add to your Cursor MCP settings (Settings → MCP Servers):
{
"mcpServers": {
"app-store-connect": {
"command": "npx",
"args": ["-y", "asc-mcp"],
"env": {
"APP_STORE_CONNECT_KEY_ID": "YOUR_KEY_ID",
"APP_STORE_CONNECT_ISSUER_ID": "YOUR_ISSUER_ID",
"APP_STORE_CONNECT_P8_PATH": "/absolute/path/to/AuthKey.p8"
}
}
}
}Add to your Continue configuration:
{
"mcpServers": {
"app-store-connect": {
"command": "asc-mcp",
"env": {
"APP_STORE_CONNECT_KEY_ID": "YOUR_KEY_ID",
"APP_STORE_CONNECT_ISSUER_ID": "YOUR_ISSUER_ID",
"APP_STORE_CONNECT_P8_PATH": "/absolute/path/to/AuthKey.p8"
}
}
}
}For CI/CD or containerized environments, you can pass the key content directly:
{
"mcpServers": {
"app-store-connect": {
"command": "asc-mcp",
"env": {
"APP_STORE_CONNECT_KEY_ID": "YOUR_KEY_ID",
"APP_STORE_CONNECT_ISSUER_ID": "YOUR_ISSUER_ID",
"APP_STORE_CONNECT_P8_CONTENT": "-----BEGIN PRIVATE KEY-----\nMIGT...your key here...AB12\n-----END PRIVATE KEY-----"
}
}
}
}Available Tools
Apps
| Tool | Description | Parameters |
|------|-------------|------------|
| list_apps | List all apps in your account | limit? (number, 1-200) |
| get_app | Get details of a specific app | appId (string, required) |
Versions
| Tool | Description | Parameters |
|------|-------------|------------|
| list_app_versions | List all versions for an app | appId, platform?, versionState?, limit? |
| get_app_version | Get version details | versionId |
| create_app_version | Create a new app version | appId, platform, versionString, releaseType? |
Version Localizations
| Tool | Description | Parameters |
|------|-------------|------------|
| list_version_localizations | List localizations for a version | versionId, limit? |
| get_version_localization | Get localization details | localizationId |
| create_version_localization | Add a new locale | versionId, locale, description?, keywords?, whatsNew? |
| update_version_localization | Update localization | localizationId, description?, keywords?, whatsNew?, promotionalText? |
| delete_version_localization | Remove a locale | localizationId |
App Info Localizations
| Tool | Description | Parameters |
|------|-------------|------------|
| list_app_infos | List app info records | appId, limit? |
| list_app_info_localizations | List name/subtitle localizations | appInfoId, limit? |
| update_app_info_localization | Update app name, subtitle | localizationId, name?, subtitle?, privacyPolicyUrl? |
Beta Testing (TestFlight)
| Tool | Description | Parameters |
|------|-------------|------------|
| list_beta_groups | List beta groups for an app | appId, limit? |
| list_beta_testers | List testers in a group | betaGroupId, limit? |
| add_beta_tester | Add a tester to a group | betaGroupId, email, firstName?, lastName? |
| remove_beta_tester | Remove a tester from a group | betaGroupId, betaTesterId |
Screenshots
| Tool | Description | Parameters |
|------|-------------|------------|
| list_screenshot_sets | List screenshot sets | localizationId, limit? |
| list_screenshots | List screenshots in a set | screenshotSetId, limit? |
| upload_screenshot | Upload a new screenshot | screenshotSetId, fileName, fileSize, filePath |
Bundle IDs
| Tool | Description | Parameters |
|------|-------------|------------|
| list_bundle_ids | List all bundle IDs | limit?, platform? |
| get_bundle_id | Get bundle ID details | bundleIdId |
| create_bundle_id | Register a new bundle ID | identifier, name, platform |
| update_bundle_id | Update bundle ID name | bundleIdId, name |
| delete_bundle_id | Delete a bundle ID | bundleIdId |
Devices
| Tool | Description | Parameters |
|------|-------------|------------|
| list_devices | List registered devices | limit?, platform?, status? |
| get_device | Get device details | deviceId |
Users
| Tool | Description | Parameters |
|------|-------------|------------|
| list_users | List team users | limit?, roles? |
| get_user | Get user details | userId |
Builds
| Tool | Description | Parameters |
|------|-------------|------------|
| list_builds | List builds for an app | appId, limit? |
| get_build | Get build details | buildId |
Categories & Pricing
| Tool | Description | Parameters |
|------|-------------|------------|
| list_app_categories | List app categories | limit?, platform? |
| get_app_price_schedule | Get app pricing info | appId |
| get_app_availability | Get app territory availability | appId |
Usage Examples
List Your Apps
"Show me all my apps in App Store Connect"
Claude will use list_apps to retrieve and display your apps.
Update App Description
"Update the English description for version 2.0 of MyApp to: 'A revolutionary app that simplifies your daily tasks.'"
Claude will:
- Find the app using
list_apps - Get the version using
list_app_versions - Find the English localization using
list_version_localizations - Update it using
update_version_localization
Add Japanese Localization
"Add Japanese localization to MyApp version 2.0 with description '素晴らしいアプリです' and keywords 'アプリ,便利,簡単'"
Claude will use create_version_localization with locale ja.
Add a Beta Tester
"Add [email protected] as a beta tester to the Internal Testing group for MyApp"
Claude will:
- Find the app and beta group using
list_beta_groups - Add the tester using
add_beta_tester
Check Version Status
"What's the status of all versions of MyApp?"
Claude will use list_app_versions to show version states (PREPARE_FOR_SUBMISSION, IN_REVIEW, READY_FOR_SALE, etc.)
Security
Credential Handling
- Private keys are never logged or exposed in error messages
- JWT tokens are automatically redacted from any error output
- Issuer IDs (UUIDs) are redacted from logs
- Token caching minimizes key usage (15-min tokens, refreshed at 10 min)
Path Validation
- P8 file paths are validated against directory traversal attacks (
..not allowed) - Only absolute paths are resolved
Best Practices
- Never commit credentials - Use environment variables or a secrets manager
- Restrict API key permissions - Use minimal required role (App Manager for most operations)
- Rotate keys periodically - Generate new API keys and revoke old ones
- Secure your .p8 file - Set file permissions to
600(owner read/write only)
chmod 600 /path/to/AuthKey.p8Troubleshooting
"Configuration error: APP_STORE_CONNECT_KEY_ID environment variable is required"
Ensure all required environment variables are set:
APP_STORE_CONNECT_KEY_IDAPP_STORE_CONNECT_ISSUER_IDAPP_STORE_CONNECT_P8_PATHorAPP_STORE_CONNECT_P8_CONTENT
"Failed to read private key"
- Verify the path in
APP_STORE_CONNECT_P8_PATHis correct and absolute - Check file permissions:
ls -la /path/to/AuthKey.p8 - Ensure the file is a valid
.p8from Apple (starts with-----BEGIN PRIVATE KEY-----)
"Authentication failed"
This usually means:
- The API key was revoked in App Store Connect
- The Key ID or Issuer ID doesn't match the .p8 file
- The .p8 file is corrupted or incomplete
"Rate limit exceeded"
The server includes built-in rate limiting (50 requests/minute). If you hit Apple's limits:
- Wait for the indicated retry time
- Batch your operations when possible
- The server automatically retries with exponential backoff
Tools Not Appearing in Claude
- Verify the server is running: check Claude Desktop logs
- Ensure the config file path is correct for your OS
- Restart Claude Desktop after config changes
Development
Prerequisites
- Node.js 20+
- npm or pnpm
Setup
# Clone the repository
git clone https://github.com/SardorbekR/appstore-connect-mcp.git
cd appstore-connect-mcp
# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Lint
npm run lint
# Type check
npm run typecheckProject Structure
src/
├── index.ts # MCP server entry point
├── auth/
│ └── jwt.ts # JWT token generation & caching
├── api/
│ ├── client.ts # HTTP client with retry logic
│ └── types.ts # TypeScript interfaces
├── tools/
│ ├── index.ts # Tool registry
│ ├── apps.tools.ts
│ ├── versions.tools.ts
│ ├── localizations.tools.ts
│ ├── app-info.tools.ts
│ ├── beta.tools.ts
│ ├── screenshots.tools.ts
│ ├── bundle-ids.tools.ts
│ ├── devices.tools.ts
│ ├── users.tools.ts
│ ├── builds.tools.ts
│ └── categories.tools.ts
└── utils/
├── errors.ts # Error classes with redaction
└── validation.ts # Zod schemasRunning Locally
# Development mode with auto-reload
npm run dev
# Or run the built version
npm startContributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes and add tests
- Run
npm testandnpm run lint - Submit a pull request
License
MIT License - see LICENSE for details.
