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

TableJSON 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

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