Skip to main content
Glama

Google Calendar MCP Server

import { OAuth2Client, Credentials } from 'google-auth-library'; import { tokenManager } from './token-manager'; import logger, { LoggerMeta } from '../utils/logger'; import { sanitizeErrorForLogging } from '../utils/security-sanitizer'; /** * Token processing and management class * Handles token validation, refresh, and storage operations */ export class TokenProcessor { private static instance: TokenProcessor; private constructor() {} public static getInstance(): TokenProcessor { if (!TokenProcessor.instance) { TokenProcessor.instance = new TokenProcessor(); } return TokenProcessor.instance; } /** * Check if user is authenticated without triggering authentication flow */ public isAuthenticated(oauth2Client: OAuth2Client): boolean { const userId = 'default-user'; // Check if we have valid credentials in OAuth2Client if (oauth2Client.credentials && oauth2Client.credentials.access_token) { if (!this.isTokenExpired(oauth2Client.credentials)) { return true; } } // Check if we have valid tokens in token manager const accessToken = tokenManager.getToken(`${userId}_access`); const refreshToken = tokenManager.getToken(userId); return !!(accessToken || refreshToken); } /** * Get authenticated client without triggering authentication flow * Returns null if not authenticated */ public async getAuthenticatedClientSafe(oauth2Client: OAuth2Client): Promise<OAuth2Client | null> { if (!this.isAuthenticated(oauth2Client)) { return null; } const userId = 'default-user'; // If credentials are already set and valid, return them if (oauth2Client.credentials && oauth2Client.credentials.access_token) { if (!this.isTokenExpired(oauth2Client.credentials)) { return oauth2Client; } } // Try to load tokens from token manager const refreshToken = tokenManager.getToken(userId); const accessToken = tokenManager.getToken(`${userId}_access`); if (accessToken) { const credentials: Credentials = { access_token: accessToken }; if (refreshToken) { credentials.refresh_token = refreshToken; } oauth2Client.setCredentials(credentials); return oauth2Client; } return null; } /** * Get or refresh token */ public async getOrRefreshToken(oauth2Client: OAuth2Client): Promise<OAuth2Client> { // If credentials are already set, check and refresh if needed if (oauth2Client.credentials && oauth2Client.credentials.access_token) { // Check if token is expired if (this.isTokenExpired(oauth2Client.credentials)) { logger.info('Token expired, refreshing...'); await this.refreshToken(oauth2Client); } return oauth2Client; } // Try to load from token manager const userId = 'default-user'; const refreshToken = tokenManager.getToken(userId); const accessToken = tokenManager.getToken(`${userId}_access`); if (accessToken) { const credentials: Credentials = { access_token: accessToken }; if (refreshToken) { credentials.refresh_token = refreshToken; } oauth2Client.setCredentials(credentials); // Check if loaded token is expired and refresh if needed if (this.isTokenExpired(credentials)) { logger.info('Loaded token is expired, refreshing...'); await this.refreshToken(oauth2Client); } return oauth2Client; } throw new Error('No valid tokens available - authentication required'); } /** * Check token expiration */ public isTokenExpired(token: Credentials): boolean { if (!token.expiry_date) return true; return token.expiry_date <= Date.now(); } /** * Refresh access token using refresh token */ public async refreshToken(oauth2Client: OAuth2Client): Promise<void> { try { // If there's no refresh token, throw error to indicate re-authentication is needed if (!oauth2Client.credentials.refresh_token) { logger.warn('No refresh token available, re-authentication required'); // Clear existing credentials oauth2Client.credentials = {}; throw new Error('No refresh token available - re-authentication required'); } // If there's a refresh token, perform normal refresh const { credentials } = await oauth2Client.refreshAccessToken(); oauth2Client.setCredentials(credentials); // Also store the refreshed access token in the token manager if (credentials.access_token) { const userId = 'default-user'; const expiresIn = credentials.expiry_date ? credentials.expiry_date - Date.now() : 3600 * 1000; tokenManager.storeToken(`${userId}_access`, credentials.access_token, expiresIn); logger.info('Successfully refreshed and stored access token'); } } catch (error) { logger.error('Failed to refresh token:', { error: sanitizeErrorForLogging(error) } as LoggerMeta); // If an error occurs, clear credentials and throw error logger.warn('Token refresh failed, re-authentication required'); oauth2Client.credentials = {}; throw new Error('Token refresh failed - re-authentication required'); } } /** * Store tokens from OAuth2Client credentials */ public storeTokensFromCredentials(oauth2Client: OAuth2Client): void { const userId = 'default-user'; const credentials = oauth2Client.credentials; if (credentials.access_token) { const expiresIn = credentials.expiry_date ? credentials.expiry_date - Date.now() : 3600 * 1000; tokenManager.storeToken(`${userId}_access`, credentials.access_token, expiresIn); logger.debug('Stored access token'); } if (credentials.refresh_token) { tokenManager.storeToken(userId, credentials.refresh_token); logger.debug('Stored refresh token'); } } /** * Clear all stored tokens */ public clearTokens(oauth2Client: OAuth2Client): void { const userId = 'default-user'; // Clear from token manager tokenManager.removeToken(userId); tokenManager.removeToken(`${userId}_access`); // Clear from OAuth2Client oauth2Client.credentials = {}; logger.info('All tokens cleared'); } /** * Get token information */ public getTokenInfo(oauth2Client: OAuth2Client): { hasAccessToken: boolean; hasRefreshToken: boolean; isExpired: boolean; expiryDate: number | null; storedAccessToken: boolean; storedRefreshToken: boolean; } { const userId = 'default-user'; const credentials = oauth2Client.credentials; return { hasAccessToken: !!credentials.access_token, hasRefreshToken: !!credentials.refresh_token, isExpired: this.isTokenExpired(credentials), expiryDate: credentials.expiry_date || null, storedAccessToken: !!tokenManager.getToken(`${userId}_access`), storedRefreshToken: !!tokenManager.getToken(userId) }; } /** * Validate token and attempt refresh if expired */ public async validateAndRefreshIfNeeded(oauth2Client: OAuth2Client): Promise<boolean> { try { if (!oauth2Client.credentials.access_token) { return false; } if (this.isTokenExpired(oauth2Client.credentials)) { await this.refreshToken(oauth2Client); } return true; } catch (error) { logger.error('Token validation failed:', { error: sanitizeErrorForLogging(error) } as LoggerMeta); return false; } } /** * Get token processor statistics */ public getStatistics(): { totalActiveTokens: number; hasValidCredentials: boolean; lastRefreshAttempt: string | null; } { const userId = 'default-user'; const accessToken = tokenManager.getToken(`${userId}_access`); const refreshToken = tokenManager.getToken(userId); let totalTokens = 0; if (accessToken) totalTokens++; if (refreshToken) totalTokens++; return { totalActiveTokens: totalTokens, hasValidCredentials: !!(accessToken || refreshToken), lastRefreshAttempt: null // Could be extended to track this }; } }

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/takumi0706/google-calendar-mcp'

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