Skip to main content
Glama
krzko

Google Cloud MCP Server

by krzko

gcp-profiler-list-profiles

List profiling data from Google Cloud Profiler to analyze application performance and identify optimization opportunities.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • Core handler that authenticates, calls the GCP Cloud Profiler API to list profiles, applies optional filters for profileType and target, uses helper functions for analysis and formatting, and returns a comprehensive Markdown report with summaries, insights, and pagination information.
    async ({ pageSize, pageToken, profileType, target }) => {
      try {
        const projectId = await getProjectId();
    
        // Initialize Google Auth client (same pattern as error reporting)
        const auth = await initGoogleAuth(true);
        if (!auth) {
          throw new GcpMcpError(
            "Google Cloud authentication not available. Please configure authentication to access profiler data.",
            "UNAUTHENTICATED",
            401,
          );
        }
        const client = await auth.getClient();
        const token = await client.getAccessToken();
    
        // Parse parameters
        const actualPageSize = pageSize || 50;
    
        // Build query parameters
        const params = new URLSearchParams({
          pageSize: actualPageSize.toString(),
        });
    
        // Add page token if provided
        if (pageToken) {
          params.set("pageToken", pageToken);
        }
    
        // Make REST API call to list profiles
        const apiUrl = `https://cloudprofiler.googleapis.com/v2/projects/${projectId}/profiles?${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 profiles: ${errorText}`,
            "FAILED_PRECONDITION",
            response.status,
          );
        }
    
        const data: ListProfilesResponse = await response.json();
        let profiles = data.profiles || [];
    
        // Apply client-side filtering if specified
        if (profileType) {
          profiles = profiles.filter((p) => p.profileType === profileType);
        }
    
        if (target) {
          profiles = profiles.filter((p) =>
            p.deployment?.target?.toLowerCase().includes(target.toLowerCase()),
          );
        }
    
        if (!profiles || profiles.length === 0) {
          let filterText = "";
          if (profileType) filterText += `Profile Type: ${profileType}\n`;
          if (target) filterText += `Target: ${target}\n`;
    
          return {
            content: [
              {
                type: "text",
                text: `# Profiles\n\nProject: ${projectId}\n${filterText}${data.nextPageToken ? `Page Token: ${pageToken || "first"}\n` : ""}No profiles found.`,
              },
            ],
          };
        }
    
        // Generate analysis and insights
        const analysis = analyseProfilePatterns(profiles);
    
        let content = `# Profiler Analysis\n\nProject: ${projectId}\n`;
        if (profileType)
          content += `Profile Type Filter: ${getProfileTypeDescription(profileType)}\n`;
        if (target) content += `Target Filter: ${target}\n`;
        if (data.nextPageToken)
          content += `Next Page Available: Use token "${data.nextPageToken}"\n`;
        if (data.skippedProfiles)
          content += `Skipped Profiles: ${data.skippedProfiles}\n`;
        content += `\n${analysis}\n\n`;
    
        content += `## Detailed Profile List\n\n`;
    
        profiles.forEach((profile, index) => {
          content += `### ${index + 1}. ${formatProfileSummary(profile)}\n`;
        });
    
        // Add pagination info if available
        if (data.nextPageToken) {
          content += `\n---\n\n**Pagination:** Use page token "${data.nextPageToken}" to get the next ${actualPageSize} results.\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 profiles: ${errorMessage}`,
          "INTERNAL_ERROR",
          500,
        );
      }
    },
  • Zod-based input schema defining optional parameters for pagination (pageSize, pageToken) and filtering (profileType, target).
    inputSchema: {
      pageSize: z
        .number()
        .min(1)
        .max(1000)
        .default(50)
        .describe("Maximum number of profiles to return (1-1000)"),
      pageToken: z
        .string()
        .optional()
        .describe("Token for pagination to get next page of results"),
      profileType: z
        .enum([
          ProfileType.CPU,
          ProfileType.WALL,
          ProfileType.HEAP,
          ProfileType.THREADS,
          ProfileType.CONTENTION,
          ProfileType.PEAK_HEAP,
          ProfileType.HEAP_ALLOC,
        ])
        .optional()
        .describe("Filter by specific profile type"),
      target: z
        .string()
        .optional()
        .describe("Filter by deployment target (service name)"),
    },
  • MCP server.tool registration for the 'gcp-profiler-list-profiles' tool, including title, description, input schema, and inline handler function.
      "gcp-profiler-list-profiles",
      {
        title: "List Profiles",
        description:
          "List profiles from Google Cloud Profiler with optional filtering and pagination",
        inputSchema: {
          pageSize: z
            .number()
            .min(1)
            .max(1000)
            .default(50)
            .describe("Maximum number of profiles to return (1-1000)"),
          pageToken: z
            .string()
            .optional()
            .describe("Token for pagination to get next page of results"),
          profileType: z
            .enum([
              ProfileType.CPU,
              ProfileType.WALL,
              ProfileType.HEAP,
              ProfileType.THREADS,
              ProfileType.CONTENTION,
              ProfileType.PEAK_HEAP,
              ProfileType.HEAP_ALLOC,
            ])
            .optional()
            .describe("Filter by specific profile type"),
          target: z
            .string()
            .optional()
            .describe("Filter by deployment target (service name)"),
        },
      },
      async ({ pageSize, pageToken, profileType, target }) => {
        try {
          const projectId = await getProjectId();
    
          // Initialize Google Auth client (same pattern as error reporting)
          const auth = await initGoogleAuth(true);
          if (!auth) {
            throw new GcpMcpError(
              "Google Cloud authentication not available. Please configure authentication to access profiler data.",
              "UNAUTHENTICATED",
              401,
            );
          }
          const client = await auth.getClient();
          const token = await client.getAccessToken();
    
          // Parse parameters
          const actualPageSize = pageSize || 50;
    
          // Build query parameters
          const params = new URLSearchParams({
            pageSize: actualPageSize.toString(),
          });
    
          // Add page token if provided
          if (pageToken) {
            params.set("pageToken", pageToken);
          }
    
          // Make REST API call to list profiles
          const apiUrl = `https://cloudprofiler.googleapis.com/v2/projects/${projectId}/profiles?${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 profiles: ${errorText}`,
              "FAILED_PRECONDITION",
              response.status,
            );
          }
    
          const data: ListProfilesResponse = await response.json();
          let profiles = data.profiles || [];
    
          // Apply client-side filtering if specified
          if (profileType) {
            profiles = profiles.filter((p) => p.profileType === profileType);
          }
    
          if (target) {
            profiles = profiles.filter((p) =>
              p.deployment?.target?.toLowerCase().includes(target.toLowerCase()),
            );
          }
    
          if (!profiles || profiles.length === 0) {
            let filterText = "";
            if (profileType) filterText += `Profile Type: ${profileType}\n`;
            if (target) filterText += `Target: ${target}\n`;
    
            return {
              content: [
                {
                  type: "text",
                  text: `# Profiles\n\nProject: ${projectId}\n${filterText}${data.nextPageToken ? `Page Token: ${pageToken || "first"}\n` : ""}No profiles found.`,
                },
              ],
            };
          }
    
          // Generate analysis and insights
          const analysis = analyseProfilePatterns(profiles);
    
          let content = `# Profiler Analysis\n\nProject: ${projectId}\n`;
          if (profileType)
            content += `Profile Type Filter: ${getProfileTypeDescription(profileType)}\n`;
          if (target) content += `Target Filter: ${target}\n`;
          if (data.nextPageToken)
            content += `Next Page Available: Use token "${data.nextPageToken}"\n`;
          if (data.skippedProfiles)
            content += `Skipped Profiles: ${data.skippedProfiles}\n`;
          content += `\n${analysis}\n\n`;
    
          content += `## Detailed Profile List\n\n`;
    
          profiles.forEach((profile, index) => {
            content += `### ${index + 1}. ${formatProfileSummary(profile)}\n`;
          });
    
          // Add pagination info if available
          if (data.nextPageToken) {
            content += `\n---\n\n**Pagination:** Use page token "${data.nextPageToken}" to get the next ${actualPageSize} results.\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 profiles: ${errorMessage}`,
            "INTERNAL_ERROR",
            500,
          );
        }
      },
    );
  • Key helper function called by the handler to analyze profile patterns, producing markdown sections with statistics, distributions, recent activity, type-specific analysis, and recommendations.
    export function analyseProfilePatterns(profiles: Profile[]): string {
      if (!profiles || profiles.length === 0) {
        return "No profiles found in the specified criteria.";
      }
    
      let analysis = `# Profile Analysis and Performance Insights\n\n`;
    
      // Profile summary statistics
      const totalProfiles = profiles.length;
      const profileTypes = [...new Set(profiles.map((p) => p.profileType))];
      const targets = [
        ...new Set(profiles.map((p) => p.deployment?.target).filter(Boolean)),
      ];
    
      analysis += `## Summary\n\n`;
      analysis += `- **Total Profiles:** ${totalProfiles}\n`;
      analysis += `- **Profile Types:** ${profileTypes.length} (${profileTypes.join(", ")})\n`;
      analysis += `- **Targets:** ${targets.length} (${targets.join(", ")})\n\n`;
    
      // Profile type distribution
      const typeDistribution = profiles.reduce(
        (acc, profile) => {
          acc[profile.profileType] = (acc[profile.profileType] || 0) + 1;
          return acc;
        },
        {} as Record<string, number>,
      );
    
      analysis += `## Profile Type Distribution\n\n`;
      Object.entries(typeDistribution)
        .sort(([, a], [, b]) => b - a)
        .forEach(([type, count]) => {
          const percentage = Math.round((count / totalProfiles) * 100);
          analysis += `- **${getProfileTypeDescription(type)}:** ${count} profiles (${percentage}%)\n`;
        });
    
      analysis += `\n`;
    
      // Recent activity analysis
      const recentProfiles = profiles
        .filter((p) => p.startTime)
        .sort(
          (a, b) =>
            new Date(b.startTime).getTime() - new Date(a.startTime).getTime(),
        )
        .slice(0, 5);
    
      if (recentProfiles.length > 0) {
        analysis += `## Recent Profile Activity\n\n`;
        recentProfiles.forEach((profile, index) => {
          const timeAgo = getTimeAgo(profile.startTime);
          analysis += `${index + 1}. **${profile.deployment?.target || "Unknown Target"}** - ${getProfileTypeDescription(profile.profileType)} (${timeAgo})\n`;
        });
        analysis += `\n`;
      }
    
      // Performance analysis by profile type
      analysis += `## Performance Analysis by Profile Type\n\n`;
    
      profileTypes.forEach((type) => {
        const typeProfiles = profiles.filter((p) => p.profileType === type);
        analysis += `### ${getProfileTypeDescription(type)}\n\n`;
        analysis += getProfileTypeAnalysis(type, typeProfiles);
        analysis += `\n`;
      });
    
      // Recommendations
      analysis += `## Recommendations\n\n`;
      analysis += getPerformanceRecommendations(profiles, typeDistribution);
    
      return analysis;
    }
  • Helper function used to format each profile summary in the list output.
    export function formatProfileSummary(profile: Profile): string {
      const profileName = profile.name || "Unknown";
      const profileType = profile.profileType || "Unknown";
      const deployment = profile.deployment || {};
      const target = deployment.target || "Unknown";
      const projectId = deployment.projectId || "Unknown";
      const startTime = profile.startTime
        ? new Date(profile.startTime).toLocaleString()
        : "Unknown";
      const duration = profile.duration || "Unknown";
    
      let summary = `## Profile: ${profileName.split("/").pop()}\n\n`;
      summary += `**Type:** ${getProfileTypeDescription(profileType)}\n`;
      summary += `**Target:** ${target}\n`;
      summary += `**Project:** ${projectId}\n`;
      summary += `**Start Time:** ${startTime}\n`;
      summary += `**Duration:** ${formatDuration(duration)}\n`;
    
      // Add labels if available
      if (profile.labels && Object.keys(profile.labels).length > 0) {
        summary += `**Labels:**\n`;
        Object.entries(profile.labels).forEach(([key, value]) => {
          summary += `  - ${key}: ${value}\n`;
        });
      }
    
      // Add deployment labels if available
      if (deployment.labels && Object.keys(deployment.labels).length > 0) {
        summary += `**Deployment Labels:**\n`;
        Object.entries(deployment.labels).forEach(([key, value]) => {
          summary += `  - ${key}: ${value}\n`;
        });
      }
    
      return summary;
    }
  • src/index.ts:224-224 (registration)
    Top-level call to register all Profiler tools (including gcp-profiler-list-profiles) on the MCP server.
    registerProfilerTools(server);
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