Skip to main content
Glama

Google Cloud MCP Server

by andyl25
auth.js10.6 kB
/** * Authentication utilities for Google Cloud services */ import { GoogleAuth } from 'google-auth-library'; import fs from 'fs'; import path from 'path'; import { configManager } from './config.js'; import { stateManager } from './state-manager.js'; // Global auth client that can be reused // Exported to allow checking auth status from other modules export let authClient = null; /** * Initialises Google Cloud authentication using either: * 1. GOOGLE_APPLICATION_CREDENTIALS environment variable pointing to a service account file * 2. GOOGLE_CLIENT_EMAIL and GOOGLE_PRIVATE_KEY environment variables * * This function supports lazy loading - it won't fail if credentials aren't available yet, * allowing the server to start without authentication and defer it until needed. * * Authentication is required for operation but can be lazy-loaded when first needed rather than * at startup, which helps prevent timeouts with Smithery. * * @param requireAuth If true, will throw an error if authentication fails. If false, will return null. * @returns Promise resolving to the authenticated GoogleAuth client or null if authentication isn't available */ export async function initGoogleAuth(requireAuth = false) { // Check if we're in lazy loading mode const lazyAuth = process.env.LAZY_AUTH !== 'false'; // Default to true if not set // If we're in lazy loading mode and not explicitly requiring auth, defer authentication if (lazyAuth && !requireAuth) { console.log('Lazy authentication enabled - deferring authentication until needed'); } try { // If we already have an auth client, return it if (authClient) { return authClient; } // Check if we need to create a temporary credentials file from environment variables if (process.env.GOOGLE_CLIENT_EMAIL && process.env.GOOGLE_PRIVATE_KEY) { try { // Create a temporary credentials file without blocking server startup const tempDir = path.join(process.cwd(), '.temp'); if (!fs.existsSync(tempDir)) { fs.mkdirSync(tempDir, { recursive: true }); } const credentials = { type: 'service_account', project_id: process.env.GOOGLE_CLOUD_PROJECT || '', private_key: process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, '\n'), client_email: process.env.GOOGLE_CLIENT_EMAIL, client_id: '', auth_uri: 'https://accounts.google.com/o/oauth2/auth', token_uri: 'https://oauth2.googleapis.com/token', auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs', client_x509_cert_url: `https://www.googleapis.com/robot/v1/metadata/x509/${encodeURIComponent(process.env.GOOGLE_CLIENT_EMAIL)}` }; const tempCredentialsPath = path.join(tempDir, 'temp-credentials.json'); fs.writeFileSync(tempCredentialsPath, JSON.stringify(credentials)); process.env.GOOGLE_APPLICATION_CREDENTIALS = tempCredentialsPath; } catch (error) { console.error(`Warning: Failed to create temporary credentials file: ${error instanceof Error ? error.message : String(error)}`); if (requireAuth) { throw new Error(`Failed to create temporary credentials file: ${error instanceof Error ? error.message : String(error)}`); } return null; } } // Check if GOOGLE_APPLICATION_CREDENTIALS is set if (!process.env.GOOGLE_APPLICATION_CREDENTIALS) { if (requireAuth) { throw new Error('Google Cloud authentication not configured. Please set GOOGLE_APPLICATION_CREDENTIALS ' + 'or both GOOGLE_CLIENT_EMAIL and GOOGLE_PRIVATE_KEY environment variables.'); } return null; } // Create the auth client without verifying it immediately authClient = new GoogleAuth({ scopes: [ 'https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/spanner.data', 'https://www.googleapis.com/auth/logging.read', 'https://www.googleapis.com/auth/monitoring.read' ] }); // Only verify the token if explicitly required // This prevents blocking operations during server startup if (requireAuth) { try { const client = await authClient.getClient(); await client.getAccessToken(); } catch (verifyError) { authClient = null; throw verifyError; } } return authClient; } catch (error) { // Log error but don't crash the server unless authentication is required console.error(`Auth error: ${error instanceof Error ? error.message : String(error)}`); if (requireAuth) { throw error; } return null; } } /** * Gets the project ID from the state manager, environment variables, or from the authenticated client * * @param requireAuth If true, will throw an error if project ID can't be determined. If false, will return a default value. * @returns Promise resolving to the Google Cloud project ID or a default value if not available */ export async function getProjectId(requireAuth = true) { try { // First check the state manager (fastest and most reliable method) const stateProjectId = stateManager.getCurrentProjectId(); if (stateProjectId) { console.log(`Using project ID from state manager: ${stateProjectId}`); return stateProjectId; } // Next check environment variable if (process.env.GOOGLE_CLOUD_PROJECT) { console.log(`Using project ID from environment: ${process.env.GOOGLE_CLOUD_PROJECT}`); // Store in state manager for future use await stateManager.setCurrentProjectId(process.env.GOOGLE_CLOUD_PROJECT); return process.env.GOOGLE_CLOUD_PROJECT; } // Check if we have credentials file and try to extract project ID from it if (process.env.GOOGLE_APPLICATION_CREDENTIALS) { try { const credentialsPath = process.env.GOOGLE_APPLICATION_CREDENTIALS; console.log(`Attempting to read project ID from credentials file: ${credentialsPath}`); if (fs.existsSync(credentialsPath)) { const credentialsContent = fs.readFileSync(credentialsPath, 'utf8'); const credentials = JSON.parse(credentialsContent); if (credentials.project_id) { console.log(`Found project ID in credentials file: ${credentials.project_id}`); // Store in state manager for future use await stateManager.setCurrentProjectId(credentials.project_id); return credentials.project_id; } } } catch (fileError) { console.error(`Error reading credentials file: ${fileError instanceof Error ? fileError.message : String(fileError)}`); // Continue to next method } } // Next check if we have a configured default project ID try { await configManager.initialize(); const configuredProjectId = configManager.getDefaultProjectId(); if (configuredProjectId) { console.log(`Using project ID from config: ${configuredProjectId}`); // Store in state manager for future use await stateManager.setCurrentProjectId(configuredProjectId); return configuredProjectId; } } catch (configError) { console.error(`Config error: ${configError instanceof Error ? configError.message : String(configError)}`); // Continue to next method } // Fall back to getting it from auth client try { console.log('Attempting to get project ID from auth client...'); const auth = await initGoogleAuth(requireAuth); if (!auth) { console.error('Authentication client not available'); if (requireAuth) { throw new Error('Google Cloud authentication not available. Please configure authentication to access project ID.'); } return 'unknown-project'; } console.log('Auth client available, requesting project ID...'); const projectId = await auth.getProjectId(); if (!projectId) { console.error('Auth client returned empty project ID'); if (requireAuth) { throw new Error('Could not determine Google Cloud project ID. Please set GOOGLE_CLOUD_PROJECT environment variable or use the set-project-id tool.'); } return 'unknown-project'; } console.log(`Got project ID from auth client: ${projectId}`); // Store in state manager for future use await stateManager.setCurrentProjectId(projectId); return projectId; } catch (authError) { console.error(`Auth error while getting project ID: ${authError instanceof Error ? authError.message : String(authError)}`); if (requireAuth) { throw authError; } return 'unknown-project'; } } catch (error) { console.error(`Project ID error: ${error instanceof Error ? error.message : String(error)}`); if (requireAuth) { throw error; } return 'unknown-project'; } } /** * Sets the default project ID to use for all Google Cloud operations * * @param projectId The project ID to set as default */ export async function setProjectId(projectId) { // Use the state manager to set the project ID await stateManager.setCurrentProjectId(projectId); } /** * Gets the list of recently used project IDs * * @returns Array of recent project IDs */ export async function getRecentProjectIds() { await configManager.initialize(); return configManager.getRecentProjectIds(); } //# sourceMappingURL=auth.js.map

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