apps-search
Search registered apps across App Store and Google Play stores using names, IDs, or package identifiers to find and manage applications directly from AI clients.
Instructions
Search registered apps. Returns all apps if called without query.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Search term (slug, bundleId, packageName, name). Returns all apps if empty | |
| store | No | Store filter (default: all) |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"query": {
"description": "Search term (slug, bundleId, packageName, name). Returns all apps if empty",
"type": "string"
},
"store": {
"description": "Store filter (default: all)",
"enum": [
"all",
"appStore",
"googlePlay"
],
"type": "string"
}
},
"type": "object"
}
Implementation Reference
- src/tools/apps/search.ts:88-187 (handler)Main handler function that implements the 'apps-search' tool logic: loads registered apps, performs search by query across slug/name/bundleId/packageName, applies store filter, formats output.export async function handleSearchApps(options: SearchAppsOptions) { const { query, store = "all" } = options; console.error( `[MCP] π Searching apps (query: ${query || "all"}, store: ${store})` ); try { const config = loadRegisteredApps(); console.error(`[MCP] Loaded ${config.apps.length} apps from config`); if (config.apps.length > 0) { console.error( `[MCP] App slugs: ${config.apps.map((a) => a.slug).join(", ")}` ); } let results: RegisteredApp[]; if (!query) { // If no query, return full list results = config.apps; } else { // Try exact match first (by slug, bundleId, packageName) const exactMatch = findApp(query); // Also search for partial matches const partialMatches = config.apps.filter((app) => matchesQuery(app, query) ); // Combine results: exact match first, then partial matches // Remove duplicates by slug const seenSlugs = new Set<string>(); results = []; // Add exact match first if found if (exactMatch && !seenSlugs.has(exactMatch.slug)) { results.push(exactMatch); seenSlugs.add(exactMatch.slug); } // Add partial matches (excluding exact match if already added) for (const app of partialMatches) { if (!seenSlugs.has(app.slug)) { results.push(app); seenSlugs.add(app.slug); } } } // Apply store filter results = filterByStore(results, store); if (results.length === 0) { const message = query ? `No apps found matching "${query}".` : "No apps registered."; return { content: [ { type: "text" as const, text: `β ${message} π‘ Register apps using apps-add or apps-init tools.`, }, ], _meta: { apps: [], count: 0 }, }; } const header = query ? `π Search results for "${query}": ${results.length}` : `π Registered app list: ${results.length}`; const appList = results.map(formatAppInfo).join("\n\n"); return { content: [ { type: "text" as const, text: `${header} ${appList}`, }, ], _meta: { apps: results, count: results.length }, }; } catch (error) { const message = error instanceof Error ? error.message : String(error); return { content: [ { type: "text" as const, text: `β App search failed: ${message}`, }, ], isError: true, }; } }
- src/index.ts:208-228 (registration)Registers the 'apps-search' tool with MCP server, including description, input schema (Zod), and links to the handler function.registerToolWithInfo( "apps-search", { description: "Search registered apps. Returns all apps if called without query.", inputSchema: z.object({ query: z .string() .optional() .describe( "Search term (slug, bundleId, packageName, name). Returns all apps if empty" ), store: z .enum(["all", "appStore", "googlePlay"]) .optional() .describe("Store filter (default: all)"), }), }, handleSearchApps, "App Management" );
- src/tools/apps/search.ts:15-20 (schema)TypeScript interface defining input options for the apps-search handler, matching the Zod schema used in registration.interface SearchAppsOptions { /** Search term (slug, bundleId, packageName, name). Returns all apps if empty */ query?: string; /** Store filter (default: all) */ store?: "all" | "appStore" | "googlePlay"; }
- src/tools/apps/search.ts:25-48 (helper)Helper function to check if a registered app matches the search query across multiple fields (slug, name, bundleId, packageName).function matchesQuery(app: RegisteredApp, query: string): boolean { const lowerQuery = query.toLowerCase(); // slug match if (app.slug.toLowerCase().includes(lowerQuery)) return true; // name match if (app.name.toLowerCase().includes(lowerQuery)) return true; // App Store bundleId match if (app.appStore?.bundleId?.toLowerCase().includes(lowerQuery)) return true; // App Store name match if (app.appStore?.name?.toLowerCase().includes(lowerQuery)) return true; // Google Play packageName match if (app.googlePlay?.packageName?.toLowerCase().includes(lowerQuery)) return true; // Google Play name match if (app.googlePlay?.name?.toLowerCase().includes(lowerQuery)) return true; return false; }
- src/tools/apps/search.ts:69-86 (helper)Helper function to format app information into a readable string output for the tool response.function formatAppInfo(app: RegisteredApp): string { const lines: string[] = []; lines.push(`π± **${app.name}** (\`${app.slug}\`)`); if (app.appStore) { lines.push(` π App Store: \`${app.appStore.bundleId}\``); if (app.appStore.appId) { lines.push(` App ID: ${app.appStore.appId}`); } } if (app.googlePlay) { lines.push(` π€ Google Play: \`${app.googlePlay.packageName}\``); } return lines.join("\n"); }