UNPKG

@andrewlwn77/app-store-mcp

Version:

MCP server for App Store API integration - Access Apple App Store and Google Play Store data

282 lines 9.8 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import axios, { AxiosError } from 'axios'; import * as dotenv from 'dotenv'; dotenv.config(); const API_KEY = process.env.APP_STORE_API_KEY; if (!API_KEY) { console.error('Error: APP_STORE_API_KEY environment variable is required'); console.error('Please set it in your .env file or environment'); console.error('Get your API key from: https://rapidapi.com/apimaker/api/app-stores'); process.exit(1); } const API_HOST = 'app-stores.p.rapidapi.com'; class AppStoreMcpServer { server; constructor() { this.server = new Server({ name: 'app-store-mcp', version: '1.0.0', }, { capabilities: { tools: {}, }, }); this.setupHandlers(); } setupHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: this.getTools(), })); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'app_store_autocomplete': return await this.handleAutocomplete(args); case 'app_store_search': return await this.handleSearch(args); case 'app_store_details': return await this.handleDetails(args); case 'app_store_reviews': return await this.handleReviews(args); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { const apiError = this.handleError(error); return { content: [ { type: 'text', text: `Error: ${apiError.message}`, }, ], isError: true, }; } }); } getTools() { return [ { name: 'app_store_autocomplete', description: 'Get app name suggestions based on a search term', inputSchema: { type: 'object', properties: { store: { type: 'string', enum: ['apple', 'google'], description: 'App store platform', }, term: { type: 'string', description: 'Search term for autocomplete', }, language: { type: 'string', description: 'Language code (e.g., "en")', default: 'en', }, }, required: ['store', 'term'], }, }, { name: 'app_store_search', description: 'Search for apps in the app store', inputSchema: { type: 'object', properties: { store: { type: 'string', enum: ['apple', 'google'], description: 'App store platform', }, term: { type: 'string', description: 'Search term', }, language: { type: 'string', description: 'Language code (e.g., "en")', default: 'en', }, }, required: ['store', 'term'], }, }, { name: 'app_store_details', description: 'Get detailed information about a specific app', inputSchema: { type: 'object', properties: { store: { type: 'string', enum: ['apple', 'google'], description: 'App store platform', }, id: { type: 'string', description: 'App ID (bundle ID for iOS, package name for Android)', }, language: { type: 'string', description: 'Language code (e.g., "en")', default: 'en', }, }, required: ['store', 'id'], }, }, { name: 'app_store_reviews', description: 'Get reviews for a specific app', inputSchema: { type: 'object', properties: { store: { type: 'string', enum: ['apple', 'google'], description: 'App store platform', }, id: { type: 'string', description: 'App ID (bundle ID for iOS, package name for Android)', }, language: { type: 'string', description: 'Language code (e.g., "en")', default: 'en', }, }, required: ['store', 'id'], }, }, ]; } validateStore(store) { if (store !== 'apple' && store !== 'google') { throw new Error(`Invalid store: ${store}. Must be "apple" or "google"`); } return store; } async makeApiRequest(endpoint, params) { const response = await axios.get(`https://${API_HOST}/${endpoint}`, { params, headers: { 'x-rapidapi-key': API_KEY, 'x-rapidapi-host': API_HOST, }, }); return response.data; } async handleAutocomplete(params) { const store = this.validateStore(params.store); const data = await this.makeApiRequest('autocomplete', { store, term: params.term, language: params.language || 'en', }); const response = { suggestions: data.suggestions || data || [], }; return { content: [ { type: 'text', text: JSON.stringify(response, null, 2), }, ], }; } async handleSearch(params) { const store = this.validateStore(params.store); const data = await this.makeApiRequest('search', { store, term: params.term, language: params.language || 'en', }); const response = { results: data.results || data || [], }; return { content: [ { type: 'text', text: JSON.stringify(response, null, 2), }, ], }; } async handleDetails(params) { const store = this.validateStore(params.store); const data = await this.makeApiRequest('details', { store, id: params.id, language: params.language || 'en', }); const response = { app: data, }; return { content: [ { type: 'text', text: JSON.stringify(response, null, 2), }, ], }; } async handleReviews(params) { const store = this.validateStore(params.store); const data = await this.makeApiRequest('reviews', { store, id: params.id, language: params.language || 'en', }); const response = { reviews: data.reviews || data || [], }; return { content: [ { type: 'text', text: JSON.stringify(response, null, 2), }, ], }; } handleError(error) { if (error instanceof AxiosError) { return { error: 'API Error', message: error.response?.data?.message || error.message, statusCode: error.response?.status, }; } if (error instanceof Error) { return { error: 'Server Error', message: error.message, }; } return { error: 'Unknown Error', message: 'An unexpected error occurred', }; } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('App Store MCP server running on stdio'); } } const server = new AppStoreMcpServer(); server.run().catch(console.error); //# sourceMappingURL=index.js.map