Skip to main content
Glama
satheeshds

Google Business Profile Review MCP Server

by satheeshds
reviews.ts6.25 kB
/** * Reviews Resource * Provides access to reviews for business locations * Supports both listing all locations' reviews and specific location reviews */ import { logger } from '../../utils/logger.js'; import type { IReviewService, GetResourceResult } from '../../types/index.js'; export interface ReviewsResource { uri: string; name: string; description: string; mimeType: string; handler: (uri: string) => Promise<GetResourceResult>; } export function createReviewsResource(reviewService: IReviewService): ReviewsResource { return { uri: 'reviews://{locationId}', name: 'Business Reviews', description: 'Access reviews for business locations. Use reviews://all for all locations or reviews://{locationId} for a specific location', mimeType: 'application/json', handler: async (uri: string): Promise<GetResourceResult> => { try { logger.info(`Fetching reviews resource: ${uri}`); // Parse the URI to determine what to fetch // reviews://all - fetch all locations and their reviews // reviews://locations/123 - fetch reviews for specific location if (uri === 'reviews://all') { return await fetchAllReviews(reviewService); } else if (uri.startsWith('reviews://') && uri !== 'reviews://all') { const locationId = uri.replace('reviews://', ''); return await fetchLocationReviews(reviewService, locationId); } else { return { contents: [ { uri, mimeType: 'text/plain', text: 'Invalid URI. Use reviews://all or reviews://{locationId}' } ] }; } } catch (error) { logger.error('Error fetching reviews resource:', error); return { contents: [ { uri, mimeType: 'text/plain', text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}` } ] }; } } }; } /** * Fetch reviews for all locations */ async function fetchAllReviews(reviewService: IReviewService): Promise<GetResourceResult> { // First get all locations const locationsResult = await reviewService.listLocations(); if (!locationsResult.success) { return { contents: [ { uri: 'reviews://all', mimeType: 'text/plain', text: `Error fetching locations: ${locationsResult.error}` } ] }; } const locations = locationsResult.data!.locations; const allReviewsData: any[] = []; // Fetch reviews for each location for (const location of locations) { const reviewsResult = await reviewService.getReviews(location.name); if (reviewsResult.success && reviewsResult.data) { allReviewsData.push({ location: { name: location.name, displayName: location.locationName, address: location.address }, reviews: reviewsResult.data.reviews.map(review => ({ id: review.reviewId, rating: review.starRating, text: review.comment, author: review.reviewer.displayName, isAnonymous: review.reviewer.isAnonymous, createTime: review.createTime, hasReply: !!review.reviewReply })), totalReviews: reviewsResult.data.totalSize, unrepliedCount: reviewsResult.data.reviews.length }); } } const summary = { totalLocations: locations.length, totalUnrepliedReviews: allReviewsData.reduce((sum, loc) => sum + loc.unrepliedCount, 0), locations: allReviewsData }; logger.info(`Retrieved reviews for ${locations.length} location(s), ${summary.totalUnrepliedReviews} unreplied`); return { contents: [ { uri: 'reviews://all', mimeType: 'application/json', text: JSON.stringify(summary, null, 2) } ] }; } /** * Fetch reviews for a specific location */ async function fetchLocationReviews(reviewService: IReviewService, locationName: string): Promise<GetResourceResult> { const reviewsResult = await reviewService.getReviews(locationName); if (!reviewsResult.success) { return { contents: [ { uri: `reviews://locations/${locationName}`, mimeType: 'text/plain', text: `Error fetching reviews: ${reviewsResult.error}` } ] }; } const { reviews, totalSize } = reviewsResult.data!; const formattedData = { locationName, totalReviews: totalSize, unrepliedCount: reviews.length, reviews: reviews.map(review => ({ id: review.reviewId, rating: review.starRating, text: review.comment, author: review.reviewer.displayName, isAnonymous: review.reviewer.isAnonymous, createTime: review.createTime, updateTime: review.updateTime, hasReply: !!review.reviewReply })) }; logger.info(`Retrieved ${reviews.length} unreplied reviews for location ${locationName}`); return { contents: [ { uri: `reviews://${locationName}`, mimeType: 'application/json', text: JSON.stringify(formattedData, null, 2) } ] }; }

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/satheeshds/gbp-review-agent'

If you have feedback or need assistance with the MCP directory API, please join our Discord server