Skip to main content
Glama

apps-add

Register apps by bundle ID or package name to manage App Store Connect and Google Play Console metadata. Automatically checks both stores for app registration.

Instructions

Register individual app by bundleId or packageName. Automatically checks both stores.

Input Schema

NameRequiredDescriptionDefault
identifierYesApp identifier (bundleId or packageName, e.g., com.example.app)
slugNoCustom slug (if not specified, uses last part of identifier)
storeNoStore to check (default: both)

Input Schema (JSON Schema)

{ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "properties": { "identifier": { "description": "App identifier (bundleId or packageName, e.g., com.example.app)", "type": "string" }, "slug": { "description": "Custom slug (if not specified, uses last part of identifier)", "type": "string" }, "store": { "description": "Store to check (default: both)", "enum": [ "appStore", "googlePlay", "both" ], "type": "string" } }, "required": [ "identifier" ], "type": "object" }

Implementation Reference

  • Main handler function for 'apps-add' tool. Registers or updates an app by bundle ID or package name. Fetches app info and supported locales from App Store and/or Google Play, generates slug, checks for duplicates, and saves to registered apps config.
    export async function handleAddApp(options: AddAppOptions) { const { identifier, slug: customSlug, store = "both" } = options; console.error(`[MCP] πŸ“± Adding app: ${identifier} (store: ${store})`); if (!identifier) { return { content: [ { type: "text" as const, text: `❌ identifier is required. Usage: \`\`\`json { "identifier": "com.example.app" } { "identifier": "com.example.app", "slug": "myapp" } { "identifier": "com.example.app", "store": "googlePlay" } \`\`\``, }, ], }; } // Check if already registered let existing; try { existing = findApp(identifier); } catch (error) { const message = error instanceof Error ? error.message : String(error); return { content: [ { type: "text" as const, text: `❌ Failed to load registered apps: ${message}`, }, ], }; } if (existing) { // Update language info for existing apps let appsConfig; try { appsConfig = loadRegisteredApps(); } catch (error) { const message = error instanceof Error ? error.message : String(error); return { content: [ { type: "text" as const, text: `❌ Failed to load registered apps: ${message}`, }, ], }; } const appIndex = appsConfig.apps.findIndex((a) => a.slug === existing.slug); if (appIndex >= 0) { let updated = false; const updateResults: string[] = []; // Update App Store language info if (store === "both" || store === "appStore") { if (existing.appStore) { const asResult = await appStoreService.fetchAppInfo(identifier); if (asResult.found && asResult.supportedLocales) { if (!appsConfig.apps[appIndex].appStore) { appsConfig.apps[appIndex].appStore = { bundleId: identifier, appId: asResult.appId, name: asResult.name, }; } appsConfig.apps[appIndex].appStore!.supportedLocales = asResult.supportedLocales; updated = true; updateResults.push( `🍎 App Store: Updated locales (${asResult.supportedLocales.length})` ); } } } // Update Google Play language info if (store === "both" || store === "googlePlay") { if (existing.googlePlay || store === "googlePlay") { const gpResult = await googlePlayService.fetchAppInfo(identifier); if (gpResult.found && gpResult.supportedLocales) { if (!appsConfig.apps[appIndex].googlePlay) { appsConfig.apps[appIndex].googlePlay = { packageName: identifier, name: gpResult.name, }; } appsConfig.apps[appIndex].googlePlay!.supportedLocales = gpResult.supportedLocales; if (gpResult.name) { appsConfig.apps[appIndex].googlePlay!.name = gpResult.name; } updated = true; updateResults.push( `πŸ€– Google Play: Updated locales (${gpResult.supportedLocales.length})` ); } } } if (updated) { saveRegisteredApps(appsConfig); const updatedApp = appsConfig.apps[appIndex]; const localeInfo: string[] = []; if ( updatedApp.appStore?.supportedLocales && updatedApp.appStore.supportedLocales.length > 0 ) { localeInfo.push( `β€’ App Store locales: ${updatedApp.appStore.supportedLocales.join(", ")}` ); } if ( updatedApp.googlePlay?.supportedLocales && updatedApp.googlePlay.supportedLocales.length > 0 ) { localeInfo.push( `β€’ Google Play locales: ${updatedApp.googlePlay.supportedLocales.join(", ")}` ); } return { content: [ { type: "text" as const, text: `βœ… App language info updated β€’ Slug: \`${updatedApp.slug}\` β€’ Name: ${updatedApp.name} β€’ App Store: ${updatedApp.appStore ? `βœ… ${updatedApp.appStore.bundleId}` : "❌"} β€’ Google Play: ${updatedApp.googlePlay ? `βœ… ${updatedApp.googlePlay.packageName}` : "❌"} ${updateResults.length > 0 ? `\n**Updates:**\n${updateResults.map((r) => ` β€’ ${r}`).join("\n")}` : ""} ${localeInfo.length > 0 ? `\n**Supported Languages:**\n${localeInfo.map((l) => ` ${l}`).join("\n")}` : ""}`, }, ], _meta: { app: updatedApp }, }; } } // If no updates were made, return existing info const localeInfo: string[] = []; if ( existing.appStore?.supportedLocales && existing.appStore.supportedLocales.length > 0 ) { localeInfo.push( `β€’ App Store locales: ${existing.appStore.supportedLocales.join(", ")}` ); } if ( existing.googlePlay?.supportedLocales && existing.googlePlay.supportedLocales.length > 0 ) { localeInfo.push( `β€’ Google Play locales: ${existing.googlePlay.supportedLocales.join(", ")}` ); } return { content: [ { type: "text" as const, text: `⏭️ App is already registered. β€’ Slug: \`${existing.slug}\` β€’ Name: ${existing.name} β€’ App Store: ${existing.appStore ? `βœ… ${existing.appStore.bundleId}` : "❌"} β€’ Google Play: ${existing.googlePlay ? `βœ… ${existing.googlePlay.packageName}` : "❌"} ${localeInfo.length > 0 ? `\n**Supported Languages:**\n${localeInfo.map((l) => ` ${l}`).join("\n")}` : ""}`, }, ], _meta: { app: existing }, }; } const slug = customSlug || generateSlug(identifier); // Check for slug duplicates const slugExists = findApp(slug); if (slugExists) { return { content: [ { type: "text" as const, text: `❌ slug "${slug}" is already in use. Please specify a different slug. \`\`\`json { "identifier": "${identifier}", "slug": "different-slug" } \`\`\``, }, ], }; } // Fetch app information by store (μ–Έμ–΄ 정보 포함) let appStoreInfo: RegisteredApp["appStore"] = undefined; let googlePlayInfo: RegisteredApp["googlePlay"] = undefined; let appName = identifier; const results: string[] = []; // Check App Store if (store === "both" || store === "appStore") { console.error(`[MCP] πŸ” Searching App Store for: ${identifier}`); const asResult = await appStoreService.fetchAppInfo(identifier); if (asResult.found) { appStoreInfo = toRegisteredAppStoreInfo({ bundleId: identifier, appInfo: asResult, }); appName = asResult.name || appName; const localeInfo = asResult.supportedLocales && asResult.supportedLocales.length > 0 ? ` (${asResult.supportedLocales.length} locales)` : ""; results.push(`🍎 App Store: βœ… Found (${asResult.name})${localeInfo}`); } else { results.push(`🍎 App Store: ❌ Not found`); } } // Check Google Play if (store === "both" || store === "googlePlay") { console.error(`[MCP] πŸ” Searching Google Play for: ${identifier}`); const gpResult = await googlePlayService.fetchAppInfo(identifier); if (gpResult.found) { googlePlayInfo = toRegisteredGooglePlayInfo({ packageName: identifier, appInfo: gpResult, }); appName = gpResult.name || appName; const localeInfo = gpResult.supportedLocales && gpResult.supportedLocales.length > 0 ? ` (${gpResult.supportedLocales.length} locales)` : ""; results.push(`πŸ€– Google Play: βœ… Found (${gpResult.name})${localeInfo}`); } else { results.push(`πŸ€– Google Play: ❌ Not found`); } } // Must be found in at least one store if (!appStoreInfo && !googlePlayInfo) { return { content: [ { type: "text" as const, text: `❌ App not found. **Search Results:** ${results.map((r) => ` β€’ ${r}`).join("\n")} **Things to Check:** β€’ Verify identifier is correct: \`${identifier}\` β€’ Verify app is registered in the store β€’ Verify authentication settings are correct (use auth-check tool)`, }, ], }; } // Register app try { console.error(`[MCP] πŸ’Ύ Registering app with slug: ${slug}`); const newApp = registerApp({ slug, name: appName, appStore: appStoreInfo, googlePlay: googlePlayInfo, }); console.error(`[MCP] βœ… App registered successfully`); const storeIcons = [ appStoreInfo ? "🍎" : null, googlePlayInfo ? "πŸ€–" : null, ] .filter(Boolean) .join("+"); const localeInfo: string[] = []; if ( appStoreInfo?.supportedLocales && appStoreInfo.supportedLocales.length > 0 ) { localeInfo.push( `β€’ App Store locales: ${appStoreInfo.supportedLocales.join(", ")}` ); } if ( googlePlayInfo?.supportedLocales && googlePlayInfo.supportedLocales.length > 0 ) { localeInfo.push( `β€’ Google Play locales: ${googlePlayInfo.supportedLocales.join(", ")}` ); } return { content: [ { type: "text" as const, text: `βœ… App registration complete (${storeIcons}) **Registration Info:** β€’ Slug: \`${newApp.slug}\` β€’ Name: ${newApp.name} ${appStoreInfo ? `β€’ App Store: ${appStoreInfo.bundleId} (ID: ${appStoreInfo.appId})` : ""} ${googlePlayInfo ? `β€’ Google Play: ${googlePlayInfo.packageName}` : ""} ${localeInfo.length > 0 ? `\n**Supported Languages:**\n${localeInfo.map((l) => ` ${l}`).join("\n")}` : ""} **Search Results:** ${results.map((r) => ` β€’ ${r}`).join("\n")} You can now reference this app in other tools using the \`app: "${slug}"\` parameter.`, }, ], _meta: { app: newApp }, }; } catch (error) { const msg = error instanceof Error ? error.message : String(error); return { content: [ { type: "text" as const, text: `❌ App registration failed: ${msg}`, }, ], }; } }
  • src/index.ts:184-206 (registration)
    Registration of the 'apps-add' tool using registerToolWithInfo, including description, input schema, and linking to the handleAddApp handler.
    registerToolWithInfo( "apps-add", { description: "Register individual app by bundleId or packageName. Automatically checks both stores.", inputSchema: z.object({ identifier: z .string() .describe( "App identifier (bundleId or packageName, e.g., com.example.app)" ), slug: z .string() .optional() .describe( "Custom slug (if not specified, uses last part of identifier)" ), store: storeSchema.describe("Store to check (default: both)"), }), }, handleAddApp, "App Management" );
  • Zod input schema definition for the 'apps-add' tool parameters: identifier (required), slug (optional), store (optional).
    inputSchema: z.object({ identifier: z .string() .describe( "App identifier (bundleId or packageName, e.g., com.example.app)" ), slug: z .string() .optional() .describe( "Custom slug (if not specified, uses last part of identifier)" ), store: storeSchema.describe("Store to check (default: both)"), }),
  • TypeScript interface defining the input options for the handleAddApp function.
    interface AddAppOptions { /** App identifier (bundleId or packageName) */ identifier: string; /** Custom slug (if not specified, uses last part of identifier) */ slug?: string; /** Target store (default: both - check both stores) */ store?: "appStore" | "googlePlay" | "both"; }

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