@bdmarvin/mcp-server-gbp
Version:
MCP server for Google Business Profile Performance API.
137 lines (136 loc) • 7.41 kB
JavaScript
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);
});