Skip to main content
Glama
andyl25

Google Cloud MCP Server

by andyl25

list-metric-types

Retrieve available Google Cloud Monitoring metric types using search filters or expressions to identify relevant metrics for analysis.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filterNoSimple search term (e.g., "spanner") or full filter expression (e.g., "metric.type = starts_with(\"spanner\")")
pageSizeNoMaximum number of metric types to return
timeoutNoTimeout in seconds for the request

Implementation Reference

  • Registration of the 'list-metric-types' tool with the MCP server, including inline schema and handler function.
    server.tool(
      'list-metric-types',
      {
        filter: z.string().optional().describe('Simple search term (e.g., "spanner") or full filter expression (e.g., "metric.type = starts_with(\\"spanner\\")")'),
        pageSize: z.number().min(1).max(100).default(20).describe('Maximum number of metric types to return'),
        timeout: z.number().min(5).max(60).default(30).describe('Timeout in seconds for the request')
      },
      async ({ filter, pageSize, timeout }, context) => {
        try {
          const projectId = await getProjectId();
          const client = getMonitoringClient();
          
          // Format the filter if it's a simple string without operators
          let formattedFilter = filter;
          let useClientSideFiltering = false;
          
          if (filter && !filter.includes('=') && !filter.includes('>') && !filter.includes('<')) {
            // If it's just a simple term, we'll use client-side filtering
            // We don't set a filter for the API call to avoid syntax errors
            formattedFilter = undefined;
            useClientSideFiltering = true;
          }
          
          // Create a promise that rejects after the timeout
          const timeoutPromise = new Promise((_, reject) => {
            setTimeout(() => {
              reject(new Error(`Request timed out after ${timeout} seconds`));
            }, timeout * 1000);
          });
          
          // Create the actual request promise
          const requestPromise = (async () => {
            const request: any = {
              name: `projects/${projectId}`,
              pageSize
            };
            
            if (formattedFilter) {
              request.filter = formattedFilter;
            }
            
            return await client.listMetricDescriptors(request);
          })();
          
          // Race the timeout against the actual request
          const [metricDescriptors] = await Promise.race([requestPromise, timeoutPromise]) as [any];
          
          // Apply client-side filtering if needed
          let filteredDescriptors = metricDescriptors;
          if (useClientSideFiltering && filter) {
            const searchTerm = filter.toLowerCase();
            filteredDescriptors = metricDescriptors.filter((descriptor: any) => {
              // Search in the type name
              if (descriptor.type && descriptor.type.toLowerCase().includes(searchTerm)) {
                return true;
              }
              // Search in the display name
              if (descriptor.displayName && descriptor.displayName.toLowerCase().includes(searchTerm)) {
                return true;
              }
              // Search in the description
              if (descriptor.description && descriptor.description.toLowerCase().includes(searchTerm)) {
                return true;
              }
              return false;
            });
          }
          
          if (!filteredDescriptors || filteredDescriptors.length === 0) {
            return {
              content: [{
                type: 'text',
                text: `# Available Metric Types\n\nProject: ${projectId}\n${filter ? `\nSearch term: "${filter}"` : ''}\n\nNo metric types found matching your search term. Try a different search term or increase the timeout.`
              }]
            };
          }
          
          let markdown = `# Available Metric Types\n\nProject: ${projectId}\n${filter ? `\nSearch term: "${filter}"` : ''}\n${useClientSideFiltering ? `\n*Note: Filtering was performed client-side by searching for "${filter}" in metric type, display name, and description.*` : ''}\n\nFound ${filteredDescriptors.length} metric types${metricDescriptors.length !== filteredDescriptors.length ? ` (filtered from ${metricDescriptors.length} total)` : ''}.\n\n`;
          
          // Table header
          markdown += '| Metric Type | Display Name | Kind | Value Type | Description |\n';
          markdown += '|-------------|--------------|------|------------|-------------|\n';
          
          // Table rows - limit to first 50 to avoid excessive output
          const limitedDescriptors = filteredDescriptors.slice(0, 50);
          for (const descriptor of limitedDescriptors) {
            const description = (descriptor.description || '').replace(/\n/g, ' ').substring(0, 100);
            markdown += `| ${descriptor.type || ''} | ${descriptor.displayName || ''} | ${descriptor.metricKind || ''} | ${descriptor.valueType || ''} | ${description} |\n`;
          }
          
          if (filteredDescriptors.length > 50) {
            markdown += `\n*Note: Showing first 50 of ${filteredDescriptors.length} metric types. Use a more specific search term to narrow down results.*`;
          }
          
          return {
            content: [{
              type: 'text',
              text: markdown
            }]
          };
        } catch (error: unknown) {
          // Extract error message safely
          let errorMessage = 'Unknown error';
          if (error instanceof Error) {
            errorMessage = error.message;
          } else if (typeof error === 'object' && error !== null) {
            errorMessage = String((error as any).message || JSON.stringify(error));
          } else if (typeof error === 'string') {
            errorMessage = error;
          }
          
          // Check for timeout errors
          if (errorMessage.includes('timed out')) {
            throw new GcpMcpError(
              `Request timed out. Try using a filter to narrow down results or increase the timeout parameter.`,
              'DEADLINE_EXCEEDED',
              504
            );
          }
          
          // Handle other errors
          const errorCode = (error as any)?.code || 'UNKNOWN';
          const statusCode = (error as any)?.statusCode || 500;
          
          throw new GcpMcpError(
            `Failed to list metric types: ${errorMessage}`,
            errorCode,
            statusCode
          );
        }
      }
    );
  • The handler function that executes the tool: fetches metric descriptors from Google Cloud Monitoring API, applies filtering, handles timeouts, and formats results as a markdown table.
      async ({ filter, pageSize, timeout }, context) => {
        try {
          const projectId = await getProjectId();
          const client = getMonitoringClient();
          
          // Format the filter if it's a simple string without operators
          let formattedFilter = filter;
          let useClientSideFiltering = false;
          
          if (filter && !filter.includes('=') && !filter.includes('>') && !filter.includes('<')) {
            // If it's just a simple term, we'll use client-side filtering
            // We don't set a filter for the API call to avoid syntax errors
            formattedFilter = undefined;
            useClientSideFiltering = true;
          }
          
          // Create a promise that rejects after the timeout
          const timeoutPromise = new Promise((_, reject) => {
            setTimeout(() => {
              reject(new Error(`Request timed out after ${timeout} seconds`));
            }, timeout * 1000);
          });
          
          // Create the actual request promise
          const requestPromise = (async () => {
            const request: any = {
              name: `projects/${projectId}`,
              pageSize
            };
            
            if (formattedFilter) {
              request.filter = formattedFilter;
            }
            
            return await client.listMetricDescriptors(request);
          })();
          
          // Race the timeout against the actual request
          const [metricDescriptors] = await Promise.race([requestPromise, timeoutPromise]) as [any];
          
          // Apply client-side filtering if needed
          let filteredDescriptors = metricDescriptors;
          if (useClientSideFiltering && filter) {
            const searchTerm = filter.toLowerCase();
            filteredDescriptors = metricDescriptors.filter((descriptor: any) => {
              // Search in the type name
              if (descriptor.type && descriptor.type.toLowerCase().includes(searchTerm)) {
                return true;
              }
              // Search in the display name
              if (descriptor.displayName && descriptor.displayName.toLowerCase().includes(searchTerm)) {
                return true;
              }
              // Search in the description
              if (descriptor.description && descriptor.description.toLowerCase().includes(searchTerm)) {
                return true;
              }
              return false;
            });
          }
          
          if (!filteredDescriptors || filteredDescriptors.length === 0) {
            return {
              content: [{
                type: 'text',
                text: `# Available Metric Types\n\nProject: ${projectId}\n${filter ? `\nSearch term: "${filter}"` : ''}\n\nNo metric types found matching your search term. Try a different search term or increase the timeout.`
              }]
            };
          }
          
          let markdown = `# Available Metric Types\n\nProject: ${projectId}\n${filter ? `\nSearch term: "${filter}"` : ''}\n${useClientSideFiltering ? `\n*Note: Filtering was performed client-side by searching for "${filter}" in metric type, display name, and description.*` : ''}\n\nFound ${filteredDescriptors.length} metric types${metricDescriptors.length !== filteredDescriptors.length ? ` (filtered from ${metricDescriptors.length} total)` : ''}.\n\n`;
          
          // Table header
          markdown += '| Metric Type | Display Name | Kind | Value Type | Description |\n';
          markdown += '|-------------|--------------|------|------------|-------------|\n';
          
          // Table rows - limit to first 50 to avoid excessive output
          const limitedDescriptors = filteredDescriptors.slice(0, 50);
          for (const descriptor of limitedDescriptors) {
            const description = (descriptor.description || '').replace(/\n/g, ' ').substring(0, 100);
            markdown += `| ${descriptor.type || ''} | ${descriptor.displayName || ''} | ${descriptor.metricKind || ''} | ${descriptor.valueType || ''} | ${description} |\n`;
          }
          
          if (filteredDescriptors.length > 50) {
            markdown += `\n*Note: Showing first 50 of ${filteredDescriptors.length} metric types. Use a more specific search term to narrow down results.*`;
          }
          
          return {
            content: [{
              type: 'text',
              text: markdown
            }]
          };
        } catch (error: unknown) {
          // Extract error message safely
          let errorMessage = 'Unknown error';
          if (error instanceof Error) {
            errorMessage = error.message;
          } else if (typeof error === 'object' && error !== null) {
            errorMessage = String((error as any).message || JSON.stringify(error));
          } else if (typeof error === 'string') {
            errorMessage = error;
          }
          
          // Check for timeout errors
          if (errorMessage.includes('timed out')) {
            throw new GcpMcpError(
              `Request timed out. Try using a filter to narrow down results or increase the timeout parameter.`,
              'DEADLINE_EXCEEDED',
              504
            );
          }
          
          // Handle other errors
          const errorCode = (error as any)?.code || 'UNKNOWN';
          const statusCode = (error as any)?.statusCode || 500;
          
          throw new GcpMcpError(
            `Failed to list metric types: ${errorMessage}`,
            errorCode,
            statusCode
          );
        }
      }
    );
  • Zod input schema defining parameters: optional filter (search term or expression), pageSize (default 20), timeout (default 30s).
    {
      filter: z.string().optional().describe('Simple search term (e.g., "spanner") or full filter expression (e.g., "metric.type = starts_with(\\"spanner\\")")'),
      pageSize: z.number().min(1).max(100).default(20).describe('Maximum number of metric types to return'),
      timeout: z.number().min(5).max(60).default(30).describe('Timeout in seconds for the request')
    },

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/andyl25/googlecloud-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server