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