Skip to main content
Glama
README.md
# asc-mcp

An MCP server for the App Store Connect API. It lets an MCP client such as Claude Code read your
apps, customer reviews and TestFlight builds, and publish a reply to a review, while the API key
stays inside this process and never reaches the model.

## Tools

| Tool | What it does | Writes? |
|---|---|---|
| `list_apps` | Apps in the account with ids, bundle ids, primary locale | no |
| `get_reviews` | Reviews of one app for the last N days, with filters by territory and rating | no |
| `get_review_reply` | The existing developer reply to one review | no |
| `list_builds` | Recent builds with marketing version, platform and processing state | no |
| `reply_to_review` | Publishes a public developer reply to one review | **yes** |

`reply_to_review` is the only tool with side effects. Its description asks the model to show the
exact text to the user first, and MCP clients normally ask for permission before running a tool
that is not on their allow-list.

Every call is appended to `~/.asc-mcp/calls.jsonl` (override with `ASC_MCP_LOG`): time, tool,
arguments, duration, success or error message.

## Credentials

1. In App Store Connect open **Users and Access → Integrations → App Store Connect API → Team Keys**
   and generate a key. The **Developer** role is enough for everything this server does.
2. Download the `.p8` file (it can be downloaded only once) and keep it outside this repository,
   for example in `~/.keys/`.
3. Note the **Issuer ID** (top of the Integrations page) and the **Key ID** of the new key.

The server reads three environment variables:

| Variable | Meaning |
|---|---|
| `ASC_ISSUER_ID` | Issuer ID from the Integrations page |
| `ASC_KEY_ID` | Key ID of the generated key |
| `ASC_KEY_PATH` | Path to the `.p8` file (or put the PEM text in `ASC_PRIVATE_KEY` instead) |

See `.env.example`. The key is used to sign short-lived JWTs (15 minutes, ES256). It is read once
and never written anywhere.

## Build and run

```bash
npm install
npm run build
```

Try the tools by hand in the MCP Inspector (opens a web page that starts the server for you):

```bash
ASC_ISSUER_ID=... ASC_KEY_ID=... ASC_KEY_PATH=~/.keys/AuthKey_XXXX.p8 npm run inspect
```

Or list the tools from the command line without any credentials:

```bash
npm run tools
```

## Use from Claude Code

Add the server to the project where you want it (a `.mcp.json` file in the project root), or to
`~/.claude.json` for all projects:

```json
{
  "mcpServers": {
    "asc": {
      "command": "node",
      "args": ["/Users/you/Projects/asc-mcp/dist/index.js"],
      "env": {
        "ASC_ISSUER_ID": "00000000-0000-0000-0000-000000000000",
        "ASC_KEY_ID": "ABCDEF1234",
        "ASC_KEY_PATH": "/Users/you/.keys/AuthKey_ABCDEF1234.p8"
      }
    }
  }
}
```

Then, in a Claude Code session: *"What did users write about my app this week, and which reviews
should I answer?"* Claude calls `list_apps`, then `get_reviews`, and drafts replies. Nothing is
published until you ask it to call `reply_to_review` and approve the call.

## Project layout

```
src/
  index.ts        server start-up and tool registration (stdio transport)
  auth.ts         JWT minting and caching from the .p8 key
  api.ts          GET/POST helpers, error messages, pagination
  log.ts          JSONL call log
  register.ts     wraps tool handlers: JSON results, error results, logging
  tools/
    apps.ts       list_apps
    reviews.ts    get_reviews, get_review_reply, reply_to_review
    builds.ts     list_builds
```

## Notes and things to verify

- Field names and endpoints follow the App Store Connect API reference as of this writing:
  `GET /v1/apps`, `GET /v1/apps/{id}/customerReviews`, `GET /v1/customerReviews/{id}/response`,
  `POST /v1/customerReviewResponses`, `GET /v1/builds`. If Apple changes a field, the error
  message from `api.ts` names the request that failed.
- The reply length limit (`MAX_REPLY_LENGTH` in `reviews.ts`) mirrors Apple's limit for developer
  responses; check it against the current App Store Connect help before relying on it.
- Sales and download reports use a different endpoint that returns gzipped TSV files. They are not
  implemented yet; see the roadmap.

## Roadmap

- `get_downloads`: units per day from the Sales Reports API.
- `get_app_metadata`: current name, subtitle, keywords and description per locale.
- Resources (MCP `resources/list`) exposing the app list for clients that prefer resources to tools.