play-store-mcp
by petropentsak
README.md
# play-store-mcp
Local stdio MCP server for **Google Play Console**. Credentials (a Google service-account
key) come only from environment variables; OAuth tokens are minted locally by
`google-auth-library`; every request goes directly to `*.googleapis.com`. Nothing is sent to
any third party.
TypeScript reimplementation — the Kotlin project [`antoniolg/play-store-mcp`](https://github.com/antoniolg/play-store-mcp)
was used only as a reference for the API flow and tool design.
## Available tools
23 tools, grouped by capability.
### Releases & rollout
| Tool | Description | Key inputs |
|------|-------------|------------|
| `get_releases` | Current releases/deployments per track | `packageName` |
| `deploy_app` | Upload an APK/AAB and assign it to a track (optional staged rollout) | `packageName`, `track`, `filePath`, `versionCode`, `releaseNotes?`, `rolloutPercentage?` |
| `promote_release` | Promote an existing version from one track to another | `packageName`, `fromTrack`, `toTrack`, `versionCode` |
| `update_track_rollout` | Change a staged-rollout fraction, or halt/complete the in-progress release | `packageName`, `track`, `userFraction?`, `status?` |
| `complete_all_rollouts` | Batch-complete the in-progress staged rollout across multiple apps | `packageNames[]`, `track?`, `versionCode?` |
| `update_release_notes` | Set release notes on the current release of a track (no redeploy) | `packageName`, `notes[]`, `track?` |
### Store listing
| Tool | Description | Key inputs |
|------|-------------|------------|
| `get_listings` | Store listing text (title, short/full description) for every locale | `packageName` |
| `update_listing` | Update a store listing for one locale and commit | `packageName`, `language`, `title?`, `shortDescription?`, `fullDescription?` |
| `get_app_details` | App-level details (default language, contact email/phone/website) | `packageName` |
| `upload_listing_image` | Upload a store-listing graphic (icon, screenshots, feature graphic, …) for a locale | `packageName`, `language`, `imageType`, `filePath` |
### Reviews
| Tool | Description | Key inputs |
|------|-------------|------------|
| `get_reviews` | Recent user reviews (rating, text, app version, device) | `packageName`, `maxResults?`, `translationLanguage?` |
| `reply_to_review` | Post a developer reply to a user review | `packageName`, `reviewId`, `replyText` |
### Monetization
| Tool | Description | Key inputs |
|------|-------------|------------|
| `list_in_app_products` | List managed in-app products (SKUs) | `packageName` |
| `list_subscriptions` | List subscription products | `packageName` |
| `update_in_app_product` | Update an existing managed IAP (status / default price) and commit | `packageName`, `sku`, `status?`, `defaultPrice?` |
| `get_voided_purchases` | List refunded/revoked (voided) purchases | `packageName` |
| `refund_order` | Refund a single order, optionally revoking the entitlement | `packageName`, `orderId`, `revoke?` |
### Testers
| Tool | Description | Key inputs |
|------|-------------|------------|
| `manage_testers` | Read (omit groups) or set the Google Groups of testers for a closed track | `packageName`, `track`, `googleGroups?` |
### Analytics & reports
| Tool | Description | Key inputs |
|------|-------------|------------|
| `get_users_by_version` | Distinct users per app version over N days (Reporting API) | `packageName`, `days?` |
| `get_app_vitals` | Latest crash rate and ANR rate (Reporting API) | `packageName`, `days?` |
| `get_install_stats` | Install base per app version + monthly net growth, from the statistics GCS reports | `packageName`, `month?` |
| `get_install_reports` | Raw install/uninstall report rows for one month and dimension, from the statistics GCS reports | `packageName`, `month`, `dimension?` |
### Meta
| Tool | Description | Key inputs |
|------|-------------|------------|
| `search_apps` | List the apps this service account can access (Reporting API) | — |
> `get_users_by_version` uses the Reporting API's vitals-scoped `distinctUsers` metric — a
> proxy for the active user base, ideal for the version-adoption split, **not** an exact
> install count (the Reporting API has no install-count metric; real install counts live in
> the statistics GCS reports, read by `get_install_stats` and `get_install_reports`).
>
> `get_install_reports` reads `stats/installs/installs_{package}_{YYYYMM}_{dimension}.csv`
> (`dimension` ∈ `overview` | `country` | `app_version`, default `overview`) from the reports
> bucket. These CSVs are UTF-16LE with a BOM; the server decodes and parses them. Set
> `PLAY_REPORTS_BUCKET` (Play Console → Download reports → Statistics → Copy Cloud Storage URI;
> the `pubsite_prod_*` value) and grant the service account Storage Object Viewer on it.
## Setup
1. **Google Cloud:** create a project, enable **Google Play Android Developer API** and
**Google Play Developer Reporting API**, create a **service account**, and download its
**JSON key**.
2. **Play Console → Users and permissions:** invite the service-account email; grant it the
apps and the "View app information / bulk reports" + "Releases" permissions.
3. **Configure the MCP** (`~/.claude.json`):
```json
{
"mcpServers": {
"play-store": {
"command": "npx",
"args": ["-y", "github:petropentsak/play-store-mcp"],
"env": {
"PLAY_SERVICE_ACCOUNT_KEY_PATH": "/absolute/path/to/service-account-key.json",
"PLAY_DEFAULT_TRACK": "internal"
}
}
}
}
```
`PLAY_SERVICE_ACCOUNT_KEY` (raw or base64 JSON) is accepted as an alternative to the path.
## Build / release
`dist/` is committed so `npx github:` works with no build step. The config is **not** pinned to a
tag — it tracks the default-branch HEAD, so every commit must be installable (build + commit `dist/`).
To ship: `npm run build` → commit (incl. `dist/`) → push HEAD to the default branch → clear
`~/.npm/_npx` if a stale tarball is cached → reconnect / cold-start the MCP client.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues