review_velocity
Track review velocity trends over time, including monthly counts, rating changes, reply rates, and sentiment themes. Identify patterns in your Google Business Profile reviews.
Instructions
Analyze review velocity trends over time. Returns reviews per month, rating trend, reply rate, sentiment themes, and monthly breakdown. Costs 6 credits. Note: this tool may take 10-30 seconds to return — this is normal, not an error.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| business_name | Yes | Business name | |
| location | Yes | City and state | |
| period | No | Time period: "30d", "90d", "6m", or "1y". Default: "90d" |
Implementation Reference
- src/tools/reviews.ts:32-50 (registration)The tool 'review_velocity' is registered on the MCP server using server.tool() with the name 'review_velocity', description, input schema, and handler.
server.tool( "review_velocity", "Analyze review velocity trends over time. Returns reviews per month, rating trend, reply rate, sentiment themes, and monthly breakdown. Costs 6 credits. Note: this tool may take 10-30 seconds to return — this is normal, not an error.", { business_name: z.string().describe("Business name"), location: z.string().describe("City and state"), period: z.string().optional().describe('Time period: "30d", "90d", "6m", or "1y". Default: "90d"'), }, READ_ONLY, withErrorHandling(async ({ business_name, location, period }) => { const result = await callApi( "/v1/reviews/velocity", { business_name, location, ...(period && { period }) }, getAuth(), 120_000 ); return { content: [{ type: "text" as const, text: formatResult(result.data, result) }] }; }) ); - src/tools/reviews.ts:41-50 (handler)The handler function for 'review_velocity' calls the API endpoint '/v1/reviews/velocity' with business_name, location, and optional period parameters, wrapped in withErrorHandling for error management. Uses a 120-second timeout.
withErrorHandling(async ({ business_name, location, period }) => { const result = await callApi( "/v1/reviews/velocity", { business_name, location, ...(period && { period }) }, getAuth(), 120_000 ); return { content: [{ type: "text" as const, text: formatResult(result.data, result) }] }; }) ); - src/tools/reviews.ts:35-39 (schema)The input schema for 'review_velocity' defines required parameters business_name (string) and location (string), and optional period (string) with values '30d', '90d', '6m', or '1y'.
{ business_name: z.string().describe("Business name"), location: z.string().describe("City and state"), period: z.string().optional().describe('Time period: "30d", "90d", "6m", or "1y". Default: "90d"'), }, - src/tools/reviews.ts:11-50 (registration)The registerReviewTools function is exported and called from src/server.ts, which registers the review_velocity tool along with other review tools.
export function registerReviewTools(server: McpServer, getAuth: () => string) { server.tool( "google_reviews", "Get Google reviews for a business. Returns review text, rating, date, author, and owner replies. Costs 1 credit per 10 reviews. Note: this tool may take 10-30 seconds to return — this is normal, not an error.", { business_name: z.string().describe("Business name"), location: z.string().describe("City and state"), limit: z.number().int().min(1).max(100).optional().describe("Number of reviews (1-100). Default: 10"), sort: z.enum(["newest", "highest", "lowest", "most_relevant"]).optional().describe("Sort order. Default: newest"), }, READ_ONLY, withErrorHandling(async ({ business_name, location, limit, sort }) => { const result = await callApi( "/v1/reviews/google", { business_name, location, ...(limit && { limit }), ...(sort && { sort }) }, getAuth() ); return { content: [{ type: "text" as const, text: formatResult(result.data, result) }] }; }) ); server.tool( "review_velocity", "Analyze review velocity trends over time. Returns reviews per month, rating trend, reply rate, sentiment themes, and monthly breakdown. Costs 6 credits. Note: this tool may take 10-30 seconds to return — this is normal, not an error.", { business_name: z.string().describe("Business name"), location: z.string().describe("City and state"), period: z.string().optional().describe('Time period: "30d", "90d", "6m", or "1y". Default: "90d"'), }, READ_ONLY, withErrorHandling(async ({ business_name, location, period }) => { const result = await callApi( "/v1/reviews/velocity", { business_name, location, ...(period && { period }) }, getAuth(), 120_000 ); return { content: [{ type: "text" as const, text: formatResult(result.data, result) }] }; }) ); - src/api-client.ts:143-158 (helper)The withErrorHandling helper wraps the tool handler to catch errors and return them as MCP error content.
export function withErrorHandling<T>( fn: (args: T) => Promise<ToolResult> ): (args: T) => Promise<ToolResult> { return async (args) => { try { return await fn(args); } catch (err) { const message = err instanceof Error ? err.message : String(err); console.error(`[mcp] Tool error: ${message}`); return { content: [{ type: "text" as const, text: `Error: ${message}` }], isError: true, }; } }; }