google-play-developer-mcp
A comprehensive MCP server exposing ~157 tools that give AI assistants full programmatic control over Google Play Console via the Android Publisher API v3 and Play Developer Reporting API v1beta1.
Multi-account management — register, list, switch, update, and remove multiple Play Console service-account credentials, and verify authentication with
auth_status.App discovery & details — list accessible apps and read/update app-level info (contact email, phone, website, default language).
Edit-session workflows — open, validate, commit, or discard edits so multi-step publishing changes are staged atomically and safely.
Store listings & images — manage per-locale titles/descriptions/videos and upload/delete icons, feature graphics, promo graphics, and device screenshots.
Artifact uploads — upload AABs, APKs, externally-hosted APKs, ProGuard/native deobfuscation mappings, and OBB expansion files.
Release & track management — manage internal/alpha/beta/production and custom closed-testing tracks, staged rollouts, releases, tester allowlists (Google Groups), and country availability.
Monetization catalog — full CRUD and batch operations for one-time products (product → purchase option → offer), subscriptions, base plans, and offers (free trials/intro pricing), plus region price conversion.
Purchase verification — fetch one-time product and subscription purchase state (including 2026 OfferPhase/price step-up), acknowledge, cancel, defer, and revoke purchases; list voided purchases.
Order & refund handling — list, get, and batch-get orders; issue refunds with optional entitlement revocation.
Crash/performance & business reporting — query crash rate, ANR, slow start, slow rendering, battery/memory metrics, error issues/reports, anomalies, and app search via the Reporting API.
Provides 150 tools covering the full Android Publisher API v3 and Play Developer Reporting API v1beta1, enabling management of app listings, releases, in-app products, subscriptions, reviews, crash reports, and more in the Google Play Console.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@google-play-developer-mcp list my apps"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
google-play-developer-mcp
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.
Table of Contents
Related MCP server: Google Play Developer API MCP Server
Why this exists
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 |
| ✅ | Uses deprecated |
| ✅ | Often still on v1 |
2026 features (OfferPhase, cancel/defer, priceStepUp) | ✅ | ❌ |
Multi-account | ✅ | Usually one |
Credential safety | No keys in repo, strict | 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.
Feature matrix
157 tools across 33 groups. Every non-deprecated endpoint in both APIs.
Group | Tools | Covers |
| 6 | Local registry — add / list / switch / remove / update multiple Play Console accounts |
| 1 | Verify the service account can acquire a token |
| 2 | List every app the service account can see, get app details |
| 5 | Managed-publishing transactions: |
| 3 | App-level contact email / phone / website, default language |
| 1 | Per-country availability within an edit |
| 6 | Per-locale title / short description / full description / video. Includes |
| 4 | Icon, feature graphic, promo graphic, phone/tablet/TV/wear screenshots. List, upload, delete, delete-all |
| 2 | Upload and list Android App Bundles (AAB) |
| 3 | Upload / list APKs + register externally-hosted APK (enterprise) |
| 1 | Upload ProGuard / native code mapping |
| 4 | OBB — get / upload / update / patch |
| 5 |
|
| 3 | Google Groups allowlists for internal / closed tracks |
| 17 | ✨ New monetization catalog for non-subscription products. Three-level hierarchy: product → purchase option → offer. Complete CRUD + batch on all three levels |
| 8 | Subscription catalog: list, create, update, delete, archive, batch-get, batch-update |
| 7 | Monthly/annual plans. Activate, deactivate, migrate prices, batch migrate, batch update + states |
| 10 | Free trials / introductory prices. Create, update, delete, activate, deactivate + batch flavours |
| 1 | Compute comparable region prices from one input price |
| 1 | Verify one-time-product purchases (supports multiple purchase options + offers) |
| 2 | Acknowledge / consume one-time purchases ( |
| 4 | Get, revoke, cancel, defer. Includes 2026 |
| 1 | v1 acknowledge (retained — still the right call for acknowledging initial purchase) |
| 1 | Refund / chargeback feed |
| 5 | List, get, batch-get, refund, review refund (get + batch-get added 2025-05, |
| 3 | Alternative Billing (Korea / EU) — get / create / refund |
| 3 | List, get, reply |
| 7 | Team members & per-app grants |
| 3 | Device-tier targeting for AAB |
| 5 | Recovery actions: list, create, deploy, cancel, add targeting |
| 2 | List and download generated APKs from an AAB |
| 4 | System APK variants for preload scenarios |
| 2 | Upload APK or AAB for internal link sharing |
Group | Tools | Covers |
| 2 |
|
| 1 | Detected anomalies across all metric sets |
| 2 | Crash rate — metadata + time-series query |
| 2 | ANR rate |
| 2 | Slow start (cold launch) |
| 2 | Slow rendering (jank) |
| 2 | Battery — excessive wake-ups |
| 2 | Battery — stuck wake locks |
| 2 | Low-memory killer rate |
| 2 | Anonymous RSS + swap memory usage |
| 2 | Bitmap memory usage |
| 2 | Aggregate error counts |
| 1 | Grouped ErrorIssue search |
| 1 | Raw ErrorReport search |
Quick start
npm install -g google-play-developer-mcpThen 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.
Step-by-step setup
1. Create a Google Cloud service account
Open the Google Cloud Console.
Select or create a project (any project — this is just where the service account lives).
APIs & Services → Library — enable both of these:
Google Play Android Developer API
Google Play Developer Reporting API
IAM & Admin → Service Accounts → Create service account.
Once created, open the account → Keys → Add key → JSON. Download the JSON file.
Move the JSON file somewhere safe and outside any git repo. A good location:
~/.config/google-play-developer-mcp/service-account.json.
2. Authorize the service account in Play Console
Open Play Console.
Users and permissions → Invite new user. Paste the service account email (it looks like
name@project-id.iam.gserviceaccount.com).Assign permissions:
Admin (all permissions) for full access.
Or narrower combinations (View app information, Manage store presence, Manage orders and subscriptions, etc.) if you want to restrict what the MCP can do.
Wait up to 24 hours. Play Console takes time to propagate the new authorization — this is a common gotcha. If early API calls return
PERMISSION_DENIED, this is usually why.
3. Register the account with the MCP server
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.)
4. Verify
auth_statusShould return { ok: true, email: "..." }.
apps_listLists the apps the service account can see.
Register with your MCP client
Claude Desktop
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 Code
claude mcp add google-play-developer google-play-developer-mcpOr edit ~/.claude.json:
{
"mcpServers": {
"google-play-developer": {
"command": "google-play-developer-mcp"
}
}
}Cursor
Settings → MCP → Add new MCP server:
{
"google-play-developer": {
"command": "google-play-developer-mcp"
}
}VS Code (GitHub Copilot agent mode)
.vscode/mcp.json:
{
"servers": {
"google-play-developer": {
"type": "stdio",
"command": "google-play-developer-mcp"
}
}
}Gemini CLI / Codex CLI / Windsurf / Continue
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).
Running from source (no npm install -g)
git clone https://github.com/devinwang/google-play-developer-mcp.git
cd google-play-developer-mcp
npm install
npm run buildThen in your MCP client config:
{
"mcpServers": {
"google-play-developer": {
"command": "node",
"args": ["/absolute/path/to/google-play-developer-mcp/dist/index.js"]
}
}
}Usage examples
Release a new build to internal testing
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_IDPromote a release from beta to production with staged rollout
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_IDReply to reviews
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."Create a subscription with a free-trial offer
# 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-trialVerify a purchase token server-side (backend use case)
# 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_TOKENTriage crashes
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\""Tool reference
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.
Security
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 |
| Account name + key-file path + description. No secrets. Created with |
| 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*
Recommended hygiene
Keep your service-account JSON outside any git repo on your machine.
Grant the service account the narrowest role that your workflow needs. Full admin grants the MCP permission to delete app metadata — give it only what you need.
Rotate the service-account key yearly: delete the old key in Google Cloud Console, create a new one, run
accounts_update --keyFile <newPath>.auth_statusnever returns the actual token; only a boolean and the service-account email.
Audit trail
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.
Design notes
Edit-session-aware. Every write on the Android Publisher API runs inside an edit. The server exposes
edits_insert/edits_commit/edits_deletedirectly 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.Multi-account. One server process can manage many Play Console accounts. Switch with
accounts_switch. State lives in~/.google-play-developer-mcp/accounts.json.No deprecated endpoints. Catalogue endpoints use
monetization.onetimeproducts(not the deprecatedinappproducts). Purchase verification usespurchasesV2/subscriptionsV2.Forward-compatible types. Where Google ships an API feature faster than the
googleapisTypeScript typings, we cast throughpublisherAny()/reportingAny(). The HTTP calls are identical — only TypeScript's static check is skipped on the known-drifting surfaces.Good error messages. Every Google API error is translated — 401 becomes "your token is wrong", 403 becomes "permission not propagated, wait 24h", 429 becomes "quota exhausted", etc.
Stateless transport. Server is stdio, no network listener, no persistent state beyond the accounts file.
Zero telemetry. The server never phones home.
Contributing
PRs welcome. Before you submit:
npm run typecheckpasses (CI will also run this)Never include a service-account key or token in an issue or PR. If you need to share a reproduction, redact the token (
X-Goog-Api-Client: ...REDACTED...).New tools follow the
resource_actionnaming convention.If you add a tool that hits a new API surface, add it to the Feature matrix so the doc stays in sync.
Version history
0.2.0 — 2026-10-21
157 MCP tools (+7). New:
orders_review_refund,purchases_products_acknowledge,purchases_products_consume,reports_anon_rss_swap_memory_{get,query},reports_bitmap_memory_{get,query}.Upgraded
googleapis171 → 187.
0.1.0 — 2026-04-20 (first public release)
150 MCP tools covering the full Android Publisher API v3 and Play Developer Reporting API v1beta1.
Latest-generation endpoints only. Uses
monetization.onetimeproducts(replaces deprecatedinappproducts),purchases.productsv2/subscriptionsv2(replaces v1).2026 features.
SubscriptionPurchaseV2.offerPhase,purchases.subscriptionsv2.cancel/defer,orders.batchGet,offerPhaseDetails, price step-up consent,outOfAppPurchaseContext.Multi-account support with on-disk registry.
Zero credentials in the repository. Comprehensive
.gitignore.Error translation for all common Google API failure modes.
References
License
MIT — see LICENSE.
Available Tools
157 toolsaccounts_addA
Register a new Play Console account. Provide a local filesystem path to a Google Cloud service-account JSON key. The key stays on disk — the MCP only records its path.
Inputs: name (required), keyFile (required), description.
accounts_currentA
Show which account is currently active. All subsequent API calls target this account.
Inputs: no named parameters.
accounts_listA
List every Play Console account registered with the MCP server (names + key-file paths, no secrets).
Inputs: no named parameters.
accounts_removeB
Remove an account from the local registry. Does NOT delete the key file.
Inputs: name (required).
accounts_switchB
Make an existing registered account the active one.
Inputs: name (required).
accounts_updateB
Change the key-file path or description of an existing account.
Inputs: name (required), keyFile, description.
apks_add_externally_hostedA
Register an APK that is hosted outside Google Play (enterprise-only, requires allowlist).
Inputs: editId (required), packageName (required), externallyHostedApk (required).
apks_listB
List all APK uploads in the edit.
Inputs: editId (required), packageName (required).
apks_uploadA
Upload a new APK. Prefer AAB via bundles_upload.
Inputs: file (required), editId (required), packageName (required).
app_recovery_add_targetingB
Add targeting (country/locale/version) to an in-progress recovery action.
Inputs: packageName (required), appRecoveryId (required), targetingUpdate (required).
app_recovery_cancelB
Cancel an in-flight app recovery action.
Inputs: packageName (required), appRecoveryId (required).
app_recovery_createD
Create an app recovery action.
Inputs: packageName (required), appRecoveryAction (required).
app_recovery_deployC
Deploy an app recovery action to users.
Inputs: packageName (required), appRecoveryId (required).
app_recovery_listC
List app recovery actions for a versionCode.
Inputs: packageName (required), versionCode (required).
apps_getA
Open a fresh edit and return the details resource (contact email/phone/website + default language) for one app.
Inputs: packageName (required).
apps_listB
List every Android app the active service account can access. Uses the Play Developer Reporting API's apps.search.
Inputs: pageSize, pageToken.
auth_statusA
Verify that the active account can acquire a Google OAuth token. Returns the service-account email plus whether a token was obtained.
Inputs: no named parameters.
bundles_listC
List all AAB uploads in the current edit.
Inputs: editId (required), packageName (required).
bundles_uploadA
Upload a new App Bundle (.aab). Returns versionCode and sha256. Commit the edit separately to publish to a track.
Inputs: file (required), editId (required), packageName (required), deviceTierConfigId, +1 more.
country_availability_getB
Fetch per-country availability for a given track within an edit.
Inputs: track (required), editId (required), packageName (required).
deobfuscation_files_uploadC
Upload a ProGuard mapping file for a specific version code. Use deobfuscationFileType='proguard' or 'nativeCode'.
Inputs: file (required), editId (required), packageName (required), apkVersionCode (required), +1 more.
details_getA
Get app-level details (contact email/phone/website + default language).
Inputs: editId (required), packageName (required).
details_patchB
Partial update — only the provided fields change.
Inputs: editId (required), packageName (required), contactEmail, contactPhone, +2 more.
details_updateB
Overwrite app-level details. Full replacement — unspecified fields are cleared.
Inputs: editId (required), packageName (required), contactEmail, contactPhone, +2 more.
device_tier_configs_createC
Create a new device-tier config.
Inputs: packageName (required), deviceTierConfig (required), allowUnknownDevices.
device_tier_configs_getC
Get a device-tier config by id.
Inputs: packageName (required), deviceTierConfigId (required).
device_tier_configs_listB
List all device-tier configs for an app.
Inputs: packageName (required), pageSize, pageToken.
edits_commitB
Commit and publish all changes in the edit. Pass changesNotSentForReview=true to skip automatic review submission.
Inputs: editId (required), packageName (required), changesNotSentForReview.
edits_deleteB
Abandon an edit. All pending changes are discarded.
Inputs: editId (required), packageName (required).
edits_getA
Fetch an existing edit — useful to check expiry before work.
Inputs: editId (required), packageName (required).
edits_insertA
Open a new edit session for an app. Returns the edit id plus its expiry. Subsequent edits.* tool calls must pass this id.
Inputs: packageName (required).
edits_validateA
Validate an edit without committing. Catches schema/media errors before you publish.
Inputs: editId (required), packageName (required).
expansion_files_getB
Get expansion file metadata for a version code.
Inputs: editId (required), packageName (required), apkVersionCode (required), expansionFileType (required).
expansion_files_patchC
Partial update of expansion file metadata.
Inputs: editId (required), packageName (required), apkVersionCode (required), expansionFileType (required), +2 more.
expansion_files_updateC
Full update of expansion file metadata.
Inputs: editId (required), packageName (required), apkVersionCode (required), expansionFileType (required), +2 more.
expansion_files_uploadC
Upload expansion file contents (OBB).
Inputs: file (required), editId (required), packageName (required), apkVersionCode (required), +1 more.
external_transactions_createC
Register a new external transaction (Alternative Billing).
Inputs: parent (required), transaction (required), externalTransactionId (required).
external_transactions_getC
Get an external transaction (Alternative Billing).
Inputs: parent (required), externalTransactionId (required).
external_transactions_refundC
Report a refund on an external transaction.
Inputs: parent (required), refund (required), externalTransactionId (required).
generated_apks_downloadA
Download a specific generated APK. downloadId is the id from generated_apks_list. Returns the binary as a base64 string.
Inputs: downloadId (required), packageName (required), versionCode (required).
generated_apks_listA
List generated (split + standalone) APKs for a given bundle versionCode.
Inputs: packageName (required), versionCode (required).
grants_createA
Grant a user access to one app. parent is developers/{dev}/users/{user}. Grant body contains packageName + appLevelPermissions.
Inputs: grant (required), parent (required).
grants_deleteC
Revoke a grant.
Inputs: name (required).
grants_updateC
Patch a grant (change appLevelPermissions).
Inputs: name (required), grant (required), updateMask.
images_deleteC
Delete a single image by id.
Inputs: editId (required), imageId (required), language (required), imageType (required), +1 more.
images_delete_allB
Delete every image of a given type in one locale.
Inputs: editId (required), language (required), imageType (required), packageName (required).
images_listB
List uploaded images for a specific type and locale.
Inputs: editId (required), language (required), imageType (required), packageName (required).
images_uploadB
Upload a new image. file is a local filesystem path. MIME is auto-detected from extension (png/jpg).
Inputs: file (required), editId (required), language (required), imageType (required), +1 more.
internal_app_sharing_upload_apkB
Upload an APK for internal app sharing. Returns a link you can distribute internally.
Inputs: file (required), packageName (required).
internal_app_sharing_upload_bundleC
Upload an AAB for internal app sharing.
Inputs: file (required), packageName (required).
listings_deleteC
Delete the listing for one locale.
Inputs: editId (required), language (required), packageName (required).
listings_delete_allA
Delete ALL locale listings in this edit. Irreversible within the edit.
Inputs: editId (required), packageName (required).
listings_getC
Get one locale's listing.
Inputs: editId (required), language (required), packageName (required).
listings_listB
List every locale listing within an edit.
Inputs: editId (required), packageName (required).
listings_patchC
Partial update — unspecified fields preserved.
Inputs: editId (required), language (required), packageName (required), title, +3 more.
listings_updateB
Full replacement update of a locale listing. Fields: title (30), shortDescription (80), fullDescription (4000), video (YouTube URL).
Inputs: editId (required), language (required), packageName (required), title, +3 more.
monetization_convert_region_pricesA
Utility: convert a price in one region to comparable prices in every other region. Use before setting prices on a base plan.
Inputs: price (required), packageName (required).
onetime_product_offers_batch_deleteC
Delete up to 100 offers.
Inputs: requests (required), productId (required), packageName (required), purchaseOptionId (required).
onetime_product_offers_batch_getC
Batch-get up to 100 offers.
Inputs: requests (required), productId (required), packageName (required), purchaseOptionId (required).
onetime_product_offers_batch_updateB
Batch-update up to 100 offers (creates or updates).
Inputs: requests (required), productId (required), packageName (required), purchaseOptionId (required).
onetime_product_offers_batch_update_statesC
Activate/deactivate/cancel up to 100 offers.
Inputs: requests (required), productId (required), packageName (required), purchaseOptionId (required).
onetime_product_offers_getB
Get one offer on a purchase option.
Inputs: offerId (required), productId (required), packageName (required), purchaseOptionId (required).
onetime_product_offers_listB
List offers attached to a purchase option. purchaseOptionId is required — use '-' to list across all options.
Inputs: productId (required), packageName (required), purchaseOptionId (required), pageSize, +1 more.
onetime_product_purchase_options_batch_deleteC
Delete up to 100 purchase options.
Inputs: requests (required), productId (required), packageName (required).
onetime_product_purchase_options_batch_updateC
Update or create up to 100 purchase options for a one-time product.
Inputs: requests (required), productId (required), packageName (required).
onetime_product_purchase_options_batch_update_statesC
Activate or deactivate up to 100 purchase options in one call.
Inputs: requests (required), productId (required), packageName (required).
onetime_products_batch_deleteC
Delete up to 100 one-time products in one call.
Inputs: requests (required), packageName (required).
onetime_products_batch_getB
Fetch up to 100 one-time products in one call.
Inputs: productIds (required), packageName (required).
onetime_products_batch_updateC
Update up to 100 one-time products in one call.
Inputs: requests (required), packageName (required).
onetime_products_createB
Create a one-time product. Pass the full OneTimeProduct body.
Inputs: product (required), productId (required), packageName (required), regionsVersion.
onetime_products_deleteC
Delete a one-time product.
Inputs: productId (required), packageName (required), latencyTolerance.
onetime_products_getB
Get a single one-time product.
Inputs: productId (required), packageName (required).
onetime_products_listC
List all one-time products.
Inputs: packageName (required), pageSize, pageToken.
onetime_products_updateC
Update a one-time product (patch semantics, with updateMask).
Inputs: product (required), productId (required), packageName (required), updateMask, +2 more.
orders_batch_getB
Get up to 100 orders in one call.
Inputs: orderIds (required), packageName (required).
orders_getB
Get one order by order id.
Inputs: orderId (required), packageName (required).
orders_listC
List orders within a time window. Returns OrderId, productId, purchase state, quantity, offerPhaseDetails.
Inputs: packageName (required), endTime, orderIds, pageToken, +2 more.
orders_refundB
Refund an order. Pass revoke=true to also cancel the entitlement (subscription) or consumable.
Inputs: orderId (required), packageName (required), revoke.
orders_review_refundA
Respond to a pending refund review (collaborative chargeback, 2026-07). Call within 24 hours of a PendingRefundReviewNotification. Supply refundPreference and optional usage evidence so Play can dispute the chargeback.
Inputs: orderId (required), packageName (required), refundPreference (required), pendingRefundToken (required), +3 more.
purchases_products_acknowledgeA
Acknowledge a one-time product purchase. Unacknowledged purchases are refunded by Play after 3 days.
Inputs: token (required), productId (required), packageName (required), developerPayload.
purchases_products_consumeA
Consume a consumable one-time product so the user can buy it again. Consuming also acknowledges the purchase.
Inputs: token (required), productId (required), packageName (required).
purchases_products_v2_getA
Get current state of a one-time product purchase. Supports multiple purchase options + offers (replaces legacy purchases.products).
Inputs: token (required), packageName (required).
purchases_subscriptions_acknowledgeB
Acknowledge a subscription purchase. 2025-11+ accepts optional externalAccountId for account-linking. (v1 endpoint retained for compatibility.)
Inputs: token (required), packageName (required), subscriptionId, developerPayload, +1 more.
purchases_subscriptions_v2_cancelC
Cancel a subscription (2025-09+). cancellationType: USER_REQUESTED, DEVELOPER_REQUESTED, or SYSTEM_INITIATED.
Inputs: token (required), packageName (required), cancellationType, cancelSurveyReason.
purchases_subscriptions_v2_deferA
Defer billing for a subscription (2026-01 supports subscriptions with add-ons too). Pass DeferralInfo with expectedExpiryTime + desiredExpiryTime.
Inputs: token (required), packageName (required), deferralInfo (required).
purchases_subscriptions_v2_getB
Get full state of a subscription purchase (SubscriptionPurchaseV2). Includes OfferPhase (2026), outOfAppPurchaseContext, latestSuccessfulOrderId, priceChangeState, priceStepUpConsentDetails.
Inputs: token (required), packageName (required).
purchases_subscriptions_v2_revokeC
Revoke a subscription (refund + terminate access). 2025-05 added itemBasedRefund option for per-item refunds.
Inputs: token (required), packageName (required), revocationContext.
purchases_voided_listB
List voided purchases (refunded/charged-back). Supports filtering by time range + voided source.
Inputs: packageName (required), type, token, endTime, +4 more.
reports_anomalies_listC
List detected anomalies across metric sets for an app.
Inputs: parent (required), filter, pageSize, pageToken.
reports_anon_rss_swap_memory_getC
Get anonymous RSS + swap memory usage metric-set metadata. Format: apps/{packageName}/anonRssAndSwapMemoryUsageMetricSet
Inputs: name (required).
reports_anon_rss_swap_memory_queryC
Query anonymous RSS + swap memory usage timeline.
Inputs: name (required), filter, metrics, pageSize, +4 more.
reports_anr_rate_getC
Get ANR-rate metric-set metadata.
Inputs: name (required).
reports_anr_rate_queryD
Query ANR-rate timeline.
Inputs: name (required), filter, metrics, pageSize, +4 more.
reports_apps_fetch_release_filter_optionsB
List the release-filter dimensions available for an app (version codes, track, staged rollout).
Inputs: name (required).
reports_apps_searchC
List every app the service account can access.
Inputs: pageSize, pageToken.
reports_bitmap_memory_getB
Get bitmap memory usage metric-set metadata. Format: apps/{packageName}/bitmapMemoryUsageMetricSet
Inputs: name (required).
reports_bitmap_memory_queryC
Query bitmap memory usage timeline.
Inputs: name (required), filter, metrics, pageSize, +4 more.
reports_crash_rate_getA
Get crash-rate metric-set metadata (available dimensions, metrics, freshness).
Inputs: name (required).
reports_crash_rate_queryB
Query crash-rate timeline with dimensions, metrics, filter.
Inputs: name (required), filter, metrics, pageSize, +4 more.
reports_errors_counts_getC
Get error-counts metric-set metadata.
Inputs: name (required).
reports_errors_counts_queryC
Query aggregated error-count timelines.
Inputs: name (required), filter, metrics, pageSize, +4 more.
reports_errors_issues_searchC
Search grouped error issues (ErrorIssue).
Inputs: parent (required), filter, interval, pageSize, +1 more.
reports_errors_reports_searchC
Search raw error reports (ErrorReport) within an issue or time window.
Inputs: parent (required), filter, interval, pageSize, +1 more.
reports_excessive_wakeup_rate_getC
Get excessive-wake-up-rate metadata.
Inputs: name (required).
reports_excessive_wakeup_rate_queryC
Query excessive-wake-up-rate timeline.
Inputs: name (required), filter, metrics, pageSize, +4 more.
reports_lmk_rate_getC
Get Low-Memory-Killer (LMK) rate metadata.
Inputs: name (required).
reports_lmk_rate_queryC
Query LMK-rate timeline.
Inputs: name (required), filter, metrics, pageSize, +4 more.
reports_slow_rendering_rate_getC
Get slow-rendering-rate metadata.
Inputs: name (required).
reports_slow_rendering_rate_queryC
Query slow-rendering-rate timeline.
Inputs: name (required), filter, metrics, pageSize, +4 more.
reports_slow_start_rate_getC
Get slow-start-rate metadata.
Inputs: name (required).
reports_slow_start_rate_queryD
Query slow-start-rate timeline.
Inputs: name (required), filter, metrics, pageSize, +4 more.
reports_stuck_background_wake_lock_rate_getC
Get stuck-background-wake-lock-rate metadata.
Inputs: name (required).
reports_stuck_background_wake_lock_rate_queryC
Query stuck-background-wake-lock-rate timeline.
Inputs: name (required), filter, metrics, pageSize, +4 more.
reviews_getC
Get a single review by id.
Inputs: reviewId (required), packageName (required), translationLanguage.
reviews_listB
List reviews from the last 7 days. Use token from the previous page for pagination. Optional filters: language, translationLanguage, device.
Inputs: packageName (required), token, maxResults, startIndex, +1 more.
reviews_replyA
Post a public reply to a review. Replies can be edited by calling this again.
Inputs: reviewId (required), replyText (required), packageName (required).
subscription_base_plans_activateC
Activate a base plan — starts making it available for purchase.
Inputs: productId (required), basePlanId (required), packageName (required).
subscription_base_plans_batch_migrate_pricesB
Migrate prices on up to 100 base plans in one call.
Inputs: requests (required), productId (required), packageName (required).
subscription_base_plans_batch_updateC
Upsert up to 100 base plans.
Inputs: requests (required), productId (required), packageName (required).
subscription_base_plans_batch_update_statesC
Activate/deactivate up to 100 base plans.
Inputs: requests (required), productId (required), packageName (required).
subscription_base_plans_deactivateA
Deactivate a base plan — no new purchases; existing subscribers unaffected.
Inputs: productId (required), basePlanId (required), packageName (required).
subscription_base_plans_deleteA
Delete a base plan (must be inactive).
Inputs: productId (required), basePlanId (required), packageName (required).
subscription_base_plans_migrate_pricesC
Apply a price change to existing subscribers of a base plan in specific regions.
Inputs: productId (required), basePlanId (required), packageName (required), regionalPriceMigrations (required), +2 more.
subscription_offers_activateC
Activate an offer — starts making it available for purchase.
Inputs: offerId (required), productId (required), basePlanId (required), packageName (required).
subscription_offers_batch_getC
Batch-get up to 100 offers.
Inputs: requests (required), productId (required), basePlanId (required), packageName (required).
subscription_offers_batch_updateC
Upsert up to 100 offers.
Inputs: requests (required), productId (required), basePlanId (required), packageName (required).
subscription_offers_batch_update_statesC
Activate/deactivate up to 100 offers.
Inputs: requests (required), productId (required), basePlanId (required), packageName (required).
subscription_offers_createB
Create an offer on a base plan (free trial, intro pricing, etc.).
Inputs: offer (required), offerId (required), productId (required), basePlanId (required), +2 more.
subscription_offers_deactivateC
Deactivate an offer.
Inputs: offerId (required), productId (required), basePlanId (required), packageName (required).
subscription_offers_deleteD
Delete an offer.
Inputs: offerId (required), productId (required), basePlanId (required), packageName (required).
subscription_offers_getC
Get a single offer.
Inputs: offerId (required), productId (required), basePlanId (required), packageName (required).
subscription_offers_listA
List offers for a base plan. basePlanId supports '-' wildcard to list across all.
Inputs: productId (required), basePlanId (required), packageName (required), pageSize, +1 more.
subscription_offers_updateC
Patch-update an offer.
Inputs: offer (required), offerId (required), productId (required), basePlanId (required), +5 more.
subscriptions_archiveA
Archive a subscription. Archived subscriptions are hidden from new purchases but existing subscribers keep access.
Inputs: productId (required), packageName (required).
subscriptions_batch_getB
Get up to 100 subscriptions in one call.
Inputs: productIds (required), packageName (required).
subscriptions_batch_updateC
Update up to 100 subscriptions in one call.
Inputs: requests (required), packageName (required).
subscriptions_createC
Create a subscription.
Inputs: productId (required), packageName (required), subscription (required), regionsVersion.
subscriptions_deleteA
Delete a subscription. Only works on subscriptions with no active base plans/offers.
Inputs: productId (required), packageName (required), latencyTolerance.
subscriptions_getC
Get a single subscription.
Inputs: productId (required), packageName (required).
subscriptions_listC
List all subscriptions.
Inputs: packageName (required), pageSize, pageToken, showArchived.
subscriptions_updateB
Patch-update a subscription. Pass updateMask to limit the fields updated.
Inputs: productId (required), packageName (required), subscription (required), updateMask, +3 more.
system_apks_variants_createC
Create a new system APK variant for a versionCode.
Inputs: variant (required), packageName (required), versionCode (required).
system_apks_variants_downloadC
Download a built system APK variant. Returns base64.
Inputs: variantId (required), packageName (required), versionCode (required).
system_apks_variants_getC
Get a system APK variant.
Inputs: variantId (required), packageName (required), versionCode (required).
system_apks_variants_listB
List system APK variants created for a given versionCode.
Inputs: packageName (required), versionCode (required).
testers_getB
Get the current tester allowlist for a track.
Inputs: track (required), editId (required), packageName (required).
testers_patchC
Partial update of the tester allowlist.
Inputs: track (required), editId (required), packageName (required), googleGroups.
testers_updateB
Full replacement of the tester allowlist.
Inputs: track (required), editId (required), packageName (required), googleGroups.
tracks_createA
Create a brand-new custom closed-testing track. The new id is set on the server. Type can only be closedTesting.
Inputs: track (required), editId (required), packageName (required), type, +1 more.
tracks_getB
Get one track — includes all releases currently staged.
Inputs: track (required), editId (required), packageName (required).
tracks_listA
List every track visible in this edit (includes default internal/alpha/beta/production + any custom closed-testing tracks).
Inputs: editId (required), packageName (required).
tracks_patchC
Partial update of track state.
Inputs: track (required), editId (required), releases (required), packageName (required).
tracks_updateA
Full replacement of track state. releases is an array of release objects — versionCodes, status (draft|inProgress|halted|completed), userFraction (0-1 for staged rollout), inAppUpdatePriority (0-5), countryTargeting, and releaseNotes.
Inputs: track (required), editId (required), releases (required), packageName (required).
users_createB
Add a new team member to the developer account. Pass the user resource with email + roles + optional expirationTime.
Inputs: user (required), parent (required).
users_deleteB
Remove a user from the developer account.
Inputs: name (required).
users_listA
List all users on a developer account. parent is the developer account id in the form developers/{developerId} (find it in the Play Console URL).
Inputs: parent (required), pageSize, pageToken.
users_updateC
Patch-update a team member (roles, access level).
Inputs: name (required), user (required), updateMask.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 157 tools
The vast majority of tools use clear resource_action naming (e.g., subscriptions_create, tracks_patch, orders_refund), so boundaries are mostly clean. However, a few genuine overlaps exist, notably apps_list vs reports_apps_search (both 'list every app the account can access') and the dense family of subscriptions/onetime_products batch variants that an agent could easily confuse.
Strongly consistent snake_case with a resource_prefix_action pattern across nearly all 157 tools. Minor deviations like auth_status, monetization_convert_region_prices, and mixed onetime_products_/subscriptions_ prefixes (singular vs plural asymmetry) keep it from a perfect score.
157 tools is far beyond the 15-25 comfortable range and imposes heavy selection overhead even for a large API. The domain is genuinely broad so not an absolute mismatch, but the surface is bloated with many fine-grained batch/state variants that could be consolidated.
Coverage is remarkably thorough across accounts, apps, edits, listings, images, bundles/APKs, tracks, testers, products, subscriptions, base plans, offers, purchases, orders, reviews, users/grants, recovery, and reporting. Full CRUD plus batch and lifecycle state operations are present with few obvious dead ends.
Maintenance
Related MCP Connectors
Server-side purchase verification and entitlements for Google Play and Apple App Store over MCP.
MCP registry & directory: search, find & install 31k+ MCP servers & tools. Catalog and marketplace.
MCP server for Appcircle mobile CI/CD platform.
Hosted MCP server for GA4, Google Ads and Search Console. Google OAuth, nothing to install.
Related MCP Servers
- AlicenseAqualityBmaintenanceAn MCP server that connects to the Google Play Developer API to deploy apps, manage releases, respond to reviews, and monitor app health through an AI assistant.123134 PyPI32MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for managing Google Play app deployment and in-app products via the Android Publisher API v3.29 npm6MIT
- AlicenseNot gradedqualityDmaintenanceMCP server that connects AI assistants to the Google Play Developer API for automated app publishing, subscription management, review monitoring, and tester management.MIT
- AlicenseAqualityDmaintenanceAn MCP server that drives Google Play releases: bundle upload, track releases (internal/closed/open/production), listing metadata, store graphics, and review replies.8MIT