Skip to main content
Glama

Google Search MCP Server

setup.js•7.47 kB
#!/usr/bin/env node import fs from 'fs'; import path from 'path'; import readline from 'readline'; const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); function askQuestion(question) { return new Promise((resolve) => { rl.question(question, (answer) => { resolve(answer); }); }); } function getClaudeConfigPath() { const homeDir = process.env.USERPROFILE || process.env.HOME || ''; return path.join(homeDir, '.claude.json'); } function getGlobalConfigPath() { const homeDir = process.env.USERPROFILE || process.env.HOME || ''; return path.join(homeDir, '.google-search-mcp.json'); } async function setupGlobalConfig(apiKeys, searchEngineIds) { const configPath = getGlobalConfigPath(); const keys = []; for (let i = 0; i < apiKeys.length; i++) { keys.push({ id: `key_${i + 1}`, apiKey: apiKeys[i].trim(), searchEngineId: searchEngineIds[i]?.trim() || searchEngineIds[0]?.trim() || '', dailyUsage: 0, dailyLimit: 100, lastReset: new Date().toISOString().split('T')[0], isActive: true }); } const config = { keys: keys, lastUpdated: new Date().toISOString(), version: '1.0.0' }; fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); console.log(`āœ… Global configuration saved to: ${configPath}`); return configPath; } async function setupClaudeCode() { const claudeConfigPath = getClaudeConfigPath(); try { let claudeConfig = {}; if (fs.existsSync(claudeConfigPath)) { const data = fs.readFileSync(claudeConfigPath, 'utf8'); claudeConfig = JSON.parse(data); } if (!claudeConfig.mcpServers) { claudeConfig.mcpServers = {}; } // Add our server with platform-specific command const isWindows = process.platform === 'win32'; console.log(`šŸ–„ļø Platform detected: ${isWindows ? 'Windows' : 'Unix/Linux/macOS'}`); if (isWindows) { claudeConfig.mcpServers['google-search'] = { "type": "stdio", "command": "cmd", "args": ["/c", "npx", "-y", "@kyaniiii/google-search-mcp"], "env": {} }; } else { claudeConfig.mcpServers['google-search'] = { "type": "stdio", "command": "npx", "args": ["-y", "@kyaniiii/google-search-mcp"], "env": {} }; } // Backup original if (fs.existsSync(claudeConfigPath)) { fs.writeFileSync(`${claudeConfigPath}.backup-${Date.now()}`, fs.readFileSync(claudeConfigPath)); } // Write new config fs.writeFileSync(claudeConfigPath, JSON.stringify(claudeConfig, null, 2)); console.log(`āœ… Claude Code configured automatically`); return true; } catch (error) { console.error(`āŒ Failed to configure Claude Code: ${error.message}`); console.log('šŸ’” You can configure manually with:'); console.log(' claude mcp add google-search npx -y @kyaniiii/google-search-mcp'); return false; } } async function validateApiKey(apiKey) { if (!apiKey || apiKey.length < 30) { return false; } if (!apiKey.startsWith('AIza') && !apiKey.startsWith('Aiza')) { return false; } return true; } async function main() { console.log('šŸš€ Google Search MCP - Ultimate Setup'); console.log('=====================================\n'); // Check if already configured const globalConfigPath = getGlobalConfigPath(); if (fs.existsSync(globalConfigPath)) { console.log('āš ļø Global configuration already exists!'); const overwrite = await askQuestion('Do you want to reconfigure? (y/N): '); if (overwrite.toLowerCase() !== 'y') { console.log('Setup cancelled. Current configuration preserved.'); rl.close(); return; } } console.log('šŸ“‹ Let\'s get your Google API credentials:\n'); console.log('šŸ”— Get your API keys here:'); console.log(' → https://console.cloud.google.com/apis/credentials'); console.log(' → Enable "Custom Search API"'); console.log(' → Create "API Key"\n'); console.log('šŸ”— Get your Search Engine ID here:'); console.log(' → https://programmablesearchengine.google.com/'); console.log(' → Create new search engine'); console.log(' → Sites to search: * (for entire web)'); console.log(' → Copy the "Search engine ID"\n'); // Get API keys const apiKeysInput = await askQuestion('Enter your Google API key(s) (comma-separated for multiple): '); const apiKeys = apiKeysInput.split(',').map(k => k.trim()).filter(k => k); if (apiKeys.length === 0) { console.log('āŒ At least one API key is required!'); rl.close(); return; } // Validate API keys const invalidKeys = []; for (const key of apiKeys) { if (!(await validateApiKey(key))) { invalidKeys.push(key.substring(0, 10) + '...'); } } if (invalidKeys.length > 0) { console.log(`āš ļø Warning: These keys look invalid: ${invalidKeys.join(', ')}`); const proceed = await askQuestion('Continue anyway? (y/N): '); if (proceed.toLowerCase() !== 'y') { console.log('Setup cancelled.'); rl.close(); return; } } // Get Search Engine IDs const engineIdsInput = await askQuestion('Enter your Custom Search Engine ID(s) (comma-separated): '); const engineIds = engineIdsInput.split(',').map(e => e.trim()).filter(e => e); if (engineIds.length === 0) { console.log('āŒ At least one Search Engine ID is required!'); rl.close(); return; } if (apiKeys.length !== engineIds.length) { console.log(`ā„¹ļø Using first Search Engine ID (${engineIds[0]}) for all API keys`); } console.log('\nšŸ”§ Setting up configuration...'); try { // Setup global config await setupGlobalConfig(apiKeys, engineIds); // Setup Claude Code const claudeSuccess = await setupClaudeCode(); console.log('\nšŸŽ‰ Setup completed successfully!'); console.log('\nšŸ“Š Configuration summary:'); console.log(` • API Keys: ${apiKeys.length}`); console.log(` • Search Engines: ${engineIds.length}`); console.log(` • Daily Quota: ${apiKeys.length * 100} searches`); console.log(` • Config File: ${globalConfigPath}`); if (claudeSuccess) { console.log(' • Claude Code: āœ… Configured automatically'); console.log('\nšŸš€ Ready to use! Try asking Claude to search for something.'); } else { console.log(' • Claude Code: āš ļø Manual configuration needed'); console.log('\nšŸ“ To complete setup, run:'); console.log(' claude mcp add google-search npx -y @kyaniiii/google-search-mcp'); } console.log('\nšŸ’” Tips:'); console.log(' • Quotas reset daily at midnight UTC'); console.log(' • Server automatically rotates between API keys'); console.log(' • Configuration is stored globally and persistent'); } catch (error) { console.error(`\nāŒ Setup failed: ${error.message}`); console.log('\nPlease try again or check the documentation:'); console.log('https://github.com/Fabien-desablens/google-search-mcp#readme'); } rl.close(); } // Handle Ctrl+C gracefully process.on('SIGINT', () => { console.log('\n\nā¹ļø Setup cancelled by user'); rl.close(); process.exit(0); }); main().catch(error => { console.error('šŸ’„ Unexpected error:', error); rl.close(); process.exit(1); });

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/Fabien-desablens/google-search-mcp'

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