UNPKG

@bdmarvin/mcp-server-gbp

Version:

MCP server for Google Business Profile Performance API.

137 lines (136 loc) 7.41 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 { zodToJsonSchema } from 'zod-to-json-schema'; import { z } from 'zod'; import { // Performance Schemas GetDailyPerformanceMetricsInputSchema, GetMonthlySearchKeywordsInputSchema, // Business Information Schemas ListBusinessesInputSchema, GetBusinessInformationInputSchema, GetMultipleBusinessInformationInputSchema, ListManagedAccountsInputSchema, // <-- NEW } from './schemas.js'; import { GbpPerformanceService } from './gbp-performance-service.js'; import { GbpBusinessInformationService } from './gbp-business-information-service.js'; const packageVersion = '0.1.0'; // Or dynamic import const server = new Server({ name: 'gbp-mcp-server', version: packageVersion }, { capabilities: { tools: {} } }); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ // --- NEW TOOL for Account Management --- { name: 'list_managed_accounts', description: 'Lists all Google Business Profile accounts accessible by the authenticated user.', inputSchema: zodToJsonSchema(ListManagedAccountsInputSchema), }, // Performance Tools { name: 'get_daily_performance_metrics', description: 'Fetches daily performance metrics for a Google Business Profile location.', inputSchema: zodToJsonSchema(GetDailyPerformanceMetricsInputSchema), }, { name: 'get_monthly_search_keywords', description: 'Fetches monthly search keyword impressions for a Google Business Profile location.', inputSchema: zodToJsonSchema(GetMonthlySearchKeywordsInputSchema), }, // Business Information Tools { name: 'list_businesses', description: 'Lists businesses associated with a Google Business Profile account.', inputSchema: zodToJsonSchema(ListBusinessesInputSchema), }, { name: 'get_business_information', description: 'Fetches detailed information for a specific Google Business Profile location.', inputSchema: zodToJsonSchema(GetBusinessInformationInputSchema), }, { name: 'get_multiple_business_information', description: 'Fetches detailed information for multiple Google Business Profile locations.', inputSchema: zodToJsonSchema(GetMultipleBusinessInformationInputSchema), }, ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const allArgsFromController = request.params.arguments; const googleAccessToken = allArgsFromController.__google_access_token__; const googleUserEmail = allArgsFromController.__google_user_email__; if (typeof googleAccessToken !== 'string' || !googleAccessToken) { throw new Error('__google_access_token__ not provided or invalid.'); } const originalToolArgs = {}; for (const key in allArgsFromController) { if (key !== '__google_access_token__' && key !== '__google_user_id__' && key !== '__google_user_email__') { originalToolArgs[key] = allArgsFromController[key]; } } console.error(`GBP Server: Tool: ${request.params.name}, User: ${googleUserEmail || 'unknown'}`); // Instantiate services const gbpPerformanceService = new GbpPerformanceService(); const gbpBusinessInformationService = new GbpBusinessInformationService(); let responseData; switch (request.params.name) { // --- NEW TOOL CASE --- case 'list_managed_accounts': { const parsedArgs = ListManagedAccountsInputSchema.parse(originalToolArgs); responseData = await gbpBusinessInformationService.listManagedAccounts(googleAccessToken, parsedArgs); break; } // Performance Tools case 'get_daily_performance_metrics': { const parsedArgs = GetDailyPerformanceMetricsInputSchema.parse(originalToolArgs); responseData = await gbpPerformanceService.getDailyPerformanceMetrics(googleAccessToken, parsedArgs); break; } case 'get_monthly_search_keywords': { const parsedArgs = GetMonthlySearchKeywordsInputSchema.parse(originalToolArgs); responseData = await gbpPerformanceService.getMonthlySearchKeywords(googleAccessToken, parsedArgs); break; } // Business Information Tools case 'list_businesses': { const parsedArgs = ListBusinessesInputSchema.parse(originalToolArgs); responseData = await gbpBusinessInformationService.listBusinesses(googleAccessToken, parsedArgs); break; } case 'get_business_information': { const parsedArgs = GetBusinessInformationInputSchema.parse(originalToolArgs); responseData = await gbpBusinessInformationService.getBusinessInformation(googleAccessToken, parsedArgs); break; } case 'get_multiple_business_information': { const parsedArgs = GetMultipleBusinessInformationInputSchema.parse(originalToolArgs); responseData = await gbpBusinessInformationService.getMultipleBusinessInformation(googleAccessToken, parsedArgs); // This specific service method returns the data already in the desired { results: [...] } format return { content: [{ type: 'text', text: JSON.stringify(responseData, null, 2) }] }; } default: throw new Error(`Unknown tool: ${request.params.name}`); } // For most Google API client responses, data is in `responseData.data` return { content: [{ type: 'text', text: JSON.stringify(responseData?.data || responseData, null, 2) }] }; } catch (error) { console.error(`Error in CallToolRequest for '${request.params.name}':`, error.message, error.stack); if (error.response?.data) { console.error('Google API Error Details:', JSON.stringify(error.response.data, null, 2)); } if (error instanceof z.ZodError) { const messages = error.errors.map((e) => `${e.path.join('.') || 'argument'}: ${e.message}`); throw new Error(`Invalid arguments for tool '${request.params.name}': ${messages.join('; ')}`); } throw new Error(error.message || `An unexpected error occurred in tool '${request.params.name}'`); } }); async function runServer() { const transport = new StdioServerTransport(); await server.connect(transport); console.error(`Google Business Profile MCP Server (v${packageVersion}) running on stdio, expecting __google_access_token__`); } runServer().catch((error) => { console.error('Fatal error running GBP MCP Server:', error); process.exit(1); });