Skip to main content
Glama

aso-push

Push ASO metadata from local cache to App Store and Google Play stores for app store optimization management.

Instructions

Push ASO data from local cache to App Store/Google Play.

Input Schema

NameRequiredDescriptionDefault
appNoRegistered app slug
packageNameNoGoogle Play package name
bundleIdNoApp Store bundle ID
storeNoTarget store (default: both)
uploadImagesNoWhether to upload images as well
dryRunNoIf true, only outputs result without actually pushing

Input Schema (JSON Schema)

{ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "app": { "description": "Registered app slug", "type": "string" }, "bundleId": { "description": "App Store bundle ID", "type": "string" }, "dryRun": { "description": "If true, only outputs result without actually pushing", "type": "boolean" }, "packageName": { "description": "Google Play package name", "type": "string" }, "store": { "description": "Target store (default: both)", "enum": [ "appStore", "googlePlay", "both" ], "type": "string" }, "uploadImages": { "description": "Whether to upload images as well", "type": "boolean" } }, "type": "object" }

Implementation Reference

  • Main handler function that orchestrates ASO push: resolves app, loads and prepares local ASO data from cache, optionally pushes to App Store/Google Play services, supports dry-run.
    export async function handleAsoPush(options: AsoPushOptions) { const { store = "both", uploadImages = false, dryRun = false } = options; const resolved = appResolutionService.resolve({ slug: options.app, packageName: options.packageName, bundleId: options.bundleId, }); if (!resolved.success) { return { content: [ { type: "text" as const, text: resolved.error.message, }, ], }; } const { slug, packageName, bundleId, hasAppStore, hasGooglePlay } = resolved.data; console.error(`[MCP] πŸ“€ Pushing ASO data`); console.error(`[MCP] Store: ${store}`); console.error(`[MCP] App: ${slug}`); if (packageName) console.error(`[MCP] Package Name: ${packageName}`); if (bundleId) console.error(`[MCP] Bundle ID: ${bundleId}`); console.error(`[MCP] Upload Images: ${uploadImages ? "Yes" : "No"}`); console.error(`[MCP] Mode: ${dryRun ? "Dry run" : "Actual push"}`); let config; try { config = loadConfig(); } catch (error) { const message = error instanceof Error ? error.message : String(error); return { content: [ { type: "text" as const, text: `❌ Failed to load config: ${message}` }, ], isError: true, }; } // Load local data from ASO directory const asoDir = getAsoPushDir(); const { googlePlay: googlePlayDataPath, appStore: appStoreDataPath } = getAsoDataPaths(slug, asoDir); console.error(`[MCP] πŸ“ ASO Directory: ${asoDir}`); console.error(`[MCP] πŸ“ Base ASO Dir: ${getAsoDir()}`); console.error(`[MCP] πŸ” Checking data files...`); console.error(`[MCP] Google Play: ${googlePlayDataPath}`); console.error( `[MCP] Exists: ${existsSync(googlePlayDataPath) ? "βœ… Yes" : "❌ No"}` ); console.error(`[MCP] App Store: ${appStoreDataPath}`); console.error( `[MCP] Exists: ${existsSync(appStoreDataPath) ? "βœ… Yes" : "❌ No"}` ); let configData; try { configData = loadAsoData(slug, { asoDir }); } catch (error) { const message = error instanceof Error ? error.message : String(error); return { content: [ { type: "text" as const, text: `❌ Failed to load ASO data: ${message}`, }, ], isError: true, }; } console.error(`[MCP] πŸ“Š Loaded data status:`); console.error( `[MCP] Google Play: ${ configData.googlePlay ? "βœ… Loaded" : "❌ Not found" }` ); if (configData.googlePlay) { const gpData = configData.googlePlay; if (isGooglePlayMultilingual(gpData)) { const locales = Object.keys(gpData.locales); console.error( `[MCP] Locales: ${locales.join(", ")} (${locales.length} total)` ); } else { console.error( `[MCP] Language: ${gpData.defaultLanguage || "unknown"}` ); } } console.error( `[MCP] App Store: ${configData.appStore ? "βœ… Loaded" : "❌ Not found"}` ); if (configData.appStore) { const asData = configData.appStore; if (isAppStoreMultilingual(asData)) { const locales = Object.keys(asData.locales); console.error( `[MCP] Locales: ${locales.join(", ")} (${locales.length} total)` ); } else { console.error(`[MCP] Locale: ${asData.locale || "unknown"}`); } } if (!configData.googlePlay && !configData.appStore) { const errorDetails = `❌ No ASO data found for ${slug}. πŸ“ Expected paths: Google Play: ${googlePlayDataPath} App Store: ${appStoreDataPath} πŸ’‘ To fix this: 1. Run \`aso-pull\` to fetch data from stores 2. Or ensure data exists at the paths above 3. Check that data directory is set correctly (current: ${getAsoDir()})`; console.error(`[MCP] ${errorDetails}`); return { content: [{ type: "text" as const, text: errorDetails }], }; } // Prepare data for push console.error(`[MCP] πŸ”„ Preparing data for push...`); const localAsoData = prepareAsoDataForPush(slug, configData); console.error(`[MCP] πŸ“Š Prepared data status:`); console.error( `[MCP] Google Play: ${ localAsoData.googlePlay ? "βœ… Ready" : "❌ Not available" }` ); if (localAsoData.googlePlay) { const gpData = localAsoData.googlePlay; if (isGooglePlayMultilingual(gpData)) { const locales = Object.keys(gpData.locales); console.error( `[MCP] Locales to push: ${locales.join(", ")} (${ locales.length } total)` ); } } console.error( `[MCP] App Store: ${ localAsoData.appStore ? "βœ… Ready" : "❌ Not available" }` ); if (localAsoData.appStore) { const asData = localAsoData.appStore; if (isAppStoreMultilingual(asData)) { const locales = Object.keys(asData.locales); console.error( `[MCP] Locales to push: ${locales.join(", ")} (${ locales.length } total)` ); } } if (dryRun) { return { content: [ { type: "text" as const, text: `πŸ“‹ Dry run - Data that would be pushed:\n${JSON.stringify( localAsoData, null, 2 )}`, }, ], }; } // Save to ASO directory before pushing if (localAsoData.googlePlay || localAsoData.appStore) { saveAsoData(slug, localAsoData, { asoDir }); } const results: string[] = []; // Push to Google Play if (store === "googlePlay" || store === "both") { if (!hasGooglePlay) { results.push(`⏭️ Skipping Google Play (not registered for Google Play)`); } else { const result = await googlePlayService.pushAsoData({ config, packageName, localAsoData, googlePlayDataPath, }); results.push(formatPushResult("Google Play", result)); } } // Push to App Store if (store === "appStore" || store === "both") { if (!hasAppStore) { results.push(`⏭️ Skipping App Store (not registered for App Store)`); } else { const appStoreResult = await appStoreService.pushAsoData({ config, bundleId, localAsoData, appStoreDataPath, }); results.push(formatPushResult("App Store", appStoreResult)); } } return { content: [ { type: "text" as const, text: `πŸ“€ ASO Push Results:\n${results.join("\n")}`, }, ], }; }
  • src/index.ts:257-278 (registration)
    Registers the 'aso-push' tool with the MCP server, providing description, input schema validation using Zod, and linking to the handleAsoPush handler.
    registerToolWithInfo( "aso-push", { description: "Push ASO data from local cache to App Store/Google Play.", inputSchema: z.object({ app: z.string().optional().describe("Registered app slug"), packageName: z.string().optional().describe("Google Play package name"), bundleId: z.string().optional().describe("App Store bundle ID"), store: storeSchema.describe("Target store (default: both)"), uploadImages: z .boolean() .optional() .describe("Whether to upload images as well"), dryRun: z .boolean() .optional() .describe("If true, only outputs result without actually pushing"), }), }, handleAsoPush, "ASO Data Sync" );
  • TypeScript interface defining input options for the handler, matching the Zod schema.
    interface AsoPushOptions { app?: string; // Registered app slug packageName?: string; // For Google Play bundleId?: string; // For App Store store?: StoreType; uploadImages?: boolean; dryRun?: boolean; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/quartz-labs-dev/pabal-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server