Skip to main content
Glama

release-pull-notes

Fetch release notes from App Store and Google Play to manage app updates and store metadata directly from AI clients.

Instructions

Fetch release notes from App Store/Google Play.

Input Schema

NameRequiredDescriptionDefault
appNoRegistered app slug
packageNameNoGoogle Play package name
bundleIdNoApp Store bundle ID
storeNoTarget store (default: both)
dryRunNoIf true, only outputs result without actually saving

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 saving", "type": "boolean" }, "packageName": { "description": "Google Play package name", "type": "string" }, "store": { "description": "Target store (default: both)", "enum": [ "appStore", "googlePlay", "both" ], "type": "string" } }, "type": "object" }

Implementation Reference

  • Main handler function `handleAsoPullReleaseNotes` that resolves the app, fetches release notes from App Store and/or Google Play services, logs progress, handles dry-run, and saves to local files if not dry-run.
    export async function handleAsoPullReleaseNotes( options: AsoPullReleaseNotesOptions ) { const { app, store, dryRun = false } = options; let { packageName, bundleId } = options; const { store: targetStore, includeAppStore, includeGooglePlay, } = getStoreTargets(store); const resolved = appResolutionService.resolve({ slug: app, packageName, bundleId, }); if (!resolved.success) { return { content: [ { type: "text" as const, text: resolved.error.message, }, ], }; } const { slug, bundleId: resolvedBundleId, packageName: resolvedPackageName, hasAppStore, hasGooglePlay, } = resolved.data; bundleId = resolvedBundleId; packageName = resolvedPackageName; console.error(`[MCP] πŸ“₯ Pulling release notes`); console.error(`[MCP] Store: ${targetStore}`); console.error(`[MCP] App: ${slug}`); if (packageName) console.error(`[MCP] Package Name: ${packageName}`); if (bundleId) console.error(`[MCP] Bundle ID: ${bundleId}`); console.error(`[MCP] Mode: ${dryRun ? "Dry run" : "Actual fetch"}`); 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, }; } const releaseNotes: { googlePlay?: GooglePlayReleaseNote[]; appStore?: AppStoreReleaseNote[]; } = {}; if (includeGooglePlay) { if (!hasGooglePlay) { console.error( `[MCP] ⏭️ Skipping Google Play (not registered for Google Play)` ); } else if (!config.playStore) { console.error( `[MCP] ⏭️ Skipping Google Play (not configured in ~/.config/pabal-mcp/config.json)` ); } else if (!packageName) { console.error( `[MCP] ⏭️ Skipping Google Play (no packageName provided)` ); } else { const notesResult = await googlePlayService.pullReleaseNotes(packageName); if (!notesResult.success) { console.error( `[MCP] ❌ Failed to fetch Google Play release notes: ${notesResult.error.message}` ); } else { releaseNotes.googlePlay = notesResult.data; console.error(`[MCP] πŸ“Š Google Play Release Notes:`); console.error(`[MCP] Total versions: ${notesResult.data.length}`); for (const rn of notesResult.data) { const code = (rn as any).versionCode ?? "N/A"; console.error( `[MCP] Version ${rn.versionName} (${code}): ${ Object.keys(rn.releaseNotes).length } languages` ); } console.error(`[MCP] βœ… Google Play release notes fetched`); } } } if (includeAppStore) { if (!hasAppStore) { console.error( `[MCP] ⏭️ Skipping App Store (not registered for App Store)` ); } else if (!config.appStore) { console.error( `[MCP] ⏭️ Skipping App Store (not configured in ~/.config/pabal-mcp/config.json)` ); } else if (!bundleId) { console.error(`[MCP] ⏭️ Skipping App Store (no bundleId provided)`); } else { const notesResult = await appStoreService.pullReleaseNotes(bundleId); if (!notesResult.success) { console.error( `[MCP] ❌ Failed to fetch App Store release notes: ${notesResult.error.message}` ); } else { releaseNotes.appStore = notesResult.data; console.error(`[MCP] πŸ“Š App Store Release Notes:`); console.error(`[MCP] Total versions: ${notesResult.data.length}`); for (const rn of notesResult.data) { console.error( `[MCP] Version ${rn.versionString}: ${ Object.keys(rn.releaseNotes).length } locales` ); } console.error(`[MCP] βœ… App Store release notes fetched`); } } } if (dryRun) { return { content: [ { type: "text" as const, text: `πŸ“‹ Dry run - Release notes:\n${JSON.stringify( releaseNotes, null, 2 )}`, }, ], }; } // Save to ASO directory const asoDir = getPullProductAsoDir(slug, getAsoPullDir()); if (releaseNotes.googlePlay) { const googlePlayDir = getStoreDir(asoDir, "google-play"); ensureDir(googlePlayDir); const filePath = getReleaseNotesPath(googlePlayDir); writeFileSync(filePath, JSON.stringify(releaseNotes.googlePlay, null, 2)); console.error(`[MCP] πŸ’Ύ Google Play release notes saved to ${filePath}`); } if (releaseNotes.appStore) { const appStoreDir = getStoreDir(asoDir, "app-store"); ensureDir(appStoreDir); const filePath = getReleaseNotesPath(appStoreDir); writeFileSync(filePath, JSON.stringify(releaseNotes.appStore, null, 2)); console.error(`[MCP] πŸ’Ύ App Store release notes saved to ${filePath}`); } return { content: [ { type: "text" as const, text: `βœ… Release notes pulled\n` + ` Google Play: ${ releaseNotes.googlePlay ? `${releaseNotes.googlePlay.length} versions` : "βœ—" }\n` + ` App Store: ${ releaseNotes.appStore ? `${releaseNotes.appStore.length} versions` : "βœ—" }`, }, ], }; }
  • src/index.ts:327-344 (registration)
    Registers the tool 'release-pull-notes' with MCP server, including description, Zod input schema, and references the handler function.
    registerToolWithInfo( "release-pull-notes", { description: "Fetch release notes from 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)"), dryRun: z .boolean() .optional() .describe("If true, only outputs result without actually saving"), }), }, handleAsoPullReleaseNotes, "Release Management" );
  • TypeScript interface defining the input options for the handler function.
    interface AsoPullReleaseNotesOptions { app?: string; // Registered app slug packageName?: string; // For Google Play bundleId?: string; // For App Store store?: StoreType; 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