Skip to main content
Glama

Google Drive MCP Server

auth.ts5.17 kB
import { authenticate } from "@google-cloud/local-auth"; import { google } from "googleapis"; import fs from "fs"; import path from "path"; export const SCOPES = [ "https://www.googleapis.com/auth/drive.readonly", "https://www.googleapis.com/auth/spreadsheets", ]; // Get credentials directory from environment variable or use default const CREDS_DIR = process.env.GDRIVE_CREDS_DIR || path.join(path.dirname(new URL(import.meta.url).pathname), "../../../"); // Ensure the credentials directory exists function ensureCredsDirectory() { try { fs.mkdirSync(CREDS_DIR, { recursive: true }); console.error(`Ensured credentials directory exists at: ${CREDS_DIR}`); } catch (error) { console.error( `Failed to create credentials directory: ${CREDS_DIR}`, error, ); throw error; } } const credentialsPath = path.join(CREDS_DIR, ".gdrive-server-credentials.json"); async function authenticateWithTimeout( keyfilePath: string, SCOPES: string[], timeoutMs = 30000, ): Promise<any | null> { const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("Authentication timed out")), timeoutMs), ); const authPromise = authenticate({ keyfilePath, scopes: SCOPES, }); try { return await Promise.race([authPromise, timeoutPromise]); } catch (error) { console.error(error); return null; } } async function authenticateAndSaveCredentials() { console.error("Launching auth flow…"); console.error("Using credentials path:", credentialsPath); const keyfilePath = path.join(CREDS_DIR, "gcp-oauth.keys.json"); console.error("Using keyfile path:", keyfilePath); const auth = await authenticateWithTimeout(keyfilePath, SCOPES); if (auth) { const newAuth = new google.auth.OAuth2(); newAuth.setCredentials(auth.credentials); } try { const { credentials } = await auth.refreshAccessToken(); console.error("Received new credentials with scopes:", credentials.scope); // Ensure directory exists before saving ensureCredsDirectory(); fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2)); console.error( "Credentials saved successfully with refresh token to:", credentialsPath, ); auth.setCredentials(credentials); return auth; } catch (error) { console.error("Error refreshing token during initial auth:", error); return auth; } } // Try to load credentials without prompting for auth export async function loadCredentialsQuietly() { console.error("Attempting to load credentials from:", credentialsPath); const oauth2Client = new google.auth.OAuth2( process.env.CLIENT_ID, process.env.CLIENT_SECRET, ); if (!fs.existsSync(credentialsPath)) { console.error("No credentials file found"); return null; } try { const savedCreds = JSON.parse(fs.readFileSync(credentialsPath, "utf-8")); console.error("Loaded existing credentials with scopes:", savedCreds.scope); oauth2Client.setCredentials(savedCreds); const expiryDate = new Date(savedCreds.expiry_date); const now = new Date(); const fiveMinutes = 5 * 60 * 1000; const timeToExpiry = expiryDate.getTime() - now.getTime(); console.error("Token expiry status:", { expiryDate: expiryDate.toISOString(), timeToExpiryMinutes: Math.floor(timeToExpiry / (60 * 1000)), hasRefreshToken: !!savedCreds.refresh_token, }); if (timeToExpiry < fiveMinutes && savedCreds.refresh_token) { console.error("Attempting to refresh token using refresh_token"); try { const response = await oauth2Client.refreshAccessToken(); const newCreds = response.credentials; ensureCredsDirectory(); fs.writeFileSync(credentialsPath, JSON.stringify(newCreds, null, 2)); oauth2Client.setCredentials(newCreds); console.error("Token refreshed and saved successfully"); } catch (error) { console.error("Failed to refresh token:", error); return null; } } return oauth2Client; } catch (error) { console.error("Error loading credentials:", error); return null; } } // Get valid credentials, prompting for auth if necessary export async function getValidCredentials(forceAuth = false) { if (!forceAuth) { const quietAuth = await loadCredentialsQuietly(); if (quietAuth) { return quietAuth; } } return await authenticateAndSaveCredentials(); } // Background refresh that never prompts for auth export function setupTokenRefresh() { console.error("Setting up automatic token refresh interval (45 minutes)"); return setInterval( async () => { try { console.error("Running scheduled token refresh check"); const auth = await loadCredentialsQuietly(); if (auth) { google.options({ auth }); console.error("Completed scheduled token refresh"); } else { console.error("Skipping token refresh - no valid credentials"); } } catch (error) { console.error("Error in automatic token refresh:", error); } }, 45 * 60 * 1000, ); }

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/isaacphi/mcp-gdrive'

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