Skip to main content
Glama

Google Calendar and Meet MCP Server

by INSIDE-HAIR
setup.ts•6.49 kB
#!/usr/bin/env node /** * Google Meet MCP Setup Script * * This script helps to obtain the initial OAuth2 token * to authenticate with Google Calendar API. */ import dotenv from "dotenv"; import fs from "fs/promises"; import { google } from "googleapis"; // Dynamic import for 'open' to avoid Smithery compatibility issues import path from "path"; import readline from "readline"; // Load environment variables from .env.local (if it exists) dotenv.config({ path: ".env.local" }); // Scopes required for Google Meet functionality via Calendar API and Meet API v2 const SCOPES = [ "https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/meetings.space.created", "https://www.googleapis.com/auth/meetings.space.readonly", "https://www.googleapis.com/auth/meetings.space.settings", ]; // Promisify readline question function question(query) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise((resolve) => { rl.question(query, (answer) => { rl.close(); resolve(answer); }); }); } async function main() { try { // Support both configuration methods let credentialsPath, tokenPath; if (process.env.G_OAUTH_CREDENTIALS) { // Simplified configuration (single variable) credentialsPath = process.env.G_OAUTH_CREDENTIALS; tokenPath = credentialsPath.replace(/\.json$/, ".token.json"); } else if ( process.env.GOOGLE_MEET_CREDENTIALS_PATH && process.env.GOOGLE_MEET_TOKEN_PATH ) { // Local development configuration (two variables) credentialsPath = process.env.GOOGLE_MEET_CREDENTIALS_PATH; tokenPath = process.env.GOOGLE_MEET_TOKEN_PATH; } else { // Use defaults credentialsPath = path.join(process.cwd(), "credentials.json"); tokenPath = path.join(process.cwd(), "token.json"); } console.log(`Using credentials file: ${credentialsPath}`); console.log(`Token will be saved to: ${tokenPath}`); // Check if the credentials file exists try { await fs.access(credentialsPath); } catch (error) { console.error(`Error: Credentials file not found at ${credentialsPath}`); console.error( "Please download OAuth 2.0 Client ID credentials from Google Cloud Console" ); console.error("and save them to this path."); process.exit(1); } // Automatically remove existing token file if it exists try { await fs.access(tokenPath); await fs.unlink(tokenPath); console.log(`šŸ—‘ļø Removed existing token file: ${tokenPath}`); } catch (error) { // Token file doesn't exist, which is fine console.log(`šŸ“ No existing token found - will create new one`); } // Load client secrets from the credentials file const content = await fs.readFile(credentialsPath, "utf8"); const credentials = JSON.parse(content); // Create an OAuth2 client with the given credentials // Handle both 'web' and 'installed' credential types const credentialData = credentials.web || credentials.installed; if (!credentialData) { throw new Error( 'Invalid credentials file format. Expected "web" or "installed" key.' ); } const { client_id, client_secret, redirect_uris } = credentialData; // Use the first registered redirect URI from credentials const redirectUri = redirect_uris[0] || "http://localhost:3000"; console.log(`Using redirect URI: ${redirectUri}`); const oAuth2Client = new google.auth.OAuth2( client_id, client_secret, redirectUri ); // Generate the auth URL const authUrl = oAuth2Client.generateAuthUrl({ access_type: "offline", scope: SCOPES, prompt: "consent", // Force to get refresh token redirect_uri: redirectUri, }); console.log("\n========== Google Calendar API Authentication =========="); console.log("1. You will be redirected to Google's authorization page."); console.log("2. Log in and grant the requested permissions."); console.log( "3. After authorizing, you'll be redirected to a page that may show an error." ); console.log( "4. Copy the authorization code from the URL in your browser's address bar." ); console.log(' (The code appears after "code=" in the URL)'); console.log("5. Return to this terminal and paste the code when prompted."); console.log("=======================================================\n"); console.log("Opening browser for authentication..."); try { const { default: open } = await import("open"); await open(authUrl); // Also open the OAuth code extractor helper page const extractorPath = path.join(process.cwd(), "index.html"); try { await fs.access(extractorPath); console.log("Opening OAuth code extractor helper..."); await open(`file://${extractorPath}`); console.log("šŸ’” Use the OAuth Code Extractor page to easily copy your authorization code!"); } catch { console.log("āš ļø OAuth code extractor helper not found"); } } catch { console.log("āš ļø Browser opening not available in this environment"); console.log(`šŸ“‹ Please manually visit: ${authUrl}`); } // Wait for user input const authCode = await question( "\nEnter the authorization code from the URL: " ); if (!authCode || (authCode as string).trim() === "") { console.error("Error: No authorization code provided."); process.exit(1); } console.log("\nExchanging authorization code for tokens..."); try { // Exchange authorization code for tokens const { tokens } = await oAuth2Client.getToken((authCode as string).trim()); // Save the token to disk await fs.writeFile(tokenPath, JSON.stringify(tokens, null, 2)); console.log(`\nToken saved to ${tokenPath}`); console.log( "Setup complete! You can now use the Google Meet MCP server." ); } catch (error) { console.error("\nError getting tokens:", error.message); if (error.response && error.response.data) { console.error("Error details:", error.response.data); } process.exit(1); } console.log("āœ… Setup completed successfully!"); } catch (error) { console.error("\nError during setup:", error); process.exit(1); } } // Run the main function main();

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/INSIDE-HAIR/mcp-google-calendar-and-meet'

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