Skip to main content
Glama
RadiumGu

GCP Billing and Monitoring MCP Server

by RadiumGu

gcp-error-reporting-analyse-trends

Analyze error reporting trends in Google Cloud Platform to identify recurring issues, monitor error patterns, and improve system reliability through comprehensive error data analysis.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The handler function that implements the core logic of the 'gcp-error-reporting-analyse-trends' tool. It authenticates with Google Cloud, queries the Error Reporting API for group stats with timed counts, aggregates errors over time buckets, detects spikes, summarizes top error groups, and generates a comprehensive Markdown report with tables, statistics, and recommendations.
    async ({ timeRange, serviceFilter, resolution }) => { try { const projectId = await getProjectId(); // Initialize Google Auth client (same pattern as trace service) const auth = await initGoogleAuth(true); if (!auth) { throw new GcpMcpError( "Google Cloud authentication not available. Please configure authentication to access error reporting data.", "UNAUTHENTICATED", 401, ); } const client = await auth.getClient(); const token = await client.getAccessToken(); // Parse time range - ensure we have a valid timeRange value const actualTimeRange = timeRange || "24h"; const actualResolution = resolution || "1h"; // Map time range to Google Cloud Error Reporting periods let period: string; switch (actualTimeRange) { case "1h": period = "PERIOD_1_HOUR"; break; case "6h": period = "PERIOD_6_HOURS"; break; case "24h": case "1d": period = "PERIOD_1_DAY"; break; case "7d": period = "PERIOD_1_WEEK"; break; case "30d": period = "PERIOD_30_DAYS"; break; default: // Default to 1 day for trend analysis period = "PERIOD_1_DAY"; break; } // Calculate timed count duration based on resolution let timedCountDuration: string; switch (actualResolution) { case "1m": timedCountDuration = "60s"; break; case "5m": timedCountDuration = "300s"; break; case "1h": timedCountDuration = "3600s"; break; case "1d": timedCountDuration = "86400s"; break; default: timedCountDuration = "3600s"; // Default to 1 hour break; } // Build query parameters for trends analysis const params = new URLSearchParams({ "timeRange.period": period, timedCountDuration: timedCountDuration, order: "COUNT_DESC", pageSize: "50", }); // Add service filter if provided if (serviceFilter) { params.set("serviceFilter.service", serviceFilter); } // Make REST API call for trends const apiUrl = `https://clouderrorreporting.googleapis.com/v1beta1/projects/${projectId}/groupStats?${params}`; const response = await fetch(apiUrl, { method: "GET", headers: { Authorization: `Bearer ${token.token}`, Accept: "application/json", }, }); if (!response.ok) { const errorText = await response.text(); throw new GcpMcpError( `Failed to fetch error trends: ${errorText}`, "FAILED_PRECONDITION", response.status, ); } const data = await response.json(); const errorGroupStats = data.errorGroupStats || []; if (!errorGroupStats || errorGroupStats.length === 0) { return { content: [ { type: "text", text: `# Error Trends Analysis\n\nProject: ${projectId}\nTime Range: ${actualTimeRange}\n${serviceFilter ? `Service Filter: ${serviceFilter}\n` : ""}\nResolution: ${actualResolution}\n\nNo error data found for trend analysis.`, }, ], }; } let content = `# Error Trends Analysis\n\nProject: ${projectId}\nTime Range: ${actualTimeRange}\n${serviceFilter ? `Service Filter: ${serviceFilter}\n` : ""}\nResolution: ${actualResolution}\n\n`; // Aggregate trends across all error groups const timeSlots = new Map<string, number>(); let totalErrors = 0; const totalGroups = errorGroupStats.length; errorGroupStats.forEach((stat: any) => { const count = parseInt(stat.count || "0"); totalErrors += count; if (stat.timedCounts) { stat.timedCounts.forEach((timedCount: any) => { const timeKey = timedCount.startTime; const currentCount = timeSlots.get(timeKey) || 0; timeSlots.set( timeKey, currentCount + parseInt(timedCount.count || "0"), ); }); } }); content += `## Summary\n\n`; content += `- **Total Error Groups:** ${totalGroups}\n`; content += `- **Total Errors:** ${totalErrors.toLocaleString()}\n`; content += `- **Average per Group:** ${Math.round(totalErrors / totalGroups).toLocaleString()}\n\n`; // Sort time slots chronologically const sortedTimeSlots = Array.from(timeSlots.entries()).sort( ([a], [b]) => new Date(a).getTime() - new Date(b).getTime(), ); // Initialize variables for recommendations let averageErrors = 0; let spikes: Array<[string, number]> = []; if (sortedTimeSlots.length > 0) { content += `## Error Count Over Time\n\n`; content += `| Time Period | Error Count |\n`; content += `|-------------|-------------|\n`; sortedTimeSlots.forEach(([time, count]) => { const timeStr = new Date(time).toLocaleString(); content += `| ${timeStr} | ${count.toLocaleString()} |\n`; }); content += `\n`; // Identify spikes (errors significantly above average) averageErrors = totalErrors / sortedTimeSlots.length; spikes = sortedTimeSlots.filter( ([, count]) => count > averageErrors * 2, ); if (spikes.length > 0) { content += `## Error Spikes Detected\n\n`; content += `*Time periods with error counts > 2x average (${Math.round(averageErrors)})*\n\n`; spikes.forEach(([time, count]) => { const timeStr = new Date(time).toLocaleString(); const multiplier = Math.round((count / averageErrors) * 10) / 10; content += `- **${timeStr}:** ${count.toLocaleString()} errors (${multiplier}x average)\n`; }); content += `\n`; } } // Top error groups contributing to trends content += `## Top Contributing Error Groups\n\n`; const topErrors = errorGroupStats.slice(0, 5).map((stat: any) => ({ service: stat.representative?.serviceContext?.service || "Unknown", message: stat.representative?.message || "No message", count: parseInt(stat.count || "0"), groupId: stat.group?.groupId || "unknown", })); topErrors.forEach( ( error: { service: string; message: string; count: number; groupId: string; }, index: number, ) => { const percentage = Math.round((error.count / totalErrors) * 100); content += `${index + 1}. **${error.service}** (${percentage}% of total)\n`; content += ` - ${error.message}\n`; content += ` - ${error.count.toLocaleString()} occurrences\n`; content += ` - Group ID: ${error.groupId}\n\n`; }, ); // Recommendations based on trends content += `## Recommendations\n\n`; if (spikes.length > 0) { content += `- **Investigate Error Spikes:** Focus on the ${spikes.length} time periods with significantly elevated error rates\n`; content += `- **Correlate with Deployments:** Check if error spikes align with recent deployments or configuration changes\n`; } content += `- **Monitor Top Contributors:** The top ${Math.min(3, topErrors.length)} error groups account for the majority of errors\n`; content += `- **Set Up Alerting:** Configure alerts for error rates exceeding ${Math.round(averageErrors * 1.5)} errors per ${resolution}\n`; content += `- **Review Patterns:** Look for recurring patterns in error timing to identify systemic issues\n`; return { content: [ { type: "text", text: content, }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; throw new GcpMcpError( `Failed to analyse error trends: ${errorMessage}`, "INTERNAL_ERROR", 500, ); } },
  • Registration of the 'gcp-error-reporting-analyse-trends' tool on the MCP server, including title, description, and Zod input schema definition.
    // Tool to analyse error trends over time server.tool( "gcp-error-reporting-analyse-trends", { title: "Analyse Error Trends", description: "Analyse error trends over time to identify patterns and spikes", inputSchema: { timeRange: z .string() .optional() .default("24h") .describe('Time range to analyse (e.g., "1h", "24h", "7d")'), serviceFilter: z.string().optional().describe("Filter by service name"), resolution: z .enum(["1m", "5m", "1h", "1d"]) .optional() .default("1h") .describe("Time resolution for trend analysis"), }, },
  • Zod schema defining the input parameters for the tool: timeRange (default 24h), optional serviceFilter, and resolution (default 1h).
    inputSchema: { timeRange: z .string() .optional() .default("24h") .describe('Time range to analyse (e.g., "1h", "24h", "7d")'), serviceFilter: z.string().optional().describe("Filter by service name"), resolution: z .enum(["1m", "5m", "1h", "1d"]) .optional() .default("1h") .describe("Time resolution for trend analysis"), },

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/RadiumGu/gcp-billing-and-monitoring-mcp'

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