script_projects_versions_list
Retrieve and manage version history for Google Apps Script projects to track changes and restore previous states.
Instructions
List the versions of a Google Apps Script project.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| scriptId | Yes | The ID of the script project. | |
| pageSize | No | The number of versions to return per page. | |
| pageToken | No | The token for the next page of results. | |
| fields | No | Selector specifying which fields to include in a partial response. | |
| alt | No | Data format for response. | |
| key | No | API key for the request. | |
| access_token | No | OAuth access token. | |
| oauth_token | No | OAuth 2.0 token for the current user. | |
| prettyPrint | No | Returns response with indentations and line breaks. |
Implementation Reference
- The main handler function that executes the tool logic: authenticates via OAuth, constructs the API URL for listing script versions, makes the GET request, handles responses and errors with logging.const executeFunction = async ({ scriptId, pageSize = 100, pageToken, fields, key, access_token, oauth_token, prettyPrint = true }) => { const baseUrl = 'https://script.googleapis.com'; const startTime = Date.now(); try { logger.info('SCRIPT_VERSIONS_LIST', 'Starting script versions list request', { scriptId, pageSize, pageToken }); // Get OAuth access token const token = await getOAuthAccessToken(); // Construct the URL with query parameters const url = new URL(`${baseUrl}/v1/projects/${scriptId}/versions`); url.searchParams.append('pageSize', pageSize.toString()); if (pageToken) url.searchParams.append('pageToken', pageToken); if (fields) url.searchParams.append('fields', fields); url.searchParams.append('alt', 'json'); if (key) url.searchParams.append('key', key); if (prettyPrint) url.searchParams.append('prettyPrint', prettyPrint.toString()); logger.debug('SCRIPT_VERSIONS_LIST', 'Constructed API URL', { url: url.toString(), pathSegments: url.pathname.split('/'), queryParams: Object.fromEntries(url.searchParams) }); // Set up headers for the request const headers = { 'Accept': 'application/json', 'Authorization': `Bearer ${token}` }; logger.logAPICall('GET', url.toString(), headers); // Perform the fetch request const fetchStartTime = Date.now(); const response = await fetch(url.toString(), { method: 'GET', headers }); const fetchDuration = Date.now() - fetchStartTime; const responseSize = response.headers.get('content-length') || 'unknown'; logger.logAPIResponse('GET', url.toString(), response.status, fetchDuration, responseSize); // 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(), errorResponse: errorData, duration: Date.now() - startTime, scriptId, timestamp: new Date().toISOString() }; logger.error('SCRIPT_VERSIONS_LIST', 'API request failed', detailedError); 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(); logger.info('SCRIPT_VERSIONS_LIST', 'Successfully retrieved script versions', { scriptId, versionsCount: data.versions?.length || 0, duration: Date.now() - startTime }); console.log('✅ Successfully retrieved script versions'); return data; } catch (error) { const errorDetails = { message: error.message, stack: error.stack, scriptId, duration: Date.now() - startTime, timestamp: new Date().toISOString(), errorType: error.name || 'Unknown' }; logger.error('SCRIPT_VERSIONS_LIST', 'Error listing script versions', errorDetails); console.error('❌ Error listing script versions:', errorDetails); // Return detailed error information for debugging return { error: true, message: error.message, details: errorDetails, rawError: { name: error.name, stack: error.stack } }; } };
- The tool definition including the schema for input parameters (scriptId required, optional pagination and formatting params) and tool metadata.const apiTool = { function: executeFunction, definition: { type: 'function', function: { name: 'script_projects_versions_list', description: 'List the versions of a Google Apps Script project.', parameters: { type: 'object', properties: { scriptId: { type: 'string', description: 'The ID of the script project.' }, pageSize: { type: 'integer', description: 'The number of versions to return per page.' }, pageToken: { type: 'string', description: 'The token for the next page of results.' }, fields: { type: 'string', description: 'Selector specifying which fields to include in a partial response.' }, alt: { type: 'string', enum: ['json'], description: 'Data format for response.' }, key: { type: 'string', description: 'API key for the request.' }, access_token: { type: 'string', description: 'OAuth access token.' }, oauth_token: { type: 'string', description: 'OAuth 2.0 token for the current user.' }, prettyPrint: { type: 'boolean', description: 'Returns response with indentations and line breaks.' } }, required: ['scriptId'] } } } };
- tools/paths.js:1-18 (registration)The toolPaths array includes the path to this tool's file, allowing dynamic discovery and registration in lib/tools.js.export const toolPaths = [ 'google-app-script-api/apps-script-api/script-projects-deployments-delete.js', 'google-app-script-api/apps-script-api/script-projects-create.js', 'google-app-script-api/apps-script-api/script-projects-versions-create.js', 'google-app-script-api/apps-script-api/script-projects-deployments-create.js', 'google-app-script-api/apps-script-api/script-projects-deployments-update.js', 'google-app-script-api/apps-script-api/script-projects-deployments-list.js', 'google-app-script-api/apps-script-api/script-projects-update-content.js', 'google-app-script-api/apps-script-api/script-projects-deployments-get.js', 'google-app-script-api/apps-script-api/script-scripts-run.js', 'google-app-script-api/apps-script-api/script-projects-get.js', 'google-app-script-api/apps-script-api/script-processes-list-script-processes.js', 'google-app-script-api/apps-script-api/script-projects-get-metrics.js', 'google-app-script-api/apps-script-api/script-projects-get-content.js', 'google-app-script-api/apps-script-api/script-projects-versions-list.js', 'google-app-script-api/apps-script-api/script-projects-versions-get.js', 'google-app-script-api/apps-script-api/script-processes-list.js' ];
- lib/tools.js:8-64 (registration)Dynamic tool discovery function that imports apiTool from each path in toolPaths, wraps the handler with logging, and prepares tools for MCP registration.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; }