Skip to main content
Glama
MIT License
212
15
  • Apple
  • Linux
import { AUTH_SERVER_PORT, CLIENT_ID, CLIENT_SECRET, GMAIL_CREDENTIALS_PATH, GMAIL_OAUTH_PATH, REFRESH_TOKEN } from "./config.js" import { OAuth2Client } from "google-auth-library" import fs from "fs" import http from "http" import open from "open" const AUTH_SCOPES = [ 'https://www.googleapis.com/auth/gmail.modify', 'https://www.googleapis.com/auth/gmail.compose', 'https://www.googleapis.com/auth/gmail.send', 'https://www.googleapis.com/auth/gmail.settings.basic', 'https://www.googleapis.com/auth/gmail.settings.sharing' ] const getEnvBasedCredentials = (queryConfig?: Record<string, any>) => { const clientId = queryConfig?.CLIENT_ID || CLIENT_ID const clientSecret = queryConfig?.CLIENT_SECRET || CLIENT_SECRET const refreshToken = queryConfig?.REFRESH_TOKEN || REFRESH_TOKEN if (!clientId || !clientSecret || !refreshToken) return null return { clientId, clientSecret, refreshToken } } const getFileBasedCredentials = () => { const oauthFilePresent = fs.existsSync(GMAIL_OAUTH_PATH) if (!oauthFilePresent) return null const keysContent = fs.readFileSync(GMAIL_OAUTH_PATH, 'utf8') const parsedKeys = JSON.parse(keysContent) const clientId = parsedKeys?.installed?.client_id || parsedKeys?.web?.client_id const clientSecret = parsedKeys?.installed?.client_secret || parsedKeys?.web?.client_secret let refreshToken = null if (fs.existsSync(GMAIL_CREDENTIALS_PATH)) { const gmailCredentialsFile = JSON.parse(fs.readFileSync(GMAIL_CREDENTIALS_PATH, 'utf8')) refreshToken = gmailCredentialsFile?.refresh_token } return { clientId, clientSecret, refreshToken } } export const createOAuth2Client = (queryConfig?: Record<string, any>) => { try { let credentials = getEnvBasedCredentials(queryConfig) if (!credentials) credentials = getFileBasedCredentials() const oauth2Client = new OAuth2Client({ clientId: credentials?.clientId, clientSecret: credentials?.clientSecret, redirectUri: `http://localhost:${AUTH_SERVER_PORT}/oauth2callback` }) if (credentials?.refreshToken) oauth2Client.setCredentials({ refresh_token: credentials.refreshToken }) return oauth2Client } catch (error: any) { return null } } export const launchAuthServer = async (oauth2Client: OAuth2Client) => new Promise((resolve, reject) => { const server = http.createServer() server.listen(AUTH_SERVER_PORT) const authUrl = oauth2Client.generateAuthUrl({ access_type: 'offline', scope: AUTH_SCOPES }) console.log(`Please visit this URL to authenticate: ${authUrl}`) open(authUrl) server.on('request', async (req, res) => { if (!req.url?.startsWith('/oauth2callback')) return const url = new URL(req.url, `http://localhost:${AUTH_SERVER_PORT}`) const code = url.searchParams.get('code') if (!code) { res.writeHead(400) res.end('No code provided') reject(new Error('No code provided')) return } try { const { tokens } = await oauth2Client.getToken(code) oauth2Client.setCredentials(tokens) fs.writeFileSync(GMAIL_CREDENTIALS_PATH, JSON.stringify(tokens, null, 2)) res.writeHead(200) res.end(`Authentication successful! Go to ${GMAIL_CREDENTIALS_PATH} to view your REFRESH_TOKEN. You can close this window.`) server.close() resolve(void 0) } catch (error: any) { res.writeHead(500) res.end('Authentication failed') reject(error) } }) }) export const validateCredentials = async (oauth2Client: OAuth2Client) => { try { const { credentials } = oauth2Client if (!credentials) return false const expiryDate = credentials.expiry_date const needsRefresh = !expiryDate || expiryDate <= Date.now() if (!needsRefresh) return true if (!credentials.refresh_token) return false const { credentials: tokens } = await oauth2Client.refreshAccessToken() oauth2Client.setCredentials(tokens) fs.writeFileSync(GMAIL_CREDENTIALS_PATH, JSON.stringify(tokens, null, 2)) return true } catch (error: any) { return false } }

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/shinzo-labs/gmail-mcp'

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