Skip to main content
Glama
krzko

Google Cloud MCP Server

by krzko

gcp-error-reporting-get-group-details

Retrieve detailed information about error groups in Google Cloud Error Reporting to analyze and troubleshoot application issues.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The core handler function for the 'gcp-error-reporting-get-group-details' tool. It authenticates with Google Cloud, fetches detailed error group information and recent error events using the Error Reporting REST API, parses and formats the data into a comprehensive Markdown report including group metadata, event details (timestamps, service context, messages, HTTP requests, source locations), and suggested investigation steps.
    async ({ groupId, timeRange, 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 || "24h";
        const actualPageSize = pageSize || 10;
    
        // 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 event details
            period = "PERIOD_1_DAY";
            break;
        }
    
        // First, get the error group details using projects.groups/get
        // The group name format should be: projects/{projectId}/groups/{groupId}
        const groupName = `projects/${projectId}/groups/${groupId}`;
        const groupApiUrl = `https://clouderrorreporting.googleapis.com/v1beta1/${groupName}`;
    
        // Get group details
        const groupResponse = await fetch(groupApiUrl, {
          method: "GET",
          headers: {
            Authorization: `Bearer ${token.token}`,
            Accept: "application/json",
          },
        });
    
        if (!groupResponse.ok) {
          const errorText = await groupResponse.text();
          throw new GcpMcpError(
            `Failed to fetch error group details: ${errorText}`,
            "FAILED_PRECONDITION",
            groupResponse.status,
          );
        }
    
        const groupData = await groupResponse.json();
    
        // Build query parameters for events API
        // groupId should be the raw group identifier for the events API
        const params = new URLSearchParams({
          groupId: groupId,
          "timeRange.period": period,
          pageSize: actualPageSize.toString(),
        });
    
        // Make REST API call to list events
        const apiUrl = `https://clouderrorreporting.googleapis.com/v1beta1/projects/${projectId}/events?${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 events: ${errorText}`,
            "FAILED_PRECONDITION",
            response.status,
          );
        }
    
        const data = await response.json();
        const errorEvents = data.errorEvents || [];
    
        // Start building content with group details
        let content = `# Error Group Details\n\n`;
    
        // Add group information
        content += `**Group ID:** ${groupId}\n`;
        content += `**Project:** ${projectId}\n`;
        content += `**Group Name:** ${groupData.name || "Unknown"}\n`;
        if (groupData.resolutionStatus) {
          content += `**Resolution Status:** ${groupData.resolutionStatus}\n`;
        }
        if (groupData.trackingIssues && groupData.trackingIssues.length > 0) {
          content += `**Tracking Issues:** ${groupData.trackingIssues.length} linked\n`;
        }
        content += `**Time Range:** ${actualTimeRange}\n\n`;
    
        if (!errorEvents || errorEvents.length === 0) {
          content += `## Recent Error Events\n\nNo error events found for this group in the specified time range.`;
          return {
            content: [
              {
                type: "text",
                text: content,
              },
            ],
          };
        }
    
        content += `## Recent Error Events (${errorEvents.length})\n\n`;
    
        errorEvents.forEach((event: any, index: number) => {
          content += `### Event ${index + 1}\n\n`;
          content += `**Time:** ${new Date(event.eventTime).toLocaleString()}\n`;
          content += `**Service:** ${event.serviceContext?.service || "Unknown"}`;
          if (event.serviceContext?.version) {
            content += ` (v${event.serviceContext.version})`;
          }
          content += `\n\n`;
          content += `**Message:** ${event.message}\n\n`;
    
          if (event.context?.httpRequest) {
            const req = event.context.httpRequest;
            content += `**HTTP Request:**\n`;
            if (req.method && req.url) {
              content += `- ${req.method} ${req.url}\n`;
            }
            if (req.responseStatusCode) {
              content += `- Status: ${req.responseStatusCode}\n`;
            }
            if (req.userAgent) {
              content += `- User Agent: ${req.userAgent}\n`;
            }
            if (req.remoteIp) {
              content += `- Remote IP: ${req.remoteIp}\n`;
            }
            content += `\n`;
          }
    
          if (event.context?.reportLocation) {
            const loc = event.context.reportLocation;
            content += `**Source Location:**\n`;
            if (loc.filePath) {
              content += `- File: ${loc.filePath}`;
              if (loc.lineNumber) {
                content += `:${loc.lineNumber}`;
              }
              content += `\n`;
            }
            if (loc.functionName) {
              content += `- Function: ${loc.functionName}\n`;
            }
            content += `\n`;
          }
    
          if (event.context?.user) {
            content += `**User:** ${event.context.user}\n\n`;
          }
    
          content += `---\n\n`;
        });
    
        // Add investigation suggestions
        content += `## Investigation Steps\n\n`;
        content += `1. **Check Logs:** Use Cloud Logging to find related log entries around the error times\n`;
        content += `2. **Monitor Metrics:** Review monitoring dashboards for correlated performance metrics\n`;
        content += `3. **Recent Changes:** Check recent deployments and configuration changes\n`;
        content += `4. **Pattern Analysis:** Look for patterns in user agents, IP addresses, or request parameters\n`;
        content += `5. **Trace Analysis:** If available, examine distributed traces for request flow\n\n`;
    
        return {
          content: [
            {
              type: "text",
              text: content,
            },
          ],
        };
      } catch (error: unknown) {
        const errorMessage =
          error instanceof Error ? error.message : "Unknown error";
        throw new GcpMcpError(
          `Failed to get error group details: ${errorMessage}`,
          "INTERNAL_ERROR",
          500,
        );
      }
    },
  • Zod-based input schema validation for the tool, defining parameters: groupId (required string), timeRange (optional string, default '24h'), pageSize (optional number 1-100, default 10).
    inputSchema: {
      groupId: z.string().describe("Error group ID to get details for"),
      timeRange: z
        .string()
        .optional()
        .default("24h")
        .describe('Time range to query events (e.g., "1h", "24h", "7d")'),
      pageSize: z
        .number()
        .min(1)
        .max(100)
        .default(10)
        .describe("Maximum number of error events to return"),
    },
  • Registration of the tool on the MCP server within the registerErrorReportingTools function, specifying name, metadata (title, description), input schema, and handler implementation.
      "gcp-error-reporting-get-group-details",
      {
        title: "Get Error Group Details",
        description:
          "Get detailed information about a specific error group including recent events",
        inputSchema: {
          groupId: z.string().describe("Error group ID to get details for"),
          timeRange: z
            .string()
            .optional()
            .default("24h")
            .describe('Time range to query events (e.g., "1h", "24h", "7d")'),
          pageSize: z
            .number()
            .min(1)
            .max(100)
            .default(10)
            .describe("Maximum number of error events to return"),
        },
      },
      async ({ groupId, timeRange, 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 || "24h";
          const actualPageSize = pageSize || 10;
    
          // 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 event details
              period = "PERIOD_1_DAY";
              break;
          }
    
          // First, get the error group details using projects.groups/get
          // The group name format should be: projects/{projectId}/groups/{groupId}
          const groupName = `projects/${projectId}/groups/${groupId}`;
          const groupApiUrl = `https://clouderrorreporting.googleapis.com/v1beta1/${groupName}`;
    
          // Get group details
          const groupResponse = await fetch(groupApiUrl, {
            method: "GET",
            headers: {
              Authorization: `Bearer ${token.token}`,
              Accept: "application/json",
            },
          });
    
          if (!groupResponse.ok) {
            const errorText = await groupResponse.text();
            throw new GcpMcpError(
              `Failed to fetch error group details: ${errorText}`,
              "FAILED_PRECONDITION",
              groupResponse.status,
            );
          }
    
          const groupData = await groupResponse.json();
    
          // Build query parameters for events API
          // groupId should be the raw group identifier for the events API
          const params = new URLSearchParams({
            groupId: groupId,
            "timeRange.period": period,
            pageSize: actualPageSize.toString(),
          });
    
          // Make REST API call to list events
          const apiUrl = `https://clouderrorreporting.googleapis.com/v1beta1/projects/${projectId}/events?${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 events: ${errorText}`,
              "FAILED_PRECONDITION",
              response.status,
            );
          }
    
          const data = await response.json();
          const errorEvents = data.errorEvents || [];
    
          // Start building content with group details
          let content = `# Error Group Details\n\n`;
    
          // Add group information
          content += `**Group ID:** ${groupId}\n`;
          content += `**Project:** ${projectId}\n`;
          content += `**Group Name:** ${groupData.name || "Unknown"}\n`;
          if (groupData.resolutionStatus) {
            content += `**Resolution Status:** ${groupData.resolutionStatus}\n`;
          }
          if (groupData.trackingIssues && groupData.trackingIssues.length > 0) {
            content += `**Tracking Issues:** ${groupData.trackingIssues.length} linked\n`;
          }
          content += `**Time Range:** ${actualTimeRange}\n\n`;
    
          if (!errorEvents || errorEvents.length === 0) {
            content += `## Recent Error Events\n\nNo error events found for this group in the specified time range.`;
            return {
              content: [
                {
                  type: "text",
                  text: content,
                },
              ],
            };
          }
    
          content += `## Recent Error Events (${errorEvents.length})\n\n`;
    
          errorEvents.forEach((event: any, index: number) => {
            content += `### Event ${index + 1}\n\n`;
            content += `**Time:** ${new Date(event.eventTime).toLocaleString()}\n`;
            content += `**Service:** ${event.serviceContext?.service || "Unknown"}`;
            if (event.serviceContext?.version) {
              content += ` (v${event.serviceContext.version})`;
            }
            content += `\n\n`;
            content += `**Message:** ${event.message}\n\n`;
    
            if (event.context?.httpRequest) {
              const req = event.context.httpRequest;
              content += `**HTTP Request:**\n`;
              if (req.method && req.url) {
                content += `- ${req.method} ${req.url}\n`;
              }
              if (req.responseStatusCode) {
                content += `- Status: ${req.responseStatusCode}\n`;
              }
              if (req.userAgent) {
                content += `- User Agent: ${req.userAgent}\n`;
              }
              if (req.remoteIp) {
                content += `- Remote IP: ${req.remoteIp}\n`;
              }
              content += `\n`;
            }
    
            if (event.context?.reportLocation) {
              const loc = event.context.reportLocation;
              content += `**Source Location:**\n`;
              if (loc.filePath) {
                content += `- File: ${loc.filePath}`;
                if (loc.lineNumber) {
                  content += `:${loc.lineNumber}`;
                }
                content += `\n`;
              }
              if (loc.functionName) {
                content += `- Function: ${loc.functionName}\n`;
              }
              content += `\n`;
            }
    
            if (event.context?.user) {
              content += `**User:** ${event.context.user}\n\n`;
            }
    
            content += `---\n\n`;
          });
    
          // Add investigation suggestions
          content += `## Investigation Steps\n\n`;
          content += `1. **Check Logs:** Use Cloud Logging to find related log entries around the error times\n`;
          content += `2. **Monitor Metrics:** Review monitoring dashboards for correlated performance metrics\n`;
          content += `3. **Recent Changes:** Check recent deployments and configuration changes\n`;
          content += `4. **Pattern Analysis:** Look for patterns in user agents, IP addresses, or request parameters\n`;
          content += `5. **Trace Analysis:** If available, examine distributed traces for request flow\n\n`;
    
          return {
            content: [
              {
                type: "text",
                text: content,
              },
            ],
          };
        } catch (error: unknown) {
          const errorMessage =
            error instanceof Error ? error.message : "Unknown error";
          throw new GcpMcpError(
            `Failed to get error group details: ${errorMessage}`,
            "INTERNAL_ERROR",
            500,
          );
        }
      },
    );
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