Skip to main content
Glama

Play Store MCP — Python/FastMCP on Railway

Google Play MCP server with 117 original tools + 6 cloud tools, owner-password sign-in and durable JSON storage on a Railway Volume. Google account login, Redis and SQLite are not used by the server.

Google Play API access still uses your Google service-account credentials. The owner password only authorizes access to this MCP server.

Deploy on Railway

  1. Create a service from this repository; Railway uses Dockerfile and railway.json.

  2. Attach a Volume at /data. Run one replica and one application process. Do not run multiple Uvicorn workers.

  3. Generate a public HTTPS domain.

  4. Configure these variables:

Variable

Value

MCP_PUBLIC_URL

https://YOUR-DOMAIN, without /mcp

MCP_ADMIN_PASSWORD

A private random password of at least 24 bytes

MCP_DATA_DIR

/data

GOOGLE_PLAY_STORE_CREDENTIALS

Complete service-account JSON, in a sealed variable

PLAY_STORE_MCP_READ_ONLY

1 for initial read-only verification; 0 to allow Play writes

Generate a password locally with openssl rand -hex 32. Do not put the actual value in source control.

MCP_SIGNING_KEY is optional: the server generates a stable private key at /data/.signing-key when it is absent. Back up the key with the Volume. Changing it invalidates portal/download tokens and makes previously encrypted job records unreadable. MCP_BEARER_TOKEN optionally supplies a separate automation token of at least 32 characters.

No Google OAuth Web client, consent screen, redirect URI, email allowlist, Redis service or SQL database is required. Railway supplies PORT automatically.

Related MCP server: playstore-release-mcp

Configure Google Play API access

Enable the Android Publisher API in the Google Cloud project, create a service account and grant it the necessary app-level permissions in Play Console. Save the downloaded service-account JSON in GOOGLE_PLAY_STORE_CREDENTIALS. Use the least privilege that covers your workflow.

Every connection authorized with the owner password can access the configured Play account and shared file library. This server uses a single-owner model.

Connect a remote MCP client

Endpoint: https://YOUR-DOMAIN/mcp. Choose OAuth in the client. On this server's consent page, enter MCP_ADMIN_PASSWORD and authorize the requested scopes. The server issues its own access/refresh tokens; it never redirects you to Google sign-in.

The protocol uses Authorization Code + PKCE S256, hashed opaque credentials, one-use codes, refresh rotation and grant revocation. Discovery is available at /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource.

Scopes are mcp:read, mcp:write, mcp:admin and offline_access. mcp:read is required; store mutations additionally require mcp:write; updating server credentials requires mcp:admin. Global read-only mode overrides write scope. The owner page displays the client and requested permissions.

An API/CLI client can instead send Authorization: Bearer YOUR_MCP_BEARER_TOKEN when that optional token is configured. Never use the owner password or service-account JSON as a Bearer token.

Endpoint

Purpose

/mcp

All 123 tools over Streamable HTTP

/sse, /messages/

Legacy HTTP+SSE

/mcp-code

Optional code mode (search, get_schema, execute)

/portal

Owner-password file portal

/api/assets

Authenticated uploads and file metadata

/files/ID

Authenticated or expiring signed file downloads

/credentials

Owner-admin update to the shared Play credentials, in memory

/health, /ready

Process and readiness probes

Upload files and run jobs

Open /portal, sign in with the owner password and upload an AAB/APK/image. Copy the returned asset://ID and use it in original tool arguments such as file_path, apk_path, bundle_path or image_path. Chat attachments do not automatically reach the server. Uploads are chunked and resumable; the portal reports SHA-256 after completion.

For large/long operations, call:

{
  "tool_name": "deploy_app",
  "arguments": {"package_name": "com.example.app", "track": "internal", "file_path": "asset://YOUR-ID"},
  "idempotency_key": "com.example.app-internal-build-42"
}

Pass this object to start_operation, then use get_operation or list_operations to retrieve the original result. Repeating the same owner/key/arguments returns the same job. Different arguments with the same key are rejected.

Jobs persist queued, running, completed, failed or unknown status. After restart, queued work resumes and running work becomes unknown. Failed writes also become unknown conservatively. Inspect Google Play before resubmitting an uncertain operation. The queue never automatically replays a possibly committed write. Job payloads/results remain encrypted, including dates and original result fields.

The six cloud tools remain start_operation, get_operation, list_operations, list_assets, get_asset and delete_asset. The original 117 names, input schemas and read-only guards are preserved.

Storage, backups and migration

The Volume contains state.json, .signing-key (when auto-generated), lock files and assets/. JSON transactions use a thread lock, a file lock, private temporary files, fsync and atomic replacement. Corrupt state fails closed instead of silently resetting data. Back up the whole Volume privately, with its signing key.

Only one application process may own background work. Local locks do not coordinate independently deployed replicas. Keep assets and jobs off the repository and never expose Volume contents through a static web server.

Migrate an existing Redis/SQLite deployment

Stop the old service and take a private Volume backup before changing its deployment. Keep the original BRIDGE_SIGNING_KEY as MCP_SIGNING_KEY so existing encrypted job results stay readable. Remove Google Web OAuth and Redis variables after migration; the service-account JSON is still required.

Run the standalone migration in a trusted environment with the Volume mounted:

uv run python scripts/migrate_json.py --data-dir /data --adopt-owner

Inside the new Railway image, the migration is also available as python /app/migrate_json.py --data-dir /data --adopt-owner --uid 10001 when run as root. The script reads the old SQLite database without modifying it, verifies encrypted payloads, adopts assets/jobs into the single owner and writes state.json. It refuses overwrite or colliding owner/idempotency keys. The runtime refuses to silently start empty when it detects an unmigrated SQLite database. Keep the old database only as a private migration backup.

Reconnect existing MCP clients and sign in with the owner password. Old Google-backed grants and portal cookies do not carry over. Merely changing MCP_ADMIN_PASSWORD does not revoke existing server grants; use the /revoke endpoint for a grant and rotate the optional Bearer token separately when needed.

Limits and local development

See .env.example for optional file, chunk, storage and queue limits. BRIDGE_CODE_MODE=0 disables the remote code-mode endpoint. PLAY_STORE_MCP_READ_ONLY=1 blocks all 73 Google Play mutation tools while preserving file management.

uv sync --frozen --extra dev
uv run --frozen pytest -q -o addopts='' --ignore=tests/test_integration.py --ignore=tests/test_live_api.py
uv run --frozen ruff check src/ tests/ docker_entrypoint.py scripts/
uv run --frozen ruff format --check src/ tests/ docker_entrypoint.py scripts/
uv run --frozen mypy src/
uv build

Live Google tests are opt-in. The test suite exercises mocked API calls, owner OAuth, files, schema parity, durable JSON state and write guards. A passing mock test does not verify a real service account's Play permissions.

The original stdio command remains CODE_MODE=0 uv run --frozen play-store-mcp --read-only. It does not require the remote owner's password or cloud storage. See UPSTREAM_README.md for upstream/local usage.

Based on lusky3/play-store-mcp, snapshot aebcd31, under the original MIT License. The original Google API implementation and tests are retained.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    An MCP server that drives Google Play releases: bundle upload, track releases (internal/closed/open/production), listing metadata, store graphics, and review replies.
    8
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables publishing Android apps to the Google Play Console from monorepos by exposing commands as MCP tools that handle AAB uploads, store listings, testers, and setup via the Google Play Developer API, returning structured JSON results.
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Gives AI assistants hands-on control over Google Play Console and Google Cloud Console using an authorized Google identity. Exposes 95 tools for shipping app builds and release tracks, managing store listings, reviews, in-app products, GCP projects and IAM, Firebase projects and App Distribution, and Cloud Storage or Artifact Registry resources.
    95
    MIT