Skip to main content
Glama
mohalmah

Google Apps Script MCP Server

by mohalmah

script_projects_get

Retrieve metadata for a Google Apps Script project using its ID, including details about deployments, versions, and executions. OAuth authentication is handled automatically.

Instructions

Get metadata of a Google Apps Script project. OAuth authentication is handled automatically.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
scriptIdYesThe ID of the script project to retrieve.
fieldsNoSelector specifying which fields to include in a partial response.
altNoData format for response.json
quotaUserNoArbitrary string assigned to a user for quota purposes.
prettyPrintNoReturns response with indentations and line breaks.

Implementation Reference

  • The main handler function `executeFunction` that makes the GET request to `https://script.googleapis.com/v1/projects/{scriptId}` to retrieve project metadata, handles OAuth via `getAuthHeaders`, validates inputs, manages query params, error handling, and logging.
    const executeFunction = async ({ scriptId, fields, alt = 'json', quotaUser, prettyPrint = true }) => {
      const baseUrl = 'https://script.googleapis.com';
    
      try {
        console.log('πŸ” Getting script project metadata for:', scriptId);
        
        // Validate required parameters
        if (!scriptId) {
          throw new Error('scriptId is required');
        }
    
        // Construct the URL with query parameters
        const url = new URL(`${baseUrl}/v1/projects/${scriptId}`);
        
        // Only add parameters that have values
        if (fields) url.searchParams.append('fields', fields);
        if (alt) url.searchParams.append('alt', alt);
        if (quotaUser) url.searchParams.append('quotaUser', quotaUser);
        if (prettyPrint !== undefined) url.searchParams.append('prettyPrint', prettyPrint.toString());
    
        console.log('🌐 API URL:', url.toString());
    
        // Get OAuth headers - this automatically handles token refresh
        const headers = await getAuthHeaders();
        console.log('πŸ” Authorization headers obtained successfully');
    
        // Perform the fetch request
        const response = await fetch(url.toString(), {
          method: 'GET',
          headers
        });
    
        console.log('πŸ“‘ API Response Status:', response.status, response.statusText);
    
        // Check if the response was successful
        if (!response.ok) {
          const errorText = await response.text();
          let errorData;
          
          try {
            errorData = JSON.parse(errorText);
          } catch (parseError) {
            errorData = { message: errorText };
          }
    
          const detailedError = {
            status: response.status,
            statusText: response.statusText,
            url: url.toString(),
            error: errorData,
            timestamp: new Date().toISOString()
          };
    
          console.error('❌ API Error Details:', JSON.stringify(detailedError, null, 2));
          
          throw new Error(`API Error (${response.status}): ${errorData.error?.message || errorData.message || 'Unknown error'}`);
        }
    
        // Parse and return the response data
        const data = await response.json();
        console.log('βœ… Successfully retrieved script project metadata');
        return data;
        
      } catch (error) {
        console.error('❌ Error getting script project metadata:', {
          message: error.message,
          stack: error.stack,
          scriptId,
          timestamp: new Date().toISOString()
        });
        
        // Return detailed error information for debugging
        return { 
          error: true,
          message: error.message,
          details: {
            scriptId,
            timestamp: new Date().toISOString(),
            errorType: error.name || 'Unknown'
          }
        };
      }
    };
  • The tool schema definition including name 'script_projects_get', description, input parameters schema with properties and required fields.
    definition: {
      type: 'function',
      function: {
        name: 'script_projects_get',
        description: 'Get metadata of a Google Apps Script project. OAuth authentication is handled automatically.',
        parameters: {
          type: 'object',
          properties: {
            scriptId: {
              type: 'string',
              description: 'The ID of the script project to retrieve.'
            },
            fields: {
              type: 'string',
              description: 'Selector specifying which fields to include in a partial response.'
            },
            alt: {
              type: 'string',
              enum: ['json'],
              description: 'Data format for response.',
              default: 'json'
            },
            quotaUser: {
              type: 'string',
              description: 'Arbitrary string assigned to a user for quota purposes.'
            },
            prettyPrint: {
              type: 'boolean',
              description: 'Returns response with indentations and line breaks.',
              default: true
            }
          },
          required: ['scriptId']
        }
      }
    }
  • lib/tools.js:8-64 (registration)
    The `discoverTools` function dynamically imports all tools listed in toolPaths (including the script_projects_get tool file), wraps their functions with logging, and returns the list of loaded tools for registration in the MCP server.
    export async function discoverTools() {
      logger.info('DISCOVERY', `Starting tool discovery for ${toolPaths.length} tool paths`);
      
      const toolPromises = toolPaths.map(async (file) => {
        try {
          logger.debug('DISCOVERY', `Loading tool from: ${file}`);
          const module = await import(`../tools/${file}`);
          
          if (!module.apiTool) {
            logger.warn('DISCOVERY', `Tool file missing apiTool export: ${file}`);
            return null;
          }
    
          const toolName = module.apiTool.definition?.function?.name;
          if (!toolName) {
            logger.warn('DISCOVERY', `Tool missing function name: ${file}`);
            return null;
          }
    
          // Wrap the original function with logging
          const originalFunction = module.apiTool.function;
          const wrappedFunction = withLogging(toolName, originalFunction);
    
          logger.debug('DISCOVERY', `Successfully loaded tool: ${toolName}`, {
            file,
            toolName,
            description: module.apiTool.definition?.function?.description
          });
    
          return {
            ...module.apiTool,
            function: wrappedFunction,
            path: file,
          };
        } catch (error) {
          logger.error('DISCOVERY', `Failed to load tool: ${file}`, {
            file,
            error: {
              message: error.message,
              stack: error.stack
            }
          });
          return null;
        }
      });
      
      const tools = (await Promise.all(toolPromises)).filter(Boolean);
      
      logger.info('DISCOVERY', `Tool discovery completed`, {
        totalPaths: toolPaths.length,
        successfullyLoaded: tools.length,
        failed: toolPaths.length - tools.length,
        toolNames: tools.map(t => t.definition?.function?.name).filter(Boolean)
      });
      
      return tools;
    }
  • tools/paths.js:11-11 (registration)
    The paths.js file lists the relative path to the script_projects_get tool file, which is used by discoverTools to import and register it.
    'google-app-script-api/apps-script-api/script-projects-get.js',
  • mcpServer.js:167-167 (registration)
    In the MCP server startup, calls discoverTools() to load all tools including script_projects_get and passes them to setupServerHandlers for MCP protocol registration.
    const tools = await discoverTools();

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/mohalmah/google-appscript-mcp-server'

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