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
| Name | Required | Description | Default |
|---|---|---|---|
| app | No | Registered app slug | |
| packageName | No | Google Play package name | |
| bundleId | No | App Store bundle ID | |
| store | No | Target store (default: both) | |
| uploadImages | No | Whether to upload images as well | |
| dryRun | No | If 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
- src/tools/aso/push.ts:32-259 (handler)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" );
- src/tools/aso/push.ts:23-30 (schema)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; }