Skip to main content
Glama
authenticate.js6.26 kB
#!/usr/bin/env node import { OAuth2Client } from 'google-auth-library'; import * as fs from 'fs'; import * as path from 'path'; import * as readline from 'readline'; import { exec } from 'child_process'; import * as http from 'http'; import { URL } from 'url'; import { updateClaudeSettings } from './setup.js'; const TOKEN_PATH = path.join(process.env.HOME || "", ".google-sheets-mcp-token.json"); const CREDENTIALS_PATH = path.join(process.env.HOME || "", ".google-sheets-mcp-credentials.json"); const SCOPES = [ "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive.readonly" ]; function openBrowser(url) { const platform = process.platform; let command; if (platform === 'darwin') { command = `open "${url}"`; } else if (platform === 'win32') { command = `start "" "${url}"`; } else { // Linux and other Unix-like systems command = `xdg-open "${url}"`; } exec(command, (error) => { if (error) { console.log('⚠️ Could not automatically open browser. Please copy the URL above manually.'); } else { console.log('✅ Browser opened automatically!'); } }); } function startRedirectServer(oAuth2Client) { return new Promise((resolve, reject) => { const server = http.createServer((req, res) => { if (!req.url.startsWith('/?code=')) { res.writeHead(400); res.end('Invalid request'); return; } // Extract code from URL const urlParams = new URL(req.url, 'http://localhost:3000').searchParams; const code = urlParams.get('code'); if (!code) { res.writeHead(400); res.end('No authorization code received'); return; } // Send success response to browser res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(` <!DOCTYPE html> <html> <head> <title>Authorization Successful</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; margin: 40px; text-align: center; } h1 { color: #28a745; } p { color: #666; margin-top: 20px; } </style> </head> <body> <h1>✅ Authorization Successful!</h1> <p>You can close this window and return to your terminal.</p> </body> </html> `); // Close server and resolve with code server.close(); resolve(code); }); server.listen(3000, 'localhost', () => { console.log('✅ Local server listening on http://localhost:3000 (waiting for authorization...)'); }); server.on('error', (err) => { if (err.code === 'EACCES') { console.error('\n❌ Port 3000 requires elevated privileges'); reject(err); } else if (err.code === 'EADDRINUSE') { console.error('\n❌ Port 3000 is already in use'); reject(err); } else { reject(err); } }); setTimeout(() => { if (server.listening) { server.close(); reject(new Error('Authorization timeout - no redirect received within 5 minutes')); } }, 5 * 60 * 1000); // 5 minute timeout }); } async function authenticate() { console.log('\n🔐 Google Sheets MCP Authentication'); console.log('═'.repeat(60)); console.log(); // Check if credentials file exists if (!fs.existsSync(CREDENTIALS_PATH)) { console.error(`❌ Credentials file not found at: ${CREDENTIALS_PATH}`); console.error('\n📋 Please request the credentials file from the project maintainer.'); console.error(' Once received, save it to: ~/.google-sheets-mcp-credentials.json\n'); process.exit(1); } // Load credentials const credentials = JSON.parse(fs.readFileSync(CREDENTIALS_PATH, "utf-8")); const { client_id, client_secret, redirect_uris } = credentials.installed || credentials.web; const oAuth2Client = new OAuth2Client(client_id, client_secret, redirect_uris[0]); // Generate auth URL const authUrl = oAuth2Client.generateAuthUrl({ access_type: "offline", scope: SCOPES, }); console.log('📝 Step 1: Authorize Access'); console.log('─'.repeat(60)); console.log('\nOpening your browser to Google\'s authorization page...\n'); console.log('🔗 Authorization URL:'); console.log(authUrl); console.log(); // Auto-open browser openBrowser(authUrl); console.log('\n📋 In your browser:'); console.log(' 1. Sign in with YOUR Google account'); console.log(' 2. Click "Allow" to grant access'); console.log(' 3. You\'ll be automatically redirected back here'); console.log(' 4. A success page will appear in your browser'); console.log(); console.log('─'.repeat(60)); console.log(); try { // Start local server to capture redirect const authCode = await startRedirectServer(oAuth2Client); console.log('\n✅ Authorization code received!'); console.log('\n🔄 Step 2: Exchanging code for token...\n'); const { tokens } = await oAuth2Client.getToken(authCode); fs.writeFileSync(TOKEN_PATH, JSON.stringify(tokens, null, 2)); console.log('═'.repeat(60)); console.log('✅ SUCCESS! Authentication complete!'); console.log('═'.repeat(60)); console.log(); console.log('📁 Token saved to:', TOKEN_PATH); console.log(); // Automatically update Claude settings updateClaudeSettings(); console.log('🎉 Setup complete! You can now use the Google Sheets MCP server!'); console.log(); console.log('Next steps:'); console.log(' 1. Restart Claude Code to load the new MCP server'); console.log(' 2. Try asking Claude: "What Google Sheets tools are available?"'); console.log(); } catch (error) { console.error('\n❌ Error during authentication:'); console.error(' ', error.message); console.log('\n💡 Common issues:'); console.log(' - Port 80 is in use (try running with sudo)'); console.log(' - Code expired (codes are single-use and expire quickly)'); console.log(' - Network connectivity issues'); console.log('\n🔄 Please run this script again to try again.\n'); process.exit(1); } } authenticate();

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/saturnino-adrales/gdocs-mcp'

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