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;
    }
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Tool has no description.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness1/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Tool has no description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Tool has no description.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Tool has no description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose1/5

Does the description clearly state what the tool does and how it differs from similar tools?

Tool has no description.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines1/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Tool has no description.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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