MCP server for Google Play: full Android Publisher API v3 and Play Developer Reporting API.
The complete Model Context Protocol (MCP) server for Google Play. 157 tools. Full Android Publisher API v3 + Play Developer Reporting API v1beta1. No deprecated endpoints. Works with Claude, Cursor, VS Code Copilot, Gemini CLI, or any MCP client.
See also: app-store-connect-mcp — the same philosophy for Apple's App Store Connect.
Google Play Console has an API, but its surface is wide and moves fast. Existing community MCPs each cover a slice — one does store listings, another does releases, a third does reviews — and all lag behind Google's deprecations.
google-play-developer-mcp is the one that covers everything.
| Property | This server | Typical community MCP |
|---|---|---|
| Android Publisher API v3 | ✅ Full | Partial |
| Play Developer Reporting API | ✅ Full | ❌ Missing |
monetization.onetimeproducts (post-2025 catalog) | ✅ | Uses deprecated inappproducts |
purchases.subscriptionsv2 / productsv2 | ✅ | Often still on v1 |
| 2026 features (OfferPhase, cancel/defer, priceStepUp) | ✅ | ❌ |
| Multi-account | ✅ | Usually one |
| Credential safety | No keys in repo, strict .gitignore | Varies |
| Public release under semver | ✅ v1.0.0 | Mostly pre-1.0 |
If you drive Google Play Console with an AI assistant — release automation, review triage, subscription catalog management, crash triage — this gives the assistant a full toolbox in one install.
157 tools across 33 groups. Every non-deprecated endpoint in both APIs.
| Group | Tools | Covers |
|---|---|---|
accounts_* | 6 | Local registry — add / list / switch / remove / update multiple Play Console accounts |
auth_* | 1 | Verify the service account can acquire a token |
apps_* | 2 | List every app the service account can see, get app details |
edits_* | 5 | Managed-publishing transactions: insert, get, validate, commit, delete |
details_* | 3 | App-level contact email / phone / website, default language |
country_availability_* | 1 | Per-country availability within an edit |
listings_* | 6 | Per-locale title / short description / full description / video. Includes delete_all |
images_* | 4 | Icon, feature graphic, promo graphic, phone/tablet/TV/wear screenshots. List, upload, delete, delete-all |
bundles_* | 2 | Upload and list Android App Bundles (AAB) |
apks_* | 3 | Upload / list APKs + register externally-hosted APK (enterprise) |
deobfuscation_files_* | 1 | Upload ProGuard / native code mapping |
expansion_files_* | 4 | OBB — get / upload / update / patch |
tracks_* | 5 | internal, alpha, beta, production, plus custom closed-testing tracks. List, get, update, patch, create |
testers_* | 3 | Google Groups allowlists for internal / closed tracks |
onetime_products_* | 17 | ✨ New monetization catalog for non-subscription products. Three-level hierarchy: product → purchase option → offer. Complete CRUD + batch on all three levels |
subscriptions_* | 8 | Subscription catalog: list, create, update, delete, archive, batch-get, batch-update |
subscription_base_plans_* | 7 | Monthly/annual plans. Activate, deactivate, migrate prices, batch migrate, batch update + states |
subscription_offers_* | 10 | Free trials / introductory prices. Create, update, delete, activate, deactivate + batch flavours |
monetization_convert_region_prices | 1 | Compute comparable region prices from one input price |
purchases_products_v2_* | 1 | Verify one-time-product purchases (supports multiple purchase options + offers) |
purchases_products_* | 2 | Acknowledge / consume one-time purchases (productsv2 only exposes get) |
purchases_subscriptions_v2_* | 4 | Get, revoke, cancel, defer. Includes 2026 OfferPhase, outOfAppPurchaseContext, priceStepUp consent, item-based refund |
purchases_subscriptions_acknowledge | 1 | v1 acknowledge (retained — still the right call for acknowledging initial purchase) |
purchases_voided_list | 1 | Refund / chargeback feed |
orders_* | 5 | List, get, batch-get, refund, review refund (get + batch-get added 2025-05, review_refund added 2026-07 for collaborative chargebacks) |
external_transactions_* | 3 | Alternative Billing (Korea / EU) — get / create / refund |
reviews_* | 3 | List, get, reply |
users_* + grants_* | 7 | Team members & per-app grants |
device_tier_configs_* | 3 | Device-tier targeting for AAB |
app_recovery_* | 5 | Recovery actions: list, create, deploy, cancel, add targeting |
generated_apks_* | 2 | List and download generated APKs from an AAB |
system_apks_variants_* | 4 | System APK variants for preload scenarios |
internal_app_sharing_* | 2 | Upload APK or AAB for internal link sharing |
| Group | Tools | Covers |
|---|---|---|
reports_apps_* | 2 | search, fetch_release_filter_options |
reports_anomalies_list | 1 | Detected anomalies across all metric sets |
reports_crash_rate_* | 2 | Crash rate — metadata + time-series query |
reports_anr_rate_* | 2 | ANR rate |
reports_slow_start_rate_* | 2 | Slow start (cold launch) |
reports_slow_rendering_rate_* | 2 | Slow rendering (jank) |
reports_excessive_wakeup_rate_* | 2 | Battery — excessive wake-ups |
reports_stuck_background_wake_lock_rate_* | 2 | Battery — stuck wake locks |
reports_lmk_rate_* | 2 | Low-memory killer rate |
reports_anon_rss_swap_memory_* | 2 | Anonymous RSS + swap memory usage |
reports_bitmap_memory_* | 2 | Bitmap memory usage |
reports_errors_counts_* | 2 | Aggregate error counts |
reports_errors_issues_search | 1 | Grouped ErrorIssue search |
reports_errors_reports_search | 1 | Raw ErrorReport search |
npm install -g google-play-developer-mcp
Then in your MCP client config (e.g. ~/.config/claude/config.json, Cursor MCP config, or VS Code mcp.json):
{
"mcpServers": {
"google-play-developer": {
"command": "google-play-developer-mcp"
}
}
}
Next, tell the server which Play Console account to use — see the setup guide below.
~/.config/google-play-developer-mcp/service-account.json.name@project-id.iam.gserviceaccount.com).PERMISSION_DENIED, this is usually why.Launch any MCP client that has the server configured, then run:
accounts_add --name my-app \
--keyFile /Users/you/.config/google-play-developer-mcp/service-account.json \
--description "My company's Play Console"
(Or manually create ~/.google-play-developer-mcp/accounts.json — see the file format below.)
auth_status
Should return { ok: true, email: "..." }.
apps_list
Lists the apps the service account can see.
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%/Claude/claude_desktop_config.json
{
"mcpServers": {
"google-play-developer": {
"command": "google-play-developer-mcp"
}
}
}
claude mcp add google-play-developer google-play-developer-mcp
Or edit ~/.claude.json:
{
"mcpServers": {
"google-play-developer": {
"command": "google-play-developer-mcp"
}
}
}
Settings → MCP → Add new MCP server:
{
"google-play-developer": {
"command": "google-play-developer-mcp"
}
}
.vscode/mcp.json:
{
"servers": {
"google-play-developer": {
"type": "stdio",
"command": "google-play-developer-mcp"
}
}
}
Any MCP-compliant client accepts the same command entry — point it at the globally installed google-play-developer-mcp binary (or at node /path/to/dist/index.js if running from source).
git clone https://github.com/devinwang/google-play-developer-mcp.git
cd google-play-developer-mcp
npm install
npm run build
Then in your MCP client config:
{
"mcpServers": {
"google-play-developer": {
"command": "node",
"args": ["/absolute/path/to/google-play-developer-mcp/dist/index.js"]
}
}
}
accounts_switch --name my-app
# Open an edit, upload bundle, route it to the internal track, commit.
edits_insert --packageName com.example.app
# → { id: "EDIT_ID", expiryTimeSeconds: "..." }
bundles_upload --packageName com.example.app --editId EDIT_ID \
--file /path/to/app-release.aab
# → { versionCode: 47, sha256: "..." }
tracks_update --packageName com.example.app --editId EDIT_ID \
--track internal \
--releases '[{"versionCodes":["47"],"status":"completed","releaseNotes":[{"language":"en-US","text":"Fixes a crash on startup."}]}]'
edits_commit --packageName com.example.app --editId EDIT_ID
edits_insert --packageName com.example.app
# → EDIT_ID
# Promote the beta versionCodes to production with 10% staged rollout.
tracks_update --packageName com.example.app --editId EDIT_ID \
--track production \
--releases '[{"versionCodes":["47"],"status":"inProgress","userFraction":0.1}]'
edits_commit --packageName com.example.app --editId EDIT_ID
reviews_list --packageName com.example.app --maxResults 50
# → { reviews: [{ reviewId, authorName, comments, ... }] }
reviews_reply --packageName com.example.app --reviewId REVIEW_ID \
--replyText "Thanks for the feedback! The crash is fixed in v1.2 — please update."
# 1. Create the subscription (product)
subscriptions_create --packageName com.example.app --productId plus_monthly \
--subscription '{"listings":[{"languageCode":"en-US","title":"Plus","benefits":["All premium features"]}],"taxAndComplianceSettings":{"taxTier":"TAX_TIER_UNSPECIFIED"}}'
# 2. Create a base plan
subscription_base_plans_batch_update --packageName com.example.app --productId plus_monthly \
--requests '[{"basePlan":{"basePlanId":"monthly","autoRenewingBasePlanType":{"billingPeriodDuration":"P1M","accountHoldDuration":"P30D"},"state":"DRAFT","regionalConfigs":[{"regionCode":"US","price":{"currencyCode":"USD","units":"9","nanos":990000000}}]},"updateMask":"autoRenewingBasePlanType,regionalConfigs"}]'
# 3. Activate the base plan
subscription_base_plans_activate --packageName com.example.app \
--productId plus_monthly --basePlanId monthly
# 4. Create a 7-day free-trial offer
subscription_offers_create --packageName com.example.app --productId plus_monthly \
--basePlanId monthly --offerId new-user-trial \
--offer '{"phases":[{"duration":"P7D","regionalConfigs":[{"regionCode":"US","free":true}]}],"state":"DRAFT"}'
subscription_offers_activate --packageName com.example.app \
--productId plus_monthly --basePlanId monthly --offerId new-user-trial
# For a one-time product (consumable or non-consumable)
purchases_products_v2_get --packageName com.example.app --token PURCHASE_TOKEN
# For a subscription — includes 2026 OfferPhase, priceChangeState, etc.
purchases_subscriptions_v2_get --packageName com.example.app --token PURCHASE_TOKEN
reports_crash_rate_query \
--name "apps/com.example.app/crashRateMetricSet" \
--dimensions '["versionCode","countryCode"]' \
--metrics '["crashRate","distinctUsers"]' \
--timelineSpec '{"aggregationPeriod":"DAILY","startTime":{"year":2026,"month":4,"day":1},"endTime":{"year":2026,"month":4,"day":8}}'
reports_errors_issues_search --parent "apps/com.example.app" \
--filter "errorIssueType = \"CRASH\""
All tools use snake_case names following the resource_action convention, consistent with the Android Publisher URL structure. See the Feature matrix for the full group breakdown.
Each tool accepts a JSON object of arguments — inspect the schema from your MCP client (Claude Code: /mcp tools, Claude Desktop: show tool list in chat, Cursor: MCP panel) to see the exact shape.
Complex body arguments (e.g. subscription, offer, appRecoveryAction, subscription releases) accept the Google-documented JSON schema directly — see the official reference.
This repo ships with zero credentials. You bring a service-account JSON key; the server records only the path.
What is and isn't on disk:
| Where | What |
|---|---|
~/.google-play-developer-mcp/accounts.json | Account name + key-file path + description. No secrets. Created with 0600 permissions. |
~/.config/…/service-account.json (you place it) | The actual Google Cloud service-account JSON. Never committed. Never emitted by any tool. |
| Repo contents | Code only. |
.gitignore blocks*.json.key, *service-account*.json, *service_account*.json, *-sa.json, *-sa-key.jsongcp-key*.json, google-credentials*.json, play-credentials*.json.env, .env.* (but keeps .env.example)accounts.json, credentials/, keys/, secrets/*.pem, *.p12, *.pfx, *.key, id_rsa*accounts_update --keyFile <newPath>.auth_status never returns the actual token; only a boolean and the service-account email.Every write operation on the Android Publisher API is logged by Google Cloud IAM under the service account's identity. If you ever suspect misuse, IAM → Audit Logs in the Cloud Console will show which endpoints were called.
edits_insert / edits_commit / edits_delete directly so you can hold an edit open across many tool calls — the most common multi-step flow. If you forget to commit, nothing ships. Safe by default.accounts_switch. State lives in ~/.google-play-developer-mcp/accounts.json.monetization.onetimeproducts (not the deprecated inappproducts). Purchase verification uses purchasesV2 / subscriptionsV2.googleapis TypeScript typings, we cast through publisherAny() / reportingAny(). The HTTP calls are identical — only TypeScript's static check is skipped on the known-drifting surfaces.PRs welcome. Before you submit:
npm run typecheck passes (CI will also run this)X-Goog-Api-Client: ...REDACTED...).resource_action naming convention.orders_review_refund, purchases_products_acknowledge, purchases_products_consume, reports_anon_rss_swap_memory_{get,query}, reports_bitmap_memory_{get,query}.googleapis 171 → 187.monetization.onetimeproducts (replaces deprecated inappproducts), purchases.productsv2 / subscriptionsv2 (replaces v1).SubscriptionPurchaseV2.offerPhase, purchases.subscriptionsv2.cancel/defer, orders.batchGet, offerPhaseDetails, price step-up consent, outOfAppPurchaseContext..gitignore.monetization.onetimeproducts referencepurchases.subscriptionsv2 referenceMIT — see LICENSE.
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
npx -y google-play-developer-mcpMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-devinwang-google-play-developer-mcp": {
"command": "npx",
"args": [
"-y",
"google-play-developer-mcp"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referencegoogle-play-developer-mcpnpmio.github.devinwang/google-play-developer-mcp works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.