Skip to main content
Glama
krzko

Google Cloud MCP Server

by krzko

gcp-error-reporting-list-groups

List error groups from Google Cloud Error Reporting to identify and analyze recurring issues in your applications.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The main execution handler for the gcp-error-reporting-list-groups tool. Authenticates with GCP, queries the Error Reporting API for group stats with filters, processes the data, generates analysis and remediation suggestions, and formats a markdown response.
    async ({ timeRange, serviceFilter, order, pageSize }) => { 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 || "1h"; const actualOrder = order || "COUNT_DESC"; const actualPageSize = pageSize || 20; // 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 hour for any other time range period = "PERIOD_1_HOUR"; break; } // Build query parameters const params = new URLSearchParams({ "timeRange.period": period, order: actualOrder, pageSize: actualPageSize.toString(), }); // Add service filter if provided if (serviceFilter) { params.set("serviceFilter.service", serviceFilter); } // Make REST API call using same fetch approach as trace service 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 group stats: ${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 Groups\n\nProject: ${projectId}\nTime Range: ${actualTimeRange}\n${serviceFilter ? `Service Filter: ${serviceFilter}\n` : ""}\nNo error groups found.`, }, ], }; } // errorGroupStats should already match our ErrorGroupStats interface const errorSummaries: ErrorGroupStats[] = errorGroupStats; // Generate analysis and recommendations const analysis = analyseErrorPatternsAndSuggestRemediation(errorSummaries); let content = `# Error Groups Analysis\n\nProject: ${projectId}\nTime Range: ${actualTimeRange}\n${serviceFilter ? `Service Filter: ${serviceFilter}\n` : ""}\n\n${analysis}\n\n`; content += `## Detailed Error Groups\n\n`; errorSummaries.forEach((errorSummary, index) => { content += `### ${index + 1}. ${formatErrorGroupSummary(errorSummary)}\n`; }); return { content: [ { type: "text", text: content, }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; throw new GcpMcpError( `Failed to list error groups: ${errorMessage}`, "INTERNAL_ERROR", 500, ); } },
  • Zod-based input schema defining parameters for the tool: timeRange (optional, default 1h), serviceFilter (optional), order (optional, default COUNT_DESC), pageSize (optional, default 20, max 100).
    timeRange: z .string() .optional() .default("1h") .describe('Time range to query: "1h", "6h", "24h"/"1d", "7d", "30d"'), serviceFilter: z.string().optional().describe("Filter by service name"), order: z .enum([ "COUNT_DESC", "LAST_SEEN_DESC", "CREATED_DESC", "AFFECTED_USERS_DESC", ]) .optional() .default("COUNT_DESC") .describe("Sort order for error groups"), pageSize: z .number() .min(1) .max(100) .default(20) .describe("Maximum number of error groups to return"), },
  • MCP server.tool registration for 'gcp-error-reporting-list-groups', specifying title, description, inputSchema, and binding the handler function.
    "gcp-error-reporting-list-groups", { title: "List Error Groups", description: "List error groups from Google Cloud Error Reporting with optional filtering and time range", inputSchema: { timeRange: z .string() .optional() .default("1h") .describe('Time range to query: "1h", "6h", "24h"/"1d", "7d", "30d"'), serviceFilter: z.string().optional().describe("Filter by service name"), order: z .enum([ "COUNT_DESC", "LAST_SEEN_DESC", "CREATED_DESC", "AFFECTED_USERS_DESC", ]) .optional() .default("COUNT_DESC") .describe("Sort order for error groups"), pageSize: z .number() .min(1) .max(100) .default(20) .describe("Maximum number of error groups to return"), }, }, async ({ timeRange, serviceFilter, order, pageSize }) => { 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 || "1h"; const actualOrder = order || "COUNT_DESC"; const actualPageSize = pageSize || 20; // 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 hour for any other time range period = "PERIOD_1_HOUR"; break; } // Build query parameters const params = new URLSearchParams({ "timeRange.period": period, order: actualOrder, pageSize: actualPageSize.toString(), }); // Add service filter if provided if (serviceFilter) { params.set("serviceFilter.service", serviceFilter); } // Make REST API call using same fetch approach as trace service 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 group stats: ${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 Groups\n\nProject: ${projectId}\nTime Range: ${actualTimeRange}\n${serviceFilter ? `Service Filter: ${serviceFilter}\n` : ""}\nNo error groups found.`, }, ], }; } // errorGroupStats should already match our ErrorGroupStats interface const errorSummaries: ErrorGroupStats[] = errorGroupStats; // Generate analysis and recommendations const analysis = analyseErrorPatternsAndSuggestRemediation(errorSummaries); let content = `# Error Groups Analysis\n\nProject: ${projectId}\nTime Range: ${actualTimeRange}\n${serviceFilter ? `Service Filter: ${serviceFilter}\n` : ""}\n\n${analysis}\n\n`; content += `## Detailed Error Groups\n\n`; errorSummaries.forEach((errorSummary, index) => { content += `### ${index + 1}. ${formatErrorGroupSummary(errorSummary)}\n`; }); return { content: [ { type: "text", text: content, }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; throw new GcpMcpError( `Failed to list error groups: ${errorMessage}`, "INTERNAL_ERROR", 500, ); } }, );
  • src/index.ts:213-213 (registration)
    Top-level call in main server setup to register all error reporting tools, including gcp-error-reporting-list-groups via the registerErrorReportingTools function.
    registerErrorReportingTools(server);
  • Helper function called in the handler to analyze error groups, compute totals and patterns, suggest remediations, and generate markdown analysis section.
    export function analyseErrorPatternsAndSuggestRemediation( errorGroups: ErrorGroupStats[], ): string { if (errorGroups.length === 0) { return "No errors found in the specified time range."; } let analysis = `# Error Analysis and Remediation Suggestions\n\n`; analysis += `**Total Error Groups:** ${errorGroups.length}\n\n`; // Calculate total errors and affected users const totalErrors = errorGroups.reduce( (sum, group) => sum + parseInt(group.count), 0, ); const totalAffectedUsers = errorGroups.reduce( (sum, group) => sum + parseInt(group.affectedUsersCount), 0, ); analysis += `**Summary:**\n`; analysis += `- Total errors: ${totalErrors.toLocaleString()}\n`; analysis += `- Total affected users: ${totalAffectedUsers.toLocaleString()}\n`; analysis += `- Error groups: ${errorGroups.length}\n\n`; // Sort by error count (most frequent first) const sortedErrors = [...errorGroups].sort( (a, b) => parseInt(b.count) - parseInt(a.count), ); analysis += `## Top Error Groups by Frequency\n\n`; // Analyse top 5 errors sortedErrors.slice(0, 5).forEach((errorGroup, index) => { analysis += `### ${index + 1}. ${errorGroup.representative?.serviceContext?.service || "Unknown Service"}\n\n`; analysis += `**Error:** ${errorGroup.representative?.message || "No message"}\n\n`; analysis += `**Impact:** ${errorGroup.count} occurrences, ${errorGroup.affectedUsersCount} affected users\n\n`; // Suggest remediation based on error patterns const remediation = suggestRemediation(errorGroup); if (remediation) { analysis += `**Suggested Remediation:**\n${remediation}\n\n`; } analysis += `---\n\n`; }); // Pattern analysis analysis += `## Pattern Analysis\n\n`; // Group by service const serviceGroups = new Map<string, ErrorGroupStats[]>(); errorGroups.forEach((group) => { const service = group.representative?.serviceContext?.service || "Unknown"; if (!serviceGroups.has(service)) { serviceGroups.set(service, []); } serviceGroups.get(service)!.push(group); }); if (serviceGroups.size > 1) { analysis += `**Services Affected:** ${serviceGroups.size}\n`; serviceGroups.forEach((groups, service) => { const serviceErrors = groups.reduce( (sum, group) => sum + parseInt(group.count), 0, ); analysis += `- ${service}: ${groups.length} error groups, ${serviceErrors} total errors\n`; }); analysis += `\n`; } // Time-based analysis const recentErrors = errorGroups.filter((group) => { const lastSeen = new Date(group.lastSeenTime); const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000); return lastSeen > oneHourAgo; }); if (recentErrors.length > 0) { analysis += `**Recent Activity:** ${recentErrors.length} error groups with activity in the last hour\n\n`; } return 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/krzko/google-cloud-mcp'

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