Ship a new Android app from chat. AI runs Google Play Console listings, screenshots, releases, uplo…
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Attach an already-uploaded artifact (version code) to a release — the required step between upload_bundle and start_rollout. Uploading a bundle does NOT attach it, so without this the release has no artifact and start_rollout refuses. Identify the artifact by artifact_id, or give version_code and it is looked up among the app's processed artifacts. Carries the release's existing name and notes forward untouched. Reads the release back afterwards and returns attach_verified plus the attached version codes rather than assuming success. This does NOT publish — call start_rollout for that, and confirm with the user first.
Numeric track id from list_tracks (the aliases "internal"/"production" are not accepted).
The release to attach to, from get_track or create_release.
Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name.
Numeric Play Console developer id (from the Play Console URL).
The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess.
Optional: the artifact id to attach. Omit and pass version_code instead to have it looked up.
Optional: version code of the uploaded bundle; used to find the artifact when artifact_id is omitted.
Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names.
This tool isn't marked read-only, so it may change something on the server or in an account you connected.
Pick your client. Values in capitals, like YOUR_TOKEN, are yours to fill in.
claude mcp add --transport http mcp-android_developer https://nova.civai.co/mcp/agents/mcp-android_developer
Attach an already-uploaded artifact (version code) to a release — the required step between upload_bundle and start_rollout. Uploading a bundle does NOT attach it, so without this the release has no artifact and start_rollout refuses. Identify the artifact by artifact_id, or give version_code and it is looked up among the app's processed artifacts. Carries the release's existing name and notes forward untouched. Reads the release back afterwards and returns attach_verified plus the attached version codes rather than assuming success. This does NOT publish — call start_rollout for that, and confirm with the user first.
| Argument | Type | Description |
|---|---|---|
| track_id* | string | Numeric track id from list_tracks (the aliases "internal"/"production" are not accepted). |
| release_id* | string | The release to attach to, from get_track or create_release. |
| artifact_id | string | Optional: the artifact id to attach. Omit and pass version_code instead to have it looked up. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| version_code | string | Optional: version code of the uploaded bundle; used to find the artifact when artifact_id is omitted. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"track_id",
"release_id"
],
"properties": {
"track_id": {
"type": "string",
"description": "Numeric track id from list_tracks (the aliases \"internal\"/\"production\" are not accepted)."
},
"release_id": {
"type": "string",
"description": "The release to attach to, from get_track or create_release."
},
"artifact_id": {
"type": "string",
"description": "Optional: the artifact id to attach. Omit and pass version_code instead to have it looked up."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"version_code": {
"type": "string",
"description": "Optional: version code of the uploaded bundle; used to find the artifact when artifact_id is omitted."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Check whether a package name is available before creating a new app. Derived from web decompile recon, not the official API — uses the Play Console web session, not the service account.
| Argument | Type | Description |
|---|---|---|
| developer_id* | string | Numeric Play Console developer id, from your console URL (play.google.com/console/u/N/developers/{this}/...). |
| package_name* | string | Target Android package name, e.g. com.example.myapp. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm the right one with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"package_name",
"google_account_email"
],
"properties": {
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id, from your console URL (play.google.com/console/u/N/developers/{this}/...)."
},
"package_name": {
"type": "string",
"description": "Target Android package name, e.g. com.example.myapp."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm the right one with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Create a brand-new Android app on Google Play — the one thing the official Android Publisher API cannot do. Derived from web decompile recon of Play Console's own client, not yet verified against a real call; uses the Play Console web session (browser_auth_profile.json), not the service account. Check package_name availability first.
| Argument | Type | Description |
|---|---|---|
| paid | boolean | Whether the app is paid. Default false. |
| app_type | string | APP_TYPE_APP or APP_TYPE_GAME. |
| app_class | string | PLAY_APP_CLASSIFICATION_UNSPECIFIED for a normal app (default), or EXTERNAL / THIRD_PARTY_APP_STORE / CREATOR. |
| app_title* | string | App title shown on the store listing. |
| developer_id* | string | Numeric Play Console developer id, from your console URL (play.google.com/console/u/N/developers/{this}/...). |
| package_name* | string | Target Android package name, e.g. com.example.myapp. |
| default_language* | string | Default app language, e.g. en-US. |
| us_law_compliant | boolean |
Create a new draft release on a track. Play Console allows only one draft release per track at a time — fails clearly if one already exists rather than guessing its id. Optionally sets a release_name (cosmetic label only).
| Argument | Type | Description |
|---|---|---|
| track_id* | string | Numeric track id (e.g. the long digits in the Play Console URL's .../tracks/<this>/..., not the human alias like "internal"). Call list_tracks first to find it. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| release_name | string | Optional cosmetic label for the release (not shown to users on Google Play). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
Declare whether the store listing's images were created or edited using AI. Play Console's listing editor has a second step ("Review") carrying this REQUIRED regulatory declaration, and until it is answered the listing stays Draft, the dashboard's store_listings task stays incomplete, and send_app_for_review refuses with a bare FAILED_PRECONDITION — however complete the listing content is. DRY-RUN BY DEFAULT. This is a statement to a regulator about who made the images: ask the user, never infer it.
| Argument | Type | Description |
|---|---|---|
| commit | string | "true" actually declares. Omit or "false" for a dry run that lists the assets it would mark. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| ai_declaration* | string | "not_ai_generated" (Play Console's "Don't label assets") or "ai_generated" ("Label assets as created or edited using AI"). Applies to every asset in the app's Asset Library, so confirm it is true of all of them. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message |
Read, or set, an app's Play App Signing enrolment. An app that is NOT enrolled CANNOT accept an .aab: upload_bundle returns 200 and Play then rejects the bundle during processing (error 3008), leaving a pending upload reference, no artifact, and an unexplained 400 from start_rollout. Call with action="status" first — that is read-only. Enrolment is PERMANENT, sets the app's signing identity for the life of the app and gives Google custody of the app signing key: get the user's explicit agreement to this specific action before enrolling, and ask whether Google should generate a fresh key or reuse another app's deployment key. There is no way to ship an .aab without it.
| Argument | Type | Description |
|---|---|---|
| action | string | "status" (default, read-only) or "enroll". |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| confirm_permanent | string | Required for action="enroll": must be exactly "yes". Only set it once the USER has agreed to this specific permanent change — not on a general approval to ship. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message |
Has this app ever been sent for Google Play review? ANSWERS WHAT get_pre_submit_status CANNOT: that tool reported review_eligible: true for an unreviewed draft app that could not publish by any route. An app that has never been reviewed cannot be rolled out to production at all. `ever_submitted_for_review` is the trustworthy field. The status codes are RAW AND UNMAPPED on purpose — a previous guess reported a live in-review submission as REJECTED — so do not read a verdict into them; Play Console's Publishing overview is the authority on the real state. If the submission history cannot be read, this returns submission_state_known: false rather than guessing 'never submitted'.
| Argument | Type | Description |
|---|---|---|
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email"
],
"properties": {
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Read-only: what Google Play still requires before this app is review-eligible. Reports each App Content declaration's state, the hub's blocking validation errors, the store listing's validation warnings, and whether the Publishing page considers the app blocked. review_eligible is conservative — if any source could not be read it is false and the unread source is listed in errors, so never report an app as clear on a partial answer.
| Argument | Type | Description |
|---|---|---|
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| store_listing_id | string | Numeric store listing id (0 for the main listing). Defaults to 0. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email"
],
"properties": {
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"store_listing_id": {
"type": "string",
"description": "Numeric store listing id (0 for the main listing). Defaults to 0."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Get a release's current state, including currently-attached artifacts and validation status — check this before start_rollout.
| Argument | Type | Description |
|---|---|---|
| track_id* | string | Numeric track id (e.g. the long digits in the Play Console URL's .../tracks/<this>/..., not the human alias like "internal"). Call list_tracks first to find it. |
| release_id* | string | Release id on this track, from create_release/get_track. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"track_id",
"release_id",
"google_account_email"
],
"properties": {
"track_id": {
"type": "string",
"description": "Numeric track id (e.g. the long digits in the Play Console URL's .../tracks/<this>/..., not the human alias like \"internal\"). Call list_tracks first to find it."
},
"release_id": {
"type": "string",
"description": "Release id on this track, from create_release/get_track."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Read the app dashboard's setup checklist. Returns which tasks are complete and which are still open (privacy_policy, app_access, ads, content_rating, target_audience, store_settings, store_listings, prod_countries, prod_release, ...). WARNING: the `incomplete` list is NOT a list of blockers — measured live, it listed 10 open tasks while Play Console's own Submit button was enabled and the app then submitted fine. It mixes real setup items with the action you are trying to take (*_sent_for_review), paths the app does not use (open_*, prereg_*) and consequences that only become true after review and rollout (prod_rollout, serving_in_prod). Still far better than get_pre_submit_status, which reads declarations and listing warnings only. For whether a submission can actually go through, use send_app_for_review's dry run (Play's `blocked` flag) or the Publishing overview. Read-only.
| Argument | Type | Description |
|---|---|---|
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
Get one release track's current state by track_id, including every release on that track with its release_id, name, status and lifecycle state. This is how you find an existing draft release's id after create_release refuses a second draft.
| Argument | Type | Description |
|---|---|---|
| track_id* | string | Numeric track id (e.g. the long digits in the Play Console URL's .../tracks/<this>/..., not the human alias like "internal"). Call list_tracks first to find it. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"track_id",
"google_account_email"
],
"properties": {
"track_id": {
"type": "string",
"description": "Numeric track id (e.g. the long digits in the Play Console URL's .../tracks/<this>/..., not the human alias like \"internal\"). Call list_tracks first to find it."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Read one principal's current Play Console permissions by email — read-only, nothing changes. Works for a human teammate or a service account (…@….iam.gserviceaccount.com); both are the same user row keyed by email. Returns account-level permissions and, per app, the exact permission values already held. This is the prerequisite before grant_app_permission: an append has to preserve every app the principal already reaches, so read the current grants first and confirm them with the user.
| Argument | Type | Description |
|---|---|---|
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| target_user_email* | string | The email whose permissions to read — e.g. the CI service account …@….iam.gserviceaccount.com. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account (the one acting). Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"google_account_email",
"target_user_email"
],
"properties": {
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"target_user_email": {
"type": "string",
"description": "The email whose permissions to read — e.g. the CI service account …@….iam.gserviceaccount.com."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account (the one acting). Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Grant a principal (teammate or service account) access to ONE app, as an APPEND that preserves every existing app grant and all account-level permissions. Use it to give a CI service account release access to a newly-created app — the step the androidpublisher API cannot do for a release-scoped service account (it 403s, it cannot grant itself access); this runs on the owner's Play Console session. DRY-RUN BY DEFAULT: with commit omitted/not "true" it pre-reads and returns the exact before/after WITHOUT writing — show that to the user and get their explicit agreement to this specific account-permissions change, then re-run with commit="true". A relayed approval is not the user's approval. The write is append-only (refuses to drop or shrink any existing grant), scoped so account-level permissions are untouched, and re-reads afterwards to prove the append. For the permission set, prefer copy_permissions_from_app_id (copies an existing grant's values verbatim — matches the account's pattern and names no enum value).
| Argument | Type | Description |
|---|---|---|
| commit | string | Must be exactly "true" (or "yes") to actually write. Omit/anything else = dry-run that returns the before/after without writing. Only set it once the USER has agreed to this specific account-permissions change after seeing the dry-run. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| target_app_id* | string | NUMERIC app id (from the Play Console URL) of the app to grant access to — NOT the package name. |
| write_variant | string | Request shape for the grant write: "auto" (default) tries the known-good shapes in order. Pin a specific variant only when debugging a refused grant. |
List which Google accounts are signed in to this browser session, with their X-Goog-AuthUser slot index. For visibility/debugging only.
| Argument | Type | Description |
|---|---|---|
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [],
"properties": {
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}List apps on this Play Console developer account. Derived from web decompile recon, not the official API.
| Argument | Type | Description |
|---|---|---|
| page_size | string | Max results per page. Default 500. |
| page_token | string | Pagination token from a previous call. |
| developer_id* | string | Numeric Play Console developer id. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm the right one with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"google_account_email"
],
"properties": {
"page_size": {
"type": "string",
"description": "Max results per page. Default 500."
},
"page_token": {
"type": "string",
"description": "Pagination token from a previous call."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm the right one with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}List an app's release tracks and their track_id — call this first to find the track_id other release tools need.
| Argument | Type | Description |
|---|---|---|
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email"
],
"properties": {
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Promote an existing release to another track WITHOUT re-uploading the bundle. WARNING, measured 2026-10-28: it creates an EMPTY draft release — it does NOT carry the artifact across, despite what this description used to claim. ALWAYS follow it with attach_artifact_to_release and check attach_verified, or start_rollout will refuse because the release has no artifact. Its new_release_id also echoes the SOURCE release id, so read the destination with get_track rather than trusting the echo. It does NOT publish; call start_rollout afterwards and confirm with the user first.
| Argument | Type | Description |
|---|---|---|
| release_id | string | Release id on the source track (from get_track/create_release). Pass this or version_code. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| version_code | string | Android version code of the build to promote; the release carrying it is looked up on the source track. Pass this or release_id. |
| source_track_id* | string | Numeric track id the release is on now. Call list_tracks first — the human alias ("internal") is not accepted. |
| destination_track_id* | string | Numeric track id to promote to. Call list_tracks first — the human alias ("production") is not accepted. |
Refresh the saved Play Console session in place, with no new browser sign-in. Google rotates the __Secure-1PSIDTS/__Secure-3PSIDTS session cookies about every 10 minutes; the captured copy goes stale and every tool then returns 401 UNAUTHENTICATED — or list_accounts returns an empty list — even though the user never signed out. Every tool already retries this automatically on a 401, so call it deliberately before a long sequence, or to tell a stale cookie apart from a session that has genuinely ended (if this succeeds and no account is signed in, only start_browser_auth will help).
| Argument | Type | Description |
|---|---|---|
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [],
"properties": {
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Send the app's pending changes to Google Play review — the API behind Play Console's "Send app for review". OUTWARD-FACING AND NOT FREELY REVERSIBLE: for an app that has never shipped this is the submission that decides whether it can be published at all. DRY-RUN BY DEFAULT — it reports what would be sent and sends nothing until commit="true". Confirm with the user first, exactly like start_rollout. It fetches the publishing page's continuation token itself and round-trips it, which is what Play actually requires; the dry run also reports Play's own `blocked` flag, the best machine-readable "can this be sent?" in this capture. A FAILED_PRECONDITION here is NOT reliably a setup-task problem — that was wrong for a whole session. Read the dry run's `publishing_page` block and Play Console's Publishing overview before blaming the app's state.
| Argument | Type | Description |
|---|---|---|
| commit | string | "true" actually submits. Omit or "false" for a dry run. Never pass "true" without the user's explicit agreement in this conversation. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| include_sections | string | Comma-separated non-track sections to include: store_listing, store_settings, app_content, preregistration, advanced_distribution. Mirrors the Publishing overview's own groups - include each group that shows pending changes. |
| review_behaviour | string |
Set up a track's testers: creates or updates a tester email list and attaches it to the track as an audience group. Google requires a personal developer account to run a closed test with a minimum tester count for a minimum number of days before it can even APPLY for production access — this starts that clock, and reports the live required-vs-current tester and day counts so the gap is a number. DRY-RUN BY DEFAULT.
| Argument | Type | Description |
|---|---|---|
| commit | string | "true" applies the change. Omit or "false" for a dry run. |
| track_id* | string | Numeric track id — call list_tracks first. Use the closed/alpha track for the production-access requirement. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| tester_emails | string | Comma-separated Google account emails of testers. Real accounts that will install the app — Play counts installs, not invitations. |
| tester_list_name | string | Name of the tester email list (default "Closed testers"). An existing list with this name is updated rather than duplicated. |
| google_account_email |
Open App Store Connect sign-in only when needed. If the saved session is still valid, this tool returns success immediately and does not open the viewer. Call session_status first. Use force_reconnect only when the user explicitly wants to wipe the saved cookie and sign in again (destructive).
| Argument | Type | Description |
|---|---|---|
| force_reconnect | boolean | DESTRUCTIVE: delete the saved session cookie for this tenant, then open the viewer for a fresh sign-in. Do not set true unless the user explicitly asks to sign out / reconnect / clear session. |
{
"type": "object",
"required": [],
"properties": {
"force_reconnect": {
"type": "boolean",
"description": "DESTRUCTIVE: delete the saved session cookie for this tenant, then open the viewer for a fresh sign-in. Do not set true unless the user explicitly asks to sign out / reconnect / clear session."
}
}
}Roll out a release — this IS Android's publish action for the release. Not simply reversible; always confirm with the user, especially on production. Preconditions it cannot satisfy itself: the release needs an artifact attached (attach_artifact_to_release — promote_release does NOT attach one), and the track needs at least one EXPLICITLY selected country (target_rest_of_world alone is not a selection — see update_track_countries). A bare FAILED_PRECONDITION here names nothing: open the Console's release review page (.../tracks/{track}/releases/{release}/review) and expand its errors, which is read-only and states the cause in one sentence. Production additionally requires the app to have passed review once.
| Argument | Type | Description |
|---|---|---|
| track_id* | string | Numeric track id (e.g. the long digits in the Play Console URL's .../tracks/<this>/..., not the human alias like "internal"). Call list_tracks first to find it. |
| release_id* | string | Release id on this track, from create_release/get_track. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| rollout_percentage | string | Percentage of users to roll out to, 0-100. Defaults to 100 (full rollout) if omitted. |
| targeted_countries |
Submit the production-access application questionnaire for a personal developer account. Only possible once the closed-testing tester/day requirement is met (see setup_closed_testing and get_setup_state). All ten answers are the developer's own words about their testing — never invent them. DRY-RUN BY DEFAULT.
| Argument | Type | Description |
|---|---|---|
| commit | string | "true" submits. Omit or "false" for a dry run. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| tester_feedback | string | What feedback testers gave (free text). |
| intended_audience | string | Who the app is for (free text). |
| tester_engagement | string | How testers engaged with the app (free text). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
Declare whether the app contains ads, using Play Console's own web session. Mandatory App content declaration required before a new app is eligible for production submission/review.
| Argument | Type | Description |
|---|---|---|
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| contains_ads* | string | "true" if the app shows ads, "false" otherwise. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"contains_ads"
],
"properties": {
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"contains_ads": {
"type": "string",
"description": "\"true\" if the app shows ads, \"false\" otherwise."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Submit and apply the mandatory IARC content rating questionnaire, using Play Console's own web session. Only content_rating_category="all_other_app_types" (every question answered No, producing the lowest possible rating) is currently supported — the correct choice for a brand-new app with no mature content.
| Argument | Type | Description |
|---|---|---|
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
| content_rating_category* | string | Must be "all_other_app_types" — the only supported value right now. Games and Social/Communication apps need a different questionnaire path not yet supported. |
| content_rating_contact_email* | string | Contact email for content rating authorities / IARC correspondence. |
Submit the Data safety declaration. data_collection="none" declares the app collects and shares NO user data; data_collection="collects" files the per-data-type questionnaire from data_types. REQUIRES update_privacy_policy to have been called first. This is a public, legally-meaningful statement about the app: "none" is a FALSE declaration for any app that collects anything at all, including a push notification token, so confirm what the app actually collects with the user rather than assuming. Nothing is defaulted on your behalf — an unknown data type or a missing purpose is refused, not approximated. An app where users can sign up must also answer the account section (questions 92-96); pass the real account_creation_methods plus the deletion URLs rather than defaulting to "none", which publicly declares the app has no sign-up.
| Argument | Type | Description |
|---|---|---|
| data_types | string | Required when data_collection="collects". JSON array, one object per data type the app collects or shares: {"type": <data type>, "collected": bool, "shared": bool, "ephemeral": bool, "required": bool, "collection_purposes": [...], "sharing_purposes": [...]}. "required" means users cannot use the app without providing it. Purposes: app_functionality, analytics, developer_communications, fraud_prevention_and_security, advertising_or_marketing, personalization, account_management. Data types include name, email_address, phone_number, physical_address, user_ids, purchase_history, payment_info, device_or_other_ids, approximate_location, precise_location, photos, videos, contacts, crash_logs, diagnostics, app_interactions, installed_apps, files_and_docs, health_info, fitness_info — the tool's error detail lists the full set if one is rejected. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* |
Declare 'none of the above' for a multi-select feature-checklist App content declaration, using Play Console's own web session. Mandatory declarations. Currently supports none_option_declaration="financial_features" (does the app provide any financial features?) or "health" (does the app use any health features?). Only the 'none apply' answer is supported.
| Argument | Type | Description |
|---|---|---|
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
| none_option_declaration* | string | Which declaration to set: "financial_features" or "health". Other values are not supported. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"none_option_declaration"
],
"properties": {
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
},
"none_option_declaration": {
"type": "string",
"description": "Which declaration to set: \"financial_features\" or \"health\". Other values are not supported."
}
}
}Set a simple Yes/No App content policy declaration, using Play Console's own web session. Mandatory declaration gating production submission eligibility. Currently supports policy_declaration="advertising_id" (does the app use advertising ID?) or "government_app" (is this app developed by or on behalf of a government?).
| Argument | Type | Description |
|---|---|---|
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| policy_declaration* | string | Which declaration to set: "advertising_id" or "government_app". Other App content declarations (data safety, content rating, target audience, ads, sign in details, financial features, health) have their own tools or are not yet supported. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
| policy_declaration_answer* | string |
Set the app's privacy policy URL, using Play Console's own web session. Mandatory App content declaration, and a prerequisite for submitting the Data safety declaration.
| Argument | Type | Description |
|---|---|---|
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| privacy_policy_url* | string | A real, publicly accessible URL (http:// or https://) to the app's privacy policy page. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"privacy_policy_url"
],
"properties": {
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"privacy_policy_url": {
"type": "string",
"description": "A real, publicly accessible URL (http:// or https://) to the app's privacy policy page."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Declare whether any part of the app is restricted (requires account sign-in, payment, referral/QR codes, OTP, biometrics, or actions on another device). Formerly 'App access'. Mandatory App content declaration and one of the app-dashboard setup tasks that gate send_app_for_review. Both answers are supported: "false" is live-verified; "true" attaches reviewer credentials and its wire shape is derived from Play Console's own bundle but not yet live-verified — check the App access page after filing one.
| Argument | Type | Description |
|---|---|---|
| credentials | string | Required when is_restricted="true". JSON array, one object per test account Play's reviewer should use: [{"name": "Checkout account", "username": "...", "password": "...", "credential_type": "email"|"username"|"phone_number"|"otp"|"other", "additional_details": "any steps the reviewer needs"}]. Ask the user for a REAL working test account — never invent credentials, and never reuse a personal login. Passwords are redacted from this tool's output but are sent to Play. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| is_restricted* | string | "false" if every part of the app works without signing in or paying. "true" if ANY functionality is behind a login, payment, OTP, referral code, biometrics or an action on another device — then `credentials` is required so Play's reviewer can get in. This is a declaration Google acts on: filing "false" for an app with gated content is a false declaration and a common rejection reason. Ask the user; don't infer it from the code. |
Update an app's main store listing (title, short/full description) for one language using Play Console's own web session. Does NOT need create_edit/commit_edit — it patches the listing directly. On an app whose language has no listing entry yet this CREATES the entry (verified live), so it is the first call before attaching any graphic. Note the PATCH replaces the whole entry for that language, so title, short_description and full_description must all be supplied together.
| Argument | Type | Description |
|---|---|---|
| title* | string | App title for this language. |
| language* | string | BCP-47 language code for the listing, e.g. en-US. |
| save_mode | string | "save" COMMITS the listing (what Play Console's own Save button does); "draft" (the DEFAULT) writes only the draft copy. **Pass "save" for any listing that has to count toward release.** With the default, the app dashboard's `store_listings` task never completes no matter how complete the content is, and send_app_for_review stays blocked - measured live, and no amount of content or validation_mode=full fixes it. "draft" is for staging text you are not ready to commit. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| validation_mode |
Reorder or remove an app's existing store-listing screenshots for one language. Preserves the listing's title/descriptions untouched. Can ONLY reorder/remove already-uploaded screenshots (matched by URL) — cannot add a brand-new screenshot image.
| Argument | Type | Description |
|---|---|---|
| language* | string | BCP-47 language code for the listing, e.g. en-US. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| screenshot_urls* | string | JSON array of the EXISTING screenshot URLs, in the desired final order (omit a URL to remove that screenshot). Every URL must already be present in the listing — this tool cannot add new images. |
| store_listing_id* | string | Numeric store listing id from the Play Console store listing URL (0 for the main listing). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
Set the app's store category and public contact details — one of the app dashboard setup tasks that gates send_app_for_review. Until it is done Play refuses the review submission with a bare FAILED_PRECONDITION and Play Console's own Send-for-review button stays greyed out. The contact details are PUBLIC on the store listing. Derived from Play Console's own bundle; not yet live-verified.
| Argument | Type | Description |
|---|---|---|
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| app_category | string | Store category, lower_snake_case: shopping, food_and_drink, business, lifestyle, social, finance, health_and_fitness, education, entertainment, productivity, travel_and_local, photography, music_and_audio, news_and_magazines, books_and_reference, tools, dating, beauty, events, parenting, medical, weather, maps_and_navigation, personalization, art_and_design, auto_and_vehicles, house_and_home, comics, communication, sports, video_players, libraries_and_demo. Decides where the app is listed — ask the user. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| contact_email | string | PUBLIC support email shown on the store listing. Confirm it with the user; don't reuse an internal address by reflex. |
| contact_phone | string | Optional public support phone number. |
| contact_website |
Declare the app's target audience & content, using Play Console's own web session. Mandatory App content declaration. Only target_audience="adults" (18 and over only, not aimed at children) is currently supported — the correct, simplest answer for an app with no child-directed content.
| Argument | Type | Description |
|---|---|---|
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| target_audience* | string | Must be "adults" (18 and over only, not aimed at children) — the only supported value right now. Any other value is not yet implemented and will return an error. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"target_audience"
],
"properties": {
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"target_audience": {
"type": "string",
"description": "Must be \"adults\" (18 and over only, not aimed at children) — the only supported value right now. Any other value is not yet implemented and will return an error."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}Set which countries/regions a release track serves — the precondition for a track's first rollout. CRITICAL, measured 2026-10-28: pass at least one explicit targeted_countries value. target_rest_of_world="true" ALONE writes the rest-of-world flag and leaves the country list empty, and Play's release validator then refuses every rollout with "No countries or regions have been selected for this track" — surfacing from start_rollout as a bare FAILED_PRECONDITION with no detail, while get_setup_state still reports closed_countries/prod_countries as complete. For a worldwide launch pass one real market in targeted_countries AND target_rest_of_world="true". Does not publish anything. Ask the user which countries; never pick for them.
| Argument | Type | Description |
|---|---|---|
| track_id* | string | Numeric track id — call list_tracks first. Not the alias like "production". |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| targeted_countries | string | Comma-separated ISO 3166-1 alpha-2 codes, e.g. "NG,GH,KE". These are the countries the app becomes downloadable in. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
Upload a signed .aab. IMPORTANT: uploading does NOT attach the artifact to the release — it only becomes an app-level artifact (visible with its own version code) while the release's addedArtifacts stays empty, so start_rollout would have nothing to roll out. Call attach_artifact_to_release next, then get_release to check signing/content validation, then start_rollout. This call only confirms the bytes arrived and that Play accepted the bundle for processing.
| Argument | Type | Description |
|---|---|---|
| track_id* | string | Numeric track id (e.g. the long digits in the Play Console URL's .../tracks/<this>/..., not the human alias like "internal"). Call list_tracks first to find it. |
| bundle_url | string | https URL the replay host downloads the signed .aab from — the route for a bundle built on your own machine, since bundle_path only sees files already on the replay host. Must be publicly resolvable. |
| release_id* | string | Release id on this track, from create_release/get_track. |
| bundle_path | string | Absolute path ON THE REPLAY HOST, inside the secops container (repo root = /app). Only usable if you can already put files there — most operators cannot, so prefer bundle_url. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string |
Upload an image into the app's Asset Library. NOTE: for store listing graphics use upload_store_listing_graphic instead — the Asset Library's image cannot be attached to a listing slot (it lacks the blobKey the listing requires, confirmed live). This tool is only for getting an image into the Asset Library itself.
| Argument | Type | Description |
|---|---|---|
| image_url | string | https URL the replay host fetches the image from — the route for anything over the base64 cap. Must be publicly resolvable (a URL that resolves to a private address is refused). |
| image_path | string | Absolute path ON THE REPLAY HOST, inside the secops container (repo root = /app). Only usable if you can already put files there — most operators cannot, so prefer image_base64 or image_url. |
| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| image_base64 | string | The image's bytes as base64 (a data: URI prefix is fine) — the route that needs no file on the replay host and no hosting at all. Capped at 64 KiB of image because CLI steps receive their arguments in one environment variable and Linux caps that at 128 KiB; anything larger must use image_url. A 512x512 icon usually fits, a full-resolution screenshot usually does not. |
| google_account_email |
Upload an image AND attach it to a store-listing slot in one call — phone screenshot, feature graphic or app icon. This is what makes a store listing completable from here; upload_screenshot_asset only gets an image into the Asset Library and CANNOT attach it. Play requires at least 2 phone screenshots plus a feature graphic and an icon for a complete listing, so call this once per image. Preserves the listing's existing text and other graphics, and refuses rather than risking a partial overwrite. Give the image ONE of three ways: image_base64 (inline bytes, no hosting needed, 64 KiB cap), image_url (https, any size) or image_path (replay host only).
| Argument | Type | Description |
|---|---|---|
| language* | string | BCP-47 language code of the listing to attach into, e.g. en-US. The listing must already have text for this language (update_store_listing creates it). |
| image_url | string | https URL the replay host fetches the image from — the route for anything over the base64 cap. Must be publicly resolvable (a URL that resolves to a private address is refused). |
| image_path | string | Absolute path ON THE REPLAY HOST, inside the secops container (repo root = /app). Only usable if you can already put files there — most operators cannot, so prefer image_base64 or image_url. |
| image_type* | string | Which slot: "phone_screenshot", "feature_graphic" (must be exactly 1024x500) or "icon" (must be exactly 512x512). |
| attach_mode | string | For phone_screenshot only: "append" (default) adds alongside existing screenshots, "replace" makes it the only one. Ignored for feature_graphic and icon, which are single-image slots. |
We read every tool's name, description and inputs the way the model will, looking for instructions hidden from you. A clean result means no warning signs, not a guarantee. Scanned Nov 2, 2026.
Takes a password, API key or token as an argument, so the secret passes through the model's context and chat logs.
Fix: Read credentials from the server's own configuration (environment, OAuth) instead of a tool argument.
No readOnlyHint / destructiveHint annotations, so clients can't tell a read from a write without asking.
Fix: Add annotations to each tool, e.g. { readOnlyHint: true } for tools that only read.
| Confirms US law compliance. Default true. |
| app_meets_guidelines | boolean | Confirms the app meets Play policy guidelines. Default true. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm the right one with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
| distributes_on_android | boolean | Whether the app distributes on Android. Default true. |
| distributes_on_windows | boolean | Whether the app also distributes on Windows. Default false. |
{
"type": "object",
"required": [
"developer_id",
"package_name",
"app_title",
"default_language",
"google_account_email"
],
"properties": {
"paid": {
"type": "boolean",
"description": "Whether the app is paid. Default false."
},
"app_type": {
"type": "string",
"description": "APP_TYPE_APP or APP_TYPE_GAME."
},
"app_class": {
"type": "string",
"description": "PLAY_APP_CLASSIFICATION_UNSPECIFIED for a normal app (default), or EXTERNAL / THIRD_PARTY_APP_STORE / CREATOR."
},
"app_title": {
"type": "string",
"description": "App title shown on the store listing."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id, from your console URL (play.google.com/console/u/N/developers/{this}/...)."
},
"package_name": {
"type": "string",
"description": "Target Android package name, e.g. com.example.myapp."
},
"default_language": {
"type": "string",
"description": "Default app language, e.g. en-US."
},
"us_law_compliant": {
"type": "boolean",
"description": "Confirms US law compliance. Default true."
},
"app_meets_guidelines": {
"type": "boolean",
"description": "Confirms the app meets Play policy guidelines. Default true."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm the right one with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
},
"distributes_on_android": {
"type": "boolean",
"description": "Whether the app distributes on Android. Default true."
},
"distributes_on_windows": {
"type": "boolean",
"description": "Whether the app also distributes on Windows. Default false."
}
}
}{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"track_id",
"google_account_email"
],
"properties": {
"track_id": {
"type": "string",
"description": "Numeric track id (e.g. the long digits in the Play Console URL's .../tracks/<this>/..., not the human alias like \"internal\"). Call list_tracks first to find it."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"release_name": {
"type": "string",
"description": "Optional cosmetic label for the release (not shown to users on Google Play)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}| string |
| Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"ai_declaration"
],
"properties": {
"commit": {
"type": "string",
"description": "\"true\" actually declares. Omit or \"false\" for a dry run that lists the assets it would mark."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"ai_declaration": {
"type": "string",
"description": "\"not_ai_generated\" (Play Console's \"Don't label assets\") or \"ai_generated\" (\"Label assets as created or edited using AI\"). Applies to every asset in the app's Asset Library, so confirm it is true of all of them."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}| string |
| Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
| reuse_deployment_key_app_id | string | Optional: numeric play_app_id of an existing app whose deployment key this app should share. Leave empty for Google to generate a fresh signing key, which is the right default unless the apps genuinely need a shared signing identity. The user's call. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email"
],
"properties": {
"action": {
"type": "string",
"description": "\"status\" (default, read-only) or \"enroll\"."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"confirm_permanent": {
"type": "string",
"description": "Required for action=\"enroll\": must be exactly \"yes\". Only set it once the USER has agreed to this specific permanent change — not on a general approval to ship."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
},
"reuse_deployment_key_app_id": {
"type": "string",
"description": "Optional: numeric play_app_id of an existing app whose deployment key this app should share. Leave empty for Google to generate a fresh signing key, which is the right default unless the apps genuinely need a shared signing identity. The user's call."
}
}
}{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email"
],
"properties": {
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}| permission_values | string | Alternative to copy_permissions_from_app_id: a JSON array of integer permission values for a least-privilege set, e.g. "[1,6]" (CAN_ACCESS_APP, CAN_MANAGE_TRACK_APKS — upload + testing-track release). |
| target_user_email* | string | The principal being granted access — e.g. the CI service account …@….iam.gserviceaccount.com. Must already exist on the account. |
| google_account_email* | string | The signed-in owner account email that is acting. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
| copy_permissions_from_app_id | string | Preferred: numeric app id of an app the principal ALREADY has, whose permission values are copied verbatim onto the new grant. Matches the existing pattern and avoids naming any enum value. |
{
"type": "object",
"required": [
"developer_id",
"google_account_email",
"target_user_email",
"target_app_id"
],
"properties": {
"commit": {
"type": "string",
"description": "Must be exactly \"true\" (or \"yes\") to actually write. Omit/anything else = dry-run that returns the before/after without writing. Only set it once the USER has agreed to this specific account-permissions change after seeing the dry-run."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"target_app_id": {
"type": "string",
"description": "NUMERIC app id (from the Play Console URL) of the app to grant access to — NOT the package name."
},
"write_variant": {
"type": "string",
"description": "Request shape for the grant write: \"auto\" (default) tries the known-good shapes in order. Pin a specific variant only when debugging a refused grant."
},
"permission_values": {
"type": "string",
"description": "Alternative to copy_permissions_from_app_id: a JSON array of integer permission values for a least-privilege set, e.g. \"[1,6]\" (CAN_ACCESS_APP, CAN_MANAGE_TRACK_APKS — upload + testing-track release)."
},
"target_user_email": {
"type": "string",
"description": "The principal being granted access — e.g. the CI service account …@….iam.gserviceaccount.com. Must already exist on the account."
},
"google_account_email": {
"type": "string",
"description": "The signed-in owner account email that is acting. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
},
"copy_permissions_from_app_id": {
"type": "string",
"description": "Preferred: numeric app id of an app the principal ALREADY has, whose permission values are copied verbatim onto the new grant. Matches the existing pattern and avoids naming any enum value."
}
}
}| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"source_track_id",
"destination_track_id"
],
"properties": {
"release_id": {
"type": "string",
"description": "Release id on the source track (from get_track/create_release). Pass this or version_code."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"version_code": {
"type": "string",
"description": "Android version code of the build to promote; the release carrying it is looked up on the source track. Pass this or release_id."
},
"source_track_id": {
"type": "string",
"description": "Numeric track id the release is on now. Call list_tracks first — the human alias (\"internal\") is not accepted."
},
"destination_track_id": {
"type": "string",
"description": "Numeric track id to promote to. Call list_tracks first — the human alias (\"production\") is not accepted."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}| "review_immediately" (default) or "queue_for_review". |
| include_track_ids | string | Comma-separated numeric track ids whose pending changes this submission covers (AppChangesToInclude.trackIds). Play Console always sends this selection; with neither this nor a section list the server has an empty selection and answers FAILED_PRECONDITION. To submit everything pending, pass every track that has pending changes on the Publishing overview. |
| number_of_changes | string | The number of pending changes being submitted, exactly as Play Console's own "Submit N changes for review" button reads it. REQUIRED IN PRACTICE: Play treats this as a confirmation count and answers FAILED_PRECONDITION when it is missing, even when the Console's own button is enabled on the same pending set. Read N from the Publishing overview; do not guess. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
| publishing_behaviour | string | "automatic" (default — changes go live as soon as review passes) or "manual" (hold for a manual go-live). Confirm which the user wants. |
| send_session_headers | string | Diagnostic only. "true" also sends the Console's own X-Play-Console-Session-Id and Accept-Language headers. Measured 2026-10-28: these are NOT required - the submission succeeds without them. Leave unset unless a write is refused for a reason the payload cannot explain. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email"
],
"properties": {
"commit": {
"type": "string",
"description": "\"true\" actually submits. Omit or \"false\" for a dry run. Never pass \"true\" without the user's explicit agreement in this conversation."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"include_sections": {
"type": "string",
"description": "Comma-separated non-track sections to include: store_listing, store_settings, app_content, preregistration, advanced_distribution. Mirrors the Publishing overview's own groups - include each group that shows pending changes."
},
"review_behaviour": {
"type": "string",
"description": "\"review_immediately\" (default) or \"queue_for_review\"."
},
"include_track_ids": {
"type": "string",
"description": "Comma-separated numeric track ids whose pending changes this submission covers (AppChangesToInclude.trackIds). Play Console always sends this selection; with neither this nor a section list the server has an empty selection and answers FAILED_PRECONDITION. To submit everything pending, pass every track that has pending changes on the Publishing overview."
},
"number_of_changes": {
"type": "string",
"description": "The number of pending changes being submitted, exactly as Play Console's own \"Submit N changes for review\" button reads it. REQUIRED IN PRACTICE: Play treats this as a confirmation count and answers FAILED_PRECONDITION when it is missing, even when the Console's own button is enabled on the same pending set. Read N from the Publishing overview; do not guess."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
},
"publishing_behaviour": {
"type": "string",
"description": "\"automatic\" (default — changes go live as soon as review passes) or \"manual\" (hold for a manual go-live). Confirm which the user wants."
},
"send_session_headers": {
"type": "string",
"description": "Diagnostic only. \"true\" also sends the Console's own X-Play-Console-Session-Id and Accept-Language headers. Measured 2026-10-28: these are NOT required - the submission succeeds without them. Leave unset unless a write is refused for a reason the payload cannot explain."
}
}
}| string |
| The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"track_id"
],
"properties": {
"commit": {
"type": "string",
"description": "\"true\" applies the change. Omit or \"false\" for a dry run."
},
"track_id": {
"type": "string",
"description": "Numeric track id — call list_tracks first. Use the closed/alpha track for the production-access requirement."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"tester_emails": {
"type": "string",
"description": "Comma-separated Google account emails of testers. Real accounts that will install the app — Play counts installs, not invitations."
},
"tester_list_name": {
"type": "string",
"description": "Name of the tester email list (default \"Closed testers\"). An existing list with this name is updated rather than duplicated."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}| string |
| Comma-separated ISO 3166-1 alpha-2 codes, e.g. "NG,GH,KE". NOTE: on a track that has no country targeting of its own this does NOT work — tested live, Play still refuses. Use update_track_countries to set the track's countries first; this parameter only narrows a rollout on a track that is already targeted. Nothing is defaulted — ask the user. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
| target_rest_of_world | string | "true" serves every country/region Play allows; "false" serves only targeted_countries. Omitted is NOT the same as "false" — it keeps whatever the track already targets. Same caveat as targeted_countries: it cannot stand in for update_track_countries on an untargeted track. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"track_id",
"release_id",
"google_account_email"
],
"properties": {
"track_id": {
"type": "string",
"description": "Numeric track id (e.g. the long digits in the Play Console URL's .../tracks/<this>/..., not the human alias like \"internal\"). Call list_tracks first to find it."
},
"release_id": {
"type": "string",
"description": "Release id on this track, from create_release/get_track."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"rollout_percentage": {
"type": "string",
"description": "Percentage of users to roll out to, 0-100. Defaults to 100 (full rollout) if omitted."
},
"targeted_countries": {
"type": "string",
"description": "Comma-separated ISO 3166-1 alpha-2 codes, e.g. \"NG,GH,KE\". NOTE: on a track that has no country targeting of its own this does NOT work — tested live, Play still refuses. Use update_track_countries to set the track's countries first; this parameter only narrows a rollout on a track that is already targeted. Nothing is defaulted — ask the user."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
},
"target_rest_of_world": {
"type": "string",
"description": "\"true\" serves every country/region Play allows; \"false\" serves only targeted_countries. Omitted is NOT the same as \"false\" — it keeps whatever the track already targets. Same caveat as targeted_countries: it cannot stand in for update_track_countries on an untargeted track."
}
}
}| notification_message |
| string |
| Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
| app_value_or_uniqueness | string | What the app offers users (free text). |
| testing_induced_changes | string | What changed as a result of testing (free text). |
| subsequent_round_changes | string | Changes planned after launch (free text). |
| expected_first_year_installs | string | zero_to_ten_thousand | ten_thousand_to_one_hundred_thousand | one_hundred_thousand_to_one_million | one_million_or_more | i_dont_know |
| production_readiness_decision | string | Why the app is ready for production (free text). |
| tester_recruitment_difficulty | string | very_difficult | difficult | neither | easy | very_easy |
| tester_recruitment_methodology | string | How testers were recruited (free text, the developer's own words). |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email"
],
"properties": {
"commit": {
"type": "string",
"description": "\"true\" submits. Omit or \"false\" for a dry run."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"tester_feedback": {
"type": "string",
"description": "What feedback testers gave (free text)."
},
"intended_audience": {
"type": "string",
"description": "Who the app is for (free text)."
},
"tester_engagement": {
"type": "string",
"description": "How testers engaged with the app (free text)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
},
"app_value_or_uniqueness": {
"type": "string",
"description": "What the app offers users (free text)."
},
"testing_induced_changes": {
"type": "string",
"description": "What changed as a result of testing (free text)."
},
"subsequent_round_changes": {
"type": "string",
"description": "Changes planned after launch (free text)."
},
"expected_first_year_installs": {
"type": "string",
"description": "zero_to_ten_thousand | ten_thousand_to_one_hundred_thousand | one_hundred_thousand_to_one_million | one_million_or_more | i_dont_know"
},
"production_readiness_decision": {
"type": "string",
"description": "Why the app is ready for production (free text)."
},
"tester_recruitment_difficulty": {
"type": "string",
"description": "very_difficult | difficult | neither | easy | very_easy"
},
"tester_recruitment_methodology": {
"type": "string",
"description": "How testers were recruited (free text, the developer's own words)."
}
}
}{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"content_rating_category",
"content_rating_contact_email"
],
"properties": {
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
},
"content_rating_category": {
"type": "string",
"description": "Must be \"all_other_app_types\" — the only supported value right now. Games and Social/Communication apps need a different questionnaire path not yet supported."
},
"content_rating_contact_email": {
"type": "string",
"description": "Contact email for content rating authorities / IARC correspondence."
}
}
}| string |
| Numeric Play Console developer id (from the Play Console URL). |
| data_collection* | string | "none" (app collects/shares nothing) or "collects" (then data_types is required). |
| data_deletion_url | string | Public https URL where users request data-only deletion (question 96). Needed when supports_data_deletion is "yes". |
| account_deletion_url | string | Public https URL where users can request account deletion (question 94). Play requires this once the app declares real account creation. Must be reachable without signing in. |
| encrypted_in_transit | string | Required when data_collection="collects": "true"/"false" — is all collected user data encrypted in transit? Confirm with the user; do not assume. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
| supports_data_deletion | string | Question 95 — can users delete their data WITHOUT deleting the whole account? It looks like a yes/no but is a three-way choice: "yes", "no", or "no_auto_deleted" (the app deletes the data automatically). Confirm with the user. |
| account_creation_methods | string | For data_collection="collects": how users create accounts in the app. MANDATORY for Play (omitting it makes the submission fail with a bare INVALID_ARGUMENT), so it is always sent. Comma-separated — question 92 is a MULTIPLE choice and an app can offer several. Values: none, other, user_id_and_password, user_id_and_other_auth, oauth, user_id_password_and_other_auth, non_app_account, id_through_product_or_service, enterprise_app. "none" means the app has NO sign-up at all and cannot be combined with another value — it is a false declaration for any app with a login, so confirm with the user. Anything other than "none" makes Play require follow-ups; the tool reads the app's live questionnaire and tells you exactly which of account_creation_method_other, account_deletion_url, supports_data_deletion and data_deletion_url it needs. |
| user_can_request_deletion | string | Required when data_collection="collects": "true"/"false" — can users request that their data be deleted? Confirm with the user; do not assume. |
| account_creation_method_other | string | Free text describing the sign-up method, for question 93. Required when account_creation_methods includes "other". Ask the user; do not invent a description. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"data_collection"
],
"properties": {
"data_types": {
"type": "string",
"description": "Required when data_collection=\"collects\". JSON array, one object per data type the app collects or shares: {\"type\": <data type>, \"collected\": bool, \"shared\": bool, \"ephemeral\": bool, \"required\": bool, \"collection_purposes\": [...], \"sharing_purposes\": [...]}. \"required\" means users cannot use the app without providing it. Purposes: app_functionality, analytics, developer_communications, fraud_prevention_and_security, advertising_or_marketing, personalization, account_management. Data types include name, email_address, phone_number, physical_address, user_ids, purchase_history, payment_info, device_or_other_ids, approximate_location, precise_location, photos, videos, contacts, crash_logs, diagnostics, app_interactions, installed_apps, files_and_docs, health_info, fitness_info — the tool's error detail lists the full set if one is rejected."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"data_collection": {
"type": "string",
"description": "\"none\" (app collects/shares nothing) or \"collects\" (then data_types is required)."
},
"data_deletion_url": {
"type": "string",
"description": "Public https URL where users request data-only deletion (question 96). Needed when supports_data_deletion is \"yes\"."
},
"account_deletion_url": {
"type": "string",
"description": "Public https URL where users can request account deletion (question 94). Play requires this once the app declares real account creation. Must be reachable without signing in."
},
"encrypted_in_transit": {
"type": "string",
"description": "Required when data_collection=\"collects\": \"true\"/\"false\" — is all collected user data encrypted in transit? Confirm with the user; do not assume."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
},
"supports_data_deletion": {
"type": "string",
"description": "Question 95 — can users delete their data WITHOUT deleting the whole account? It looks like a yes/no but is a three-way choice: \"yes\", \"no\", or \"no_auto_deleted\" (the app deletes the data automatically). Confirm with the user."
},
"account_creation_methods": {
"type": "string",
"description": "For data_collection=\"collects\": how users create accounts in the app. MANDATORY for Play (omitting it makes the submission fail with a bare INVALID_ARGUMENT), so it is always sent. Comma-separated — question 92 is a MULTIPLE choice and an app can offer several. Values: none, other, user_id_and_password, user_id_and_other_auth, oauth, user_id_password_and_other_auth, non_app_account, id_through_product_or_service, enterprise_app. \"none\" means the app has NO sign-up at all and cannot be combined with another value — it is a false declaration for any app with a login, so confirm with the user. Anything other than \"none\" makes Play require follow-ups; the tool reads the app's live questionnaire and tells you exactly which of account_creation_method_other, account_deletion_url, supports_data_deletion and data_deletion_url it needs."
},
"user_can_request_deletion": {
"type": "string",
"description": "Required when data_collection=\"collects\": \"true\"/\"false\" — can users request that their data be deleted? Confirm with the user; do not assume."
},
"account_creation_method_other": {
"type": "string",
"description": "Free text describing the sign-up method, for question 93. Required when account_creation_methods includes \"other\". Ask the user; do not invent a description."
}
}
}| "true" or "false" answer to the declaration's Yes/No question. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"policy_declaration",
"policy_declaration_answer"
],
"properties": {
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"policy_declaration": {
"type": "string",
"description": "Which declaration to set: \"advertising_id\" or \"government_app\". Other App content declarations (data safety, content rating, target audience, ads, sign in details, financial features, health) have their own tools or are not yet supported."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
},
"policy_declaration_answer": {
"type": "string",
"description": "\"true\" or \"false\" answer to the declaration's Yes/No question."
}
}
}| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"is_restricted"
],
"properties": {
"credentials": {
"type": "string",
"description": "Required when is_restricted=\"true\". JSON array, one object per test account Play's reviewer should use: [{\"name\": \"Checkout account\", \"username\": \"...\", \"password\": \"...\", \"credential_type\": \"email\"|\"username\"|\"phone_number\"|\"otp\"|\"other\", \"additional_details\": \"any steps the reviewer needs\"}]. Ask the user for a REAL working test account — never invent credentials, and never reuse a personal login. Passwords are redacted from this tool's output but are sent to Play."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"is_restricted": {
"type": "string",
"description": "\"false\" if every part of the app works without signing in or paying. \"true\" if ANY functionality is behind a login, payment, OTP, referral code, biometrics or an action on another device — then `credentials` is required so Play's reviewer can get in. This is a declaration Google acts on: filing \"false\" for an app with gated content is a false declaration and a common rejection reason. Ask the user; don't infer it from the code."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}| string |
| "draft" (default) or "full". Only applies when save_mode is "draft" - the committed endpoint rejects the validationMode query param outright ("Cannot bind query parameter"). Does NOT make the dashboard task complete; only save_mode="save" does that. |
| full_description* | string | Full description for this language. |
| store_listing_id | string | Always "0" — the main store listing. (It is NOT the long number in the Play Console store-listing URL; that is the app id. "0" is what Play Console's own PATCH sends and it is what creates the listing on an app that has none.) Defaults to 0. |
| short_description* | string | Short description for this language. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"language",
"title",
"short_description",
"full_description"
],
"properties": {
"title": {
"type": "string",
"description": "App title for this language."
},
"language": {
"type": "string",
"description": "BCP-47 language code for the listing, e.g. en-US."
},
"save_mode": {
"type": "string",
"description": "\"save\" COMMITS the listing (what Play Console's own Save button does); \"draft\" (the DEFAULT) writes only the draft copy. **Pass \"save\" for any listing that has to count toward release.** With the default, the app dashboard's `store_listings` task never completes no matter how complete the content is, and send_app_for_review stays blocked - measured live, and no amount of content or validation_mode=full fixes it. \"draft\" is for staging text you are not ready to commit."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"validation_mode": {
"type": "string",
"description": "\"draft\" (default) or \"full\". Only applies when save_mode is \"draft\" - the committed endpoint rejects the validationMode query param outright (\"Cannot bind query parameter\"). Does NOT make the dashboard task complete; only save_mode=\"save\" does that."
},
"full_description": {
"type": "string",
"description": "Full description for this language."
},
"store_listing_id": {
"type": "string",
"description": "Always \"0\" — the main store listing. (It is NOT the long number in the Play Console store-listing URL; that is the app id. \"0\" is what Play Console's own PATCH sends and it is what creates the listing on an app that has none.) Defaults to 0."
},
"short_description": {
"type": "string",
"description": "Short description for this language."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}| notification_message |
| string |
| Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"store_listing_id",
"google_account_email",
"language",
"screenshot_urls"
],
"properties": {
"language": {
"type": "string",
"description": "BCP-47 language code for the listing, e.g. en-US."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"screenshot_urls": {
"type": "string",
"description": "JSON array of the EXISTING screenshot URLs, in the desired final order (omit a URL to remove that screenshot). Every URL must already be present in the listing — this tool cannot add new images."
},
"store_listing_id": {
"type": "string",
"description": "Numeric store listing id from the Play Console store listing URL (0 for the main listing)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}| string |
| Optional public support website (https). |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email"
],
"properties": {
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"app_category": {
"type": "string",
"description": "Store category, lower_snake_case: shopping, food_and_drink, business, lifestyle, social, finance, health_and_fitness, education, entertainment, productivity, travel_and_local, photography, music_and_audio, news_and_magazines, books_and_reference, tools, dating, beauty, events, parenting, medical, weather, maps_and_navigation, personalization, art_and_design, auto_and_vehicles, house_and_home, comics, communication, sports, video_players, libraries_and_demo. Decides where the app is listed — ask the user."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"contact_email": {
"type": "string",
"description": "PUBLIC support email shown on the store listing. Confirm it with the user; don't reuse an internal address by reflex."
},
"contact_phone": {
"type": "string",
"description": "Optional public support phone number."
},
"contact_website": {
"type": "string",
"description": "Optional public support website (https)."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
| target_rest_of_world | string | "true" also serves every other country/region Play allows — a worldwide launch, so confirm it. "false" (default) serves only targeted_countries. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"track_id",
"google_account_email"
],
"properties": {
"track_id": {
"type": "string",
"description": "Numeric track id — call list_tracks first. Not the alias like \"production\"."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"targeted_countries": {
"type": "string",
"description": "Comma-separated ISO 3166-1 alpha-2 codes, e.g. \"NG,GH,KE\". These are the countries the app becomes downloadable in."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
},
"target_rest_of_world": {
"type": "string",
"description": "\"true\" also serves every other country/region Play allows — a worldwide launch, so confirm it. \"false\" (default) serves only targeted_countries."
}
}
}| Numeric Play Console developer id (from the Play Console URL). |
| bundle_base64 | string | The .aab inline as base64. Exists for symmetry with the image tools but is capped at 64 KiB, far below any real bundle — use bundle_url. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"track_id",
"release_id",
"google_account_email"
],
"properties": {
"track_id": {
"type": "string",
"description": "Numeric track id (e.g. the long digits in the Play Console URL's .../tracks/<this>/..., not the human alias like \"internal\"). Call list_tracks first to find it."
},
"bundle_url": {
"type": "string",
"description": "https URL the replay host downloads the signed .aab from — the route for a bundle built on your own machine, since bundle_path only sees files already on the replay host. Must be publicly resolvable."
},
"release_id": {
"type": "string",
"description": "Release id on this track, from create_release/get_track."
},
"bundle_path": {
"type": "string",
"description": "Absolute path ON THE REPLAY HOST, inside the secops container (repo root = /app). Only usable if you can already put files there — most operators cannot, so prefer bundle_url."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"bundle_base64": {
"type": "string",
"description": "The .aab inline as base64. Exists for symmetry with the image tools but is capped at 64 KiB, far below any real bundle — use bundle_url."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}| string |
| The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email"
],
"properties": {
"image_url": {
"type": "string",
"description": "https URL the replay host fetches the image from — the route for anything over the base64 cap. Must be publicly resolvable (a URL that resolves to a private address is refused)."
},
"image_path": {
"type": "string",
"description": "Absolute path ON THE REPLAY HOST, inside the secops container (repo root = /app). Only usable if you can already put files there — most operators cannot, so prefer image_base64 or image_url."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"image_base64": {
"type": "string",
"description": "The image's bytes as base64 (a data: URI prefix is fine) — the route that needs no file on the replay host and no hosting at all. Capped at 64 KiB of image because CLI steps receive their arguments in one environment variable and Linux caps that at 128 KiB; anything larger must use image_url. A 512x512 icon usually fits, a full-resolution screenshot usually does not."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}| play_app_id* | string | Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name. |
| developer_id* | string | Numeric Play Console developer id (from the Play Console URL). |
| image_base64 | string | The image's bytes as base64 (a data: URI prefix is fine) — the route that needs no file on the replay host and no hosting at all. Capped at 64 KiB of image because CLI steps receive their arguments in one environment variable and Linux caps that at 128 KiB; anything larger must use image_url. A 512x512 icon usually fits, a full-resolution screenshot usually does not. |
| store_listing_id | string | Numeric store listing id (0 for the main listing). Defaults to 0. |
| google_account_email* | string | The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess. |
| notification_message | string | Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names. |
{
"type": "object",
"required": [
"developer_id",
"play_app_id",
"google_account_email",
"language",
"image_type"
],
"properties": {
"language": {
"type": "string",
"description": "BCP-47 language code of the listing to attach into, e.g. en-US. The listing must already have text for this language (update_store_listing creates it)."
},
"image_url": {
"type": "string",
"description": "https URL the replay host fetches the image from — the route for anything over the base64 cap. Must be publicly resolvable (a URL that resolves to a private address is refused)."
},
"image_path": {
"type": "string",
"description": "Absolute path ON THE REPLAY HOST, inside the secops container (repo root = /app). Only usable if you can already put files there — most operators cannot, so prefer image_base64 or image_url."
},
"image_type": {
"type": "string",
"description": "Which slot: \"phone_screenshot\", \"feature_graphic\" (must be exactly 1024x500) or \"icon\" (must be exactly 512x512)."
},
"attach_mode": {
"type": "string",
"description": "For phone_screenshot only: \"append\" (default) adds alongside existing screenshots, \"replace\" makes it the only one. Ignored for feature_graphic and icon, which are single-image slots."
},
"play_app_id": {
"type": "string",
"description": "Numeric Play app id from the Play Console URL (.../app/<this>/...). NOT the package name."
},
"developer_id": {
"type": "string",
"description": "Numeric Play Console developer id (from the Play Console URL)."
},
"image_base64": {
"type": "string",
"description": "The image's bytes as base64 (a data: URI prefix is fine) — the route that needs no file on the replay host and no hosting at all. Capped at 64 KiB of image because CLI steps receive their arguments in one environment variable and Linux caps that at 128 KiB; anything larger must use image_url. A 512x512 icon usually fits, a full-resolution screenshot usually does not."
},
"store_listing_id": {
"type": "string",
"description": "Numeric store listing id (0 for the main listing). Defaults to 0."
},
"google_account_email": {
"type": "string",
"description": "The signed-in Google account email that owns this Play Console developer account. Call list_accounts first and confirm with the user — do not guess."
},
"notification_message": {
"type": "string",
"description": "Short user-facing sentence for this action if the follow-up reply fails. Plain text only; do not mention template syntax or variable names."
}
}
}