Skip to main content
Glama
design.md10.9 kB
# Gemini Search MCP サーバー設計 ## 概要 o3-search-mcp を参考に、Gemini Flash 2.5 + Google Search Grounding を使った MCP サーバーの設計。 ## 参考リポジトリ - [o3-search-mcp](https://github.com/yoshiko-pg/o3-search-mcp) - OpenAI o3 モデルを使った Web 検索 MCP サーバー ## ディレクトリ構造 ``` gemini-search-mcp/ ├── index.ts # メインエントリーポイント ├── package.json ├── tsconfig.json ├── .env.example ├── .gitignore ├── README.md ├── LICENSE └── docs/ └── design.md # この設計ドキュメント ``` ## 主要コンポーネント ### 1. package.json ```json { "name": "gemini-search-mcp", "version": "0.0.1", "description": "MCP server for AI agents to use Gemini 2.5 Flash with Google Search grounding", "main": "build/index.js", "type": "module", "bin": { "gemini-search-mcp": "build/index.js" }, "scripts": { "build": "tsc && chmod +x build/index.js", "prepublishOnly": "npm run build" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.13.2", "@google/genai": "^1.33.0", "zod": "^3.25.0" }, "devDependencies": { "@types/node": "^24.0.0", "typescript": "^5.8.0" }, "engines": { "node": ">=18" }, "packageManager": "pnpm@10.10.0" } ``` ### 2. index.ts(メイン実装) ```typescript #!/usr/bin/env node 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"; // 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.GOOGLE_API_KEY || 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: GOOGLE_API_KEY or 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); }); ``` ### 3. .env.example ```bash # Required: Google AI API Key # Get your key at: https://aistudio.google.com/apikey GOOGLE_API_KEY=your_api_key_here # ============================================================ # Model Selection # ============================================================ # Short aliases (recommended): # flash -> gemini-2.5-flash (default, balanced) # flash-lite -> gemini-2.5-flash-lite (fastest, cheapest) # pro -> gemini-2.5-pro (most capable) # # Full model names also supported: # gemini-2.5-flash # gemini-2.5-flash-lite # gemini-2.5-pro # ============================================================ GEMINI_MODEL=flash # Optional: API timeout in milliseconds (default: 120000 = 2 minutes) GEMINI_API_TIMEOUT=120000 # ============================================================ # Thinking Mode # ============================================================ # -1 = auto (model default: Flash=ON, Flash-Lite=OFF, Pro=ON) # 0 = off (disable thinking) # 1-24576 = specific token budget # Note: Pro cannot disable thinking # ============================================================ GEMINI_THINKING_BUDGET=-1 # ============================================================ # Web Search (Google Search Grounding) # ============================================================ # true = enabled (default for this MCP server) # false = disabled # ============================================================ GEMINI_WEB_SEARCH=true ``` ### 4. tsconfig.json ```json { "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "./build", "rootDir": ".", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "declaration": true, "resolveJsonModule": true }, "include": ["index.ts"], "exclude": ["node_modules", "build"] } ``` ### 5. .gitignore ``` node_modules/ build/ .env *.log ``` ## 設定方法 ### Claude Code / Claude Desktop ```json { "mcpServers": { "gemini-search": { "command": "npx", "args": ["-y", "gemini-search-mcp"], "env": { "GOOGLE_API_KEY": "your_api_key_here" } } } } ``` ### ローカル開発 ```json { "mcpServers": { "gemini-search": { "command": "node", "args": ["/path/to/gemini-search-mcp/build/index.js"], "env": { "GOOGLE_API_KEY": "your_api_key_here" } } } } ``` ## o3-search-mcp との比較 | 項目 | o3-search-mcp | gemini-search-mcp | |------|---------------|-------------------| | Provider | OpenAI | Google AI | | Model | o3, o4-mini, gpt-5 | flash, flash-lite, pro | | Search | `web_search_preview` tool | `googleSearch` grounding | | Citations | なし(テキストのみ) | groundingMetadata で引用付き | | Thinking | `reasoning.effort` (low/medium/high) | `thinkingBudget` (0-24576 tokens) | | 価格 | 有料 | 無料枠あり(2026/1/5 まで無料) | | SDK | `openai` | `@google/genai` | ## 環境変数一覧 | 変数名 | 必須 | デフォルト | 説明 | |--------|------|-----------|------| | `GOOGLE_API_KEY` | Yes | - | Google AI API キー | | `GEMINI_API_KEY` | No | - | `GOOGLE_API_KEY` の別名 | | `GEMINI_MODEL` | No | `flash` | 使用するモデル(エイリアスまたはフルネーム) | | `GEMINI_API_TIMEOUT` | No | `120000` | タイムアウト(ミリ秒) | | `GEMINI_THINKING_BUDGET` | No | `-1` | Thinking: -1=auto, 0=off, 1-24576=budget | | `GEMINI_WEB_SEARCH` | No | `true` | Web検索: true=on, false=off | ## モデル比較 | エイリアス | フルネーム | 特徴 | 用途 | |-----------|-----------|------|------| | `flash` | `gemini-2.5-flash` | バランス型 | 汎用、推論タスク | | `flash-lite` | `gemini-2.5-flash-lite` | 最速・最安 | 高速応答、大量処理 | | `pro` | `gemini-2.5-pro` | 最高性能 | 複雑な分析、高精度 | ## デフォルト動作 | 機能 | Flash | Flash-Lite | Pro | |------|-------|------------|-----| | **Thinking** | ON(Auto) | OFF | ON(常時、OFF不可) | | **Web検索** | OFF | OFF | OFF | - **Thinking**: モデルが回答前に「考える」プロセス。`thinkingBudget` で制御 - **Web検索**: Google Search Grounding。明示的に有効化が必要 ## 追加機能案(将来の拡張) 1. **Dynamic Retrieval**: `dynamicRetrievalConfig` で検索を動的に制御 2. **Search Suggestions**: `searchEntryPoint.renderedContent` で関連検索を表示 3. **マルチモーダル対応**: 画像付きクエリのサポート 4. **ストリーミング**: レスポンスのストリーミング出力 ## 参考リンク - [Grounding with Google Search | Gemini API](https://ai.google.dev/gemini-api/docs/google-search) - [Gemini API pricing](https://ai.google.dev/gemini-api/docs/pricing) - [Gemini models](https://ai.google.dev/gemini-api/docs/models) - [MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk)

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