Skip to main content
Glama
index.ts4.88 kB
#!/usr/bin/env node import { config as dotenvConfig } from "dotenv"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { GoogleGenAI } from "@google/genai"; import { z } from "zod"; import { fileURLToPath } from "url"; import { dirname, join } from "path"; // Get the directory where this script is located const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Load .env file from the script's directory (not cwd) dotenvConfig({ path: join(__dirname, "..", ".env") }); // Create server instance const server = new McpServer({ name: "gemini-search-mcp", version: "0.0.1", }); // Model presets for easy switching const MODEL_PRESETS: Record<string, string> = { // Aliases for convenience "flash": "gemini-2.5-flash", "flash-lite": "gemini-2.5-flash-lite", "pro": "gemini-2.5-pro", // Full model names also work "gemini-2.5-flash": "gemini-2.5-flash", "gemini-2.5-flash-lite": "gemini-2.5-flash-lite", "gemini-2.5-pro": "gemini-2.5-pro", }; // Resolve model name from preset or use as-is function resolveModel(input: string): string { return MODEL_PRESETS[input.toLowerCase()] || input; } // Parse boolean environment variable function parseBool(value: string | undefined, defaultValue: boolean): boolean { if (value === undefined) return defaultValue; return value.toLowerCase() === "true" || value === "1"; } // Configuration from environment variables const config = { apiKey: process.env.GEMINI_API_KEY, model: resolveModel(process.env.GEMINI_MODEL || "flash"), timeout: parseInt(process.env.GEMINI_API_TIMEOUT || "120000"), // Thinking mode: -1 = auto (default), 0 = off, 1-24576 = token budget thinkingBudget: parseInt(process.env.GEMINI_THINKING_BUDGET || "-1"), // Web search: true = on (default for this MCP), false = off webSearch: parseBool(process.env.GEMINI_WEB_SEARCH, true), }; if (!config.apiKey) { console.error("Error: GEMINI_API_KEY is required"); process.exit(1); } // Initialize Gemini client const genai = new GoogleGenAI({ apiKey: config.apiKey }); // Helper: Format grounding metadata into readable citations function formatGroundingMetadata(metadata: any): string { if (!metadata?.groundingChunks?.length) return ""; const sources = metadata.groundingChunks .filter((chunk: any) => chunk.web?.uri) .map((chunk: any, i: number) => `[${i + 1}] ${chunk.web.title || "Source"}: ${chunk.web.uri}` ) .join("\n"); return sources ? `\n\n---\n**Sources:**\n${sources}` : ""; } // Define the gemini-search tool server.tool( "gemini-search", `An AI agent powered by Gemini 2.5 Flash with Google Search grounding. Useful for finding the latest information, troubleshooting errors, researching topics, and discussing ideas. Returns responses with cited sources from the web.`, { query: z .string() .describe( "Natural language query to search and analyze. Ask questions, search for information, or request analysis of complex topics." ), }, async ({ query }) => { try { // Build generation config const generationConfig: any = {}; // Configure thinking mode // -1 = auto (model default), 0 = off, >0 = specific budget if (config.thinkingBudget >= 0) { generationConfig.thinkingConfig = { thinkingBudget: config.thinkingBudget, }; } // thinkingBudget = -1 means use model default (auto) // Configure tools (web search) const tools: any[] = []; if (config.webSearch) { tools.push({ googleSearch: {} }); } const response = await genai.models.generateContent({ model: config.model, contents: query, config: { ...(tools.length > 0 && { tools }), ...generationConfig, }, }); // Extract text response const text = response.text || "No response text available."; // Extract and format grounding sources const groundingMetadata = response.candidates?.[0]?.groundingMetadata; const citations = formatGroundingMetadata(groundingMetadata); return { content: [ { type: "text", text: text + citations, }, ], }; } catch (error) { console.error("Error calling Gemini API:", error); return { content: [ { type: "text", text: `Error: ${error instanceof Error ? error.message : "Unknown error occurred"}`, }, ], }; } } ); // Main entry point async function main() { const transport = new StdioServerTransport(); await server.connect(transport); } main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });

Latest Blog Posts

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/kidapu/Gemini-Search-MCP'

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