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);

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