ask-gemini
Analyze files or ask questions using Google's Gemini models with options for model selection, sandbox testing, and structured edit suggestions.
Instructions
model selection [-m], sandbox [-s], and changeMode:boolean for providing edits
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | Analysis request. Use @ syntax to include files (e.g., '@largefile.js explain what this does') or ask general questions | |
| model | No | Optional model to use (e.g., 'gemini-2.5-flash'). If not specified, uses the default model (gemini-2.5-pro). | |
| sandbox | No | Use sandbox mode (-s flag) to safely test code changes, execute scripts, or run potentially risky operations in an isolated environment | |
| changeMode | No | Enable structured change mode - formats prompts to prevent tool errors and returns structured edit suggestions that Claude can apply directly | |
| chunkIndex | No | Which chunk to return (1-based) | |
| chunkCacheKey | No | Optional cache key for continuation | |
| powershellPath | No | Optional custom PowerShell executable path (e.g., 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' or 'pwsh'). If not specified, auto-detects available PowerShell. |
Implementation Reference
- lib/fixed-mcp-tool.js:240-287 (handler)The handler function for the 'ask-gemini' tool within the CallToolRequestSchema handler. It processes input arguments, handles chunked responses if requested, calls the executeGeminiCLI helper for Gemini AI interaction, and returns the result as MCP content.case "ask-gemini": const { prompt, model, sandbox, changeMode, chunkIndex, chunkCacheKey, powershellPath } = args; console.error('[GMCPT] ask-gemini tool called with prompt: ' + (prompt && typeof prompt === 'string' ? prompt.substring(0, 50) + '...' : 'undefined')); console.error('[GMCPT] Model: ' + model + ', Sandbox: ' + sandbox + ', ChangeMode: ' + changeMode); if (powershellPath) { console.error('[GMCPT] Custom PowerShell path: ' + powershellPath); } if (chunkCacheKey && chunkIndex) { const result = getChunkedEdits(chunkCacheKey, parseInt(chunkIndex)); return { content: [{ type: "text", text: result }] }; } console.error('[GMCPT] About to call executeGeminiCLI...'); console.log('[MCP-TOOL] About to call executeGeminiCLI with:'); console.log('[MCP-TOOL] - prompt length:', prompt ? prompt.length : 'undefined'); console.log('[MCP-TOOL] - model:', model); console.log('[MCP-TOOL] - sandbox:', sandbox); console.log('[MCP-TOOL] - changeMode:', changeMode); console.log('[MCP-TOOL] - powershellPath:', powershellPath); const result = await executeGeminiCLI(prompt, model, sandbox, changeMode, powershellPath); console.log('[MCP-TOOL] executeGeminiCLI returned:'); console.log('[MCP-TOOL] - result type:', typeof result); console.log('[MCP-TOOL] - result length:', result ? result.length : 'null'); console.log('[MCP-TOOL] - result preview:', result && typeof result === 'string' ? result.substring(0, 100) + '...' : 'null'); console.error('[GMCPT] executeGeminiCLI completed') console.error('[GMCPT] Result type:', typeof result); console.error('[GMCPT] Result is string:', typeof result === 'string'); console.error('[GMCPT] Result length:', result ? result.length : 'undefined'); console.error('[GMCPT] Result preview:', result && typeof result === 'string' ? result.substring(0, 100) : 'undefined'); // Ensure result is a string const textResult = typeof result === 'string' ? result : JSON.stringify(result); return { content: [{ type: "text", text: textResult }] };
- lib/fixed-mcp-tool.js:63-103 (schema)The schema definition for the 'ask-gemini' tool, including name, description, and detailed inputSchema with properties for prompt, model, sandbox, changeMode, chunking parameters, and powershellPath.{ name: "ask-gemini", description: "model selection [-m], sandbox [-s], and changeMode:boolean for providing edits", inputSchema: { type: "object", properties: { prompt: { type: "string", minLength: 1, description: "Analysis request. Use @ syntax to include files (e.g., '@largefile.js explain what this does') or ask general questions" }, model: { type: "string", description: "Optional model to use (e.g., 'gemini-2.5-flash'). If not specified, uses the default model (gemini-2.5-pro)." }, sandbox: { type: "boolean", default: false, description: "Use sandbox mode (-s flag) to safely test code changes, execute scripts, or run potentially risky operations in an isolated environment" }, changeMode: { type: "boolean", default: false, description: "Enable structured change mode - formats prompts to prevent tool errors and returns structured edit suggestions that Claude can apply directly" }, chunkIndex: { type: ["number", "string"], description: "Which chunk to return (1-based)" }, chunkCacheKey: { type: "string", description: "Optional cache key for continuation" }, powershellPath: { type: "string", description: "Optional custom PowerShell executable path (e.g., 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe' or 'pwsh'). If not specified, auto-detects available PowerShell." } }, required: ["prompt"] } },
- lib/fixed-mcp-tool.js:217-219 (registration)Registers the list tools handler which returns the tools array containing the 'ask-gemini' tool definition.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools }; });
- lib/fixed-geminiExecutor.js:283-366 (helper)Core helper function that implements the actual execution of the Gemini CLI. Processes the prompt (including changeMode formatting), constructs CLI arguments, spawns the process using PowerShell with proper environment, handles chunking for large changeMode responses, and returns the output.export async function executeGeminiCLI(prompt, model, sandbox, changeMode, powershellPath, onProgress) { console.log('executeGeminiCLI called with prompt: ' + (prompt && typeof prompt === 'string' ? prompt.substring(0, 50) + '...' : 'undefined')); console.log('API Key available: ' + (process.env.GEMINI_API_KEY ? 'YES' : 'NO')); console.log('Gemini CLI path: C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\@google\\gemini-cli\\dist\\index.js'); console.log('PowerShell path: ' + (powershellPath || POWERSHELL_EXECUTABLE)); let prompt_processed = prompt; if (changeMode) { console.log('[GMCPT] ChangeMode enabled, processing prompt...'); prompt_processed = prompt.replace(/file:(\S+)/g, '@$1'); const changeModeInstructions = `CHANGEMODE: Provide structured code edits in this format:\n\nFILE: filename:line\nOLD: exact code to replace\nNEW: replacement code\n\nExample:\nFILE: app.js:10\nOLD: console.log("hello");\nNEW: console.log("updated");`; prompt_processed = changeModeInstructions + "\n\n" + prompt_processed; console.log('[GMCPT] Processed prompt length:', prompt_processed.length); console.log('[GMCPT] First 200 chars of processed prompt:', prompt_processed && typeof prompt_processed === 'string' ? prompt_processed.substring(0, 200) : 'undefined'); } const args = []; // Add the -p flag for non-interactive mode args.push('-p', prompt_processed); // Use gemini-2.5-pro as default model if no model is specified const selectedModel = model || MODELS.PRO; args.push(CLI.FLAGS.MODEL, selectedModel); if (sandbox) { args.push(CLI.FLAGS.SANDBOX); } console.log(`Executing: ${CLI.COMMANDS.GEMINI} ${args.join(' ')}`); try { // Create custom environment with GEMINI_API_KEY explicitly set const customEnv = { ...process.env, GEMINI_API_KEY: process.env.GEMINI_API_KEY }; console.log('[GMCPT] Using GEMINI_API_KEY: ' + (customEnv.GEMINI_API_KEY ? 'SET' : 'NOT SET')); console.log('[GMCPT] API Key first 10 chars: ' + (customEnv.GEMINI_API_KEY && typeof customEnv.GEMINI_API_KEY === 'string' ? customEnv.GEMINI_API_KEY.substring(0, 10) + '...' : 'NONE')); console.log('[GMCPT] Executing gemini command: ' + CLI.COMMANDS.GEMINI + ' ' + args.join(' ')); console.log('[GMCPT] Full command args: ' + JSON.stringify(args)); // Execute gemini command directly with custom environment const result = await executeCommandWithEnv(CLI.COMMANDS.GEMINI, args, customEnv, onProgress, powershellPath); if (changeMode && result.stdout) { try { // Simple change mode processing - split by lines for chunking const lines = result.stdout.split('\n'); const chunks = []; const chunkSize = 50; // lines per chunk for (let i = 0; i < lines.length; i += chunkSize) { chunks.push(lines.slice(i, i + chunkSize).join('\n')); } if (chunks.length > 1) { const cacheKey = `change_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; cacheChunks(cacheKey, chunks); return `CHUNK 1/${chunks.length} (Cache Key: ${cacheKey})\n\n${chunks[0]}\n\n[Use fetch-chunk tool with cacheKey "${cacheKey}" and chunkIndex 2-${chunks.length} to get remaining chunks]`; } else { return result.stdout; } } catch (parseError) { console.error(`Failed to parse change mode output: ${parseError.message}`); return result.stdout; } } // Ensure we return a valid string even if stdout is empty or undefined if (!result.stdout || result.stdout.trim() === '') { console.log('[GMCPT] stdout is empty, checking stderr for potential API response'); if (result.stderr && result.stderr.includes('API response')) { return result.stderr; } return 'No output received from Gemini CLI. Please check your API key and try again.'; } return result.stdout; } catch (error) { console.error(`Gemini CLI execution failed: ${error.message}`); throw error; } }
- lib/fixed-geminiExecutor.js:368-391 (helper)Helper function to retrieve specific chunks from cached changeMode responses, used by the ask-gemini handler for continuation.export function getChunkedEdits(cacheKey, chunkIndex) { try { const chunks = getChunks(cacheKey); if (!chunks || chunks.length === 0) { throw new Error('No cached chunks found for the provided cache key'); } const chunk = chunks[chunkIndex - 1]; // Convert to 0-based index if (!chunk) { throw new Error(`Chunk ${chunkIndex} not found. Available chunks: 1-${chunks.length}`); } return { content: chunk, chunk: chunkIndex, totalChunks: chunks.length, cacheKey: cacheKey, hasMore: chunkIndex < chunks.length }; } catch (error) { console.error(`Failed to retrieve chunk: ${error.message}`); throw error; } }