App Store Connect MCP
App Store Connect MCP
Node.js and TypeScript MCP server for App Store Connect. It supports multiple Apple accounts and can run either as a self-hosted remote MCP gateway or as a local npx stdio MCP server.
Features
Multiple named App Store Connect accounts
Account-prefixed MCP tools, so one server can expose several Apple accounts safely
ES256 App Store Connect JWT generation and caching
Remote Streamable HTTP MCP endpoint at
/mcpBearer-token protection for remote HTTP mode
Local stdio mode for
npxusageDockerfile and Docker Compose support
Secret-safe logging and responses
Zod validation for account configuration and tool inputs
Modes
Mode | Best For | Credentials Location | MCP Transport |
Remote HTTP gateway | Teams, shared servers, centralized access | Mounted server-side JSON file | Streamable HTTP |
Local stdio package | Individual developers or local automation | MCP client environment variable | stdio |
Use remote HTTP mode when developers should not receive Apple private keys. Use local stdio mode only when the machine running the MCP client is allowed to hold Apple credentials.
Architecture
Remote HTTP mode:
MCP Client
|
| HTTPS /mcp
| Authorization: Bearer server-token
v
App Store Connect MCP Gateway
|
| ES256 Apple JWT
v
App Store Connect APILocal stdio mode:
MCP Client
|
| npx @kaisar/mcp-appstore-connect
| APPLE_ACCOUNTS=base64-json
v
Local MCP Server
|
| ES256 Apple JWT
v
App Store Connect APIApple Account Configuration
Create an apple_accounts.json file:
[
{
"id": "production",
"keyId": "ABC123DEFG",
"issuerId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
"vendorNumber": "12345678"
},
{
"id": "client_a",
"keyId": "XYZ123DEFG",
"issuerId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
}
]Fields:
id: local account name used to generate MCP tool prefixeskeyId: App Store Connect API key IDissuerId: App Store Connect issuer IDprivateKey:.p8private key content, with newlines preserved or escaped as\nvendorNumber: optional Sales and Trends vendor number
The config does not support defaultBundleId or defaultAppStoreId. Pass app IDs explicitly to tools.
Account IDs can contain spaces or symbols. Tool prefixes are generated by lowercasing the account ID and replacing unsafe characters with _. Prefixes must be unique.
Example:
"Client A" -> client_a
"Production" -> productionTool Names
The server exposes one set of tools per account. Tool names use:
account_prefix__tool_nameExamples:
production__list_apps
production__get_builds
production__get_sales_data
client_a__list_beta_groups
client_a__get_customer_reviewsThe server also exposes:
list_gateway_accountsThis returns configured account IDs and generated tool prefixes only. It never returns Apple keys, issuer IDs, private keys, or vendor numbers.
Remote HTTP Gateway
Remote mode runs a web server with:
GET /healthzPOST /mcp
Required environment variables:
APPLE_ACCOUNTS_FILE=/run/secrets/apple_accounts.json
MCP_SERVER_TOKEN=replace-with-long-random-tokenAPPLE_ACCOUNTS_JSON is intentionally not supported in remote HTTP mode. Use a mounted file so Apple credentials are not baked into the image or visible in process environment dumps.
Docker Compose
Create local files:
mkdir -p secrets
cp .env.example .envAdd Apple credentials to:
secrets/apple_accounts.jsonSet the gateway token in .env:
MCP_SERVER_TOKEN=replace-with-long-random-tokenStart the server:
docker compose up --buildHealth check:
curl http://localhost:3000/healthzUnauthorized MCP requests return 401:
curl -i -X POST http://localhost:3000/mcpManual initialize request:
curl -i http://localhost:3000/mcp \
-H "Authorization: Bearer replace-with-long-random-token" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
--data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'Remote MCP Client Config
Use this pattern for clients that support remote Streamable HTTP MCP servers:
{
"servers": {
"appstore-connect": {
"type": "http",
"url": "https://example.com/mcp",
"headers": {
"Authorization": "Bearer replace-with-long-random-token"
}
}
}
}Developers using remote mode only need the URL and gateway token. They do not need Apple API credentials.
Local npx stdio
Local stdio mode runs directly from npm:
npx -y @kaisar/mcp-appstore-connectIt requires APPLE_ACCOUNTS, a base64-encoded copy of apple_accounts.json.
Generate the value:
node -e "process.stdout.write(Buffer.from(require('fs').readFileSync('secrets/apple_accounts.json')).toString('base64'))"MCP client config:
{
"mcpServers": {
"appstore-connect": {
"command": "npx",
"args": ["-y", "@kaisar/mcp-appstore-connect"],
"env": {
"APPLE_ACCOUNTS": "base64-encoded-apple-accounts-json"
}
}
}
}Base64 is not encryption. Anyone who can read this MCP client config can decode the Apple credentials.
Development
Install dependencies:
pnpm installBuild:
pnpm run buildRun tests:
pnpm testRun remote HTTP mode locally:
APPLE_ACCOUNTS_FILE="./secrets/apple_accounts.json" \
MCP_SERVER_TOKEN="replace-with-long-random-token" \
pnpm run devRun stdio mode locally:
APPLE_ACCOUNTS="base64-encoded-apple-accounts-json" pnpm run dev:stdioValidate mounted-file configuration:
APPLE_ACCOUNTS_FILE="./secrets/apple_accounts.json" pnpm run validate:configValidate base64 configuration:
APPLE_ACCOUNTS="base64-encoded-apple-accounts-json" pnpm run validate:configValidation prints only account IDs, tool prefixes, private key validity, and key type. It does not print private key content.
Security
Do not commit real
apple_accounts.jsonfiles.Do not commit
.envfiles.Do not bake Apple private keys into Docker images.
Use HTTPS for remote HTTP deployments.
Use a long random
MCP_SERVER_TOKEN.Rotate
MCP_SERVER_TOKENwhen access changes.Treat the base64
APPLE_ACCOUNTSvalue as secret material.Give App Store Connect API keys the minimum Apple role needed for the tools users will call.
Review logs before sharing them. Logs are designed to avoid secrets, but operational logs can still reveal account IDs and request timing.
Supported Tool Areas
The server focuses on read-oriented App Store Connect operations, including:
apps and app metadata
builds and TestFlight resources
beta groups and beta feedback
customer reviews and review summaries
app versions, screenshots, previews, and localizations
in-app purchases, subscriptions, offers, prices, and promoted purchases
app availability and pricing
analytics, sales, finance, and performance reports
App Store Connect users
Troubleshooting
Set APPLE_ACCOUNTS_FILE to the mounted apple_accounts.json path
Remote HTTP mode needs APPLE_ACCOUNTS_FILE and a readable mounted JSON file.
Set APPLE_ACCOUNTS to base64-encoded apple_accounts.json content
Local stdio mode needs APPLE_ACCOUNTS.
Set MCP_SERVER_TOKEN
Remote HTTP mode needs a gateway token.
Unauthorized
The MCP client bearer token does not match MCP_SERVER_TOKEN.
JWT generation failed
The private key is not a valid App Store Connect .p8 EC private key. Re-copy the complete key, including the BEGIN PRIVATE KEY and END PRIVATE KEY lines.
Sales report errors mentioning reportSubType or vendorNumber
Sales and Trends reports require Apple report filters and a numeric Vendor Number. Pass vendorNumber in the tool call or configure it in the account entry.
App lookup errors for values like com.example.app
Most App Store Connect API app endpoints expect the numeric app resource ID returned by list_apps, not the bundle ID.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ravenKaisar/mcp-appstore-connect'
If you have feedback or need assistance with the MCP directory API, please join our Discord server