Skip to main content
Glama

perform_code_review

Review git changes with an LLM to identify issues and improvements based on task context and project standards.

Instructions

Performs a code review using a specified LLM on git changes. Requires being run from the root of a git repository.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
targetYesThe git target to review (e.g., 'staged', 'HEAD', or 'branch_diff').
taskDescriptionYesDescription of the task/feature/bugfix that led to these code changes.
llmProviderYesThe LLM provider to use (google, openai, anthropic).
modelNameYesThe specific model name from the provider (e.g., 'gemini-2.5-pro-preview-05-06', 'o4-mini', 'claude-3-7-sonnet-20250219').
reviewFocusNoSpecific areas or aspects to focus the review on (e.g., 'security vulnerabilities', 'performance optimizations', 'adherence to SOLID principles').
projectContextNoGeneral context about the project, its architecture, or coding standards.
diffBaseNoFor 'branch_diff' target, the base branch or commit SHA to compare against (e.g., 'main', 'develop', 'specific-commit-sha'). Required if target is 'branch_diff'.
maxTokensNoMaximum number of tokens to use for the LLM response. Defaults to 32000 if not specified.

Implementation Reference

  • Primary asynchronous handler for the 'perform_code_review' tool, orchestrating git diff retrieval, LLM prompting, review generation, and error handling.
    async (params: CodeReviewToolParams) => { try { console.error( `[MCP Server Tool] Received 'perform_code_review' request. Target: ${params.target}, Provider: ${params.llmProvider}, Model: ${params.modelName}` ); // Step 1: Get the diff from git const diffResult = await getGitDiffForReview(params); if (diffResult.noChanges) { return { content: [ { type: "text", text: "No changes detected for review." }, ], }; } // Step 2: Prepare LLM prompt and get the review const reviewResult = await generateLLMReview(params, diffResult.diff); return { content: [{ type: "text", text: reviewResult }], isError: false, // Explicitly set isError }; } catch (error: any) { console.error( "[MCP Server Tool] Error in 'perform_code_review' tool:", error.stack || error.message ); return { isError: true, content: [ { type: "text", text: `Error performing code review: ${error.message}`, }, ], }; } }
  • Zod schema (CodeReviewToolParamsSchema) defining and validating input parameters for the perform_code_review tool.
    export const CodeReviewToolParamsSchema = z.object({ target: ReviewTargetEnum.describe( "The git target to review (e.g., 'staged', 'HEAD', or 'branch_diff')." ), taskDescription: z .string() .min(1) .describe( "Description of the task/feature/bugfix that led to these code changes." ), llmProvider: LLMProviderEnum.describe( "The LLM provider to use (google, openai, anthropic)." ), modelName: z .string() .min(1) .describe( "The specific model name from the provider (e.g., 'gemini-2.5-pro-preview-05-06', 'o4-mini', 'claude-3-7-sonnet-20250219')." ), reviewFocus: z .string() .optional() .describe( "Specific areas or aspects to focus the review on (e.g., 'security vulnerabilities', 'performance optimizations', 'adherence to SOLID principles')." ), projectContext: z .string() .optional() .describe( "General context about the project, its architecture, or coding standards." ), diffBase: z .string() .optional() .describe( "For 'branch_diff' target, the base branch or commit SHA to compare against (e.g., 'main', 'develop', 'specific-commit-sha'). Required if target is 'branch_diff'." ), maxTokens: z .number() .positive() .optional() .describe( "Maximum number of tokens to use for the LLM response. Defaults to 32000 if not specified." ), });
  • src/index.ts:51-96 (registration)
    Registers the 'perform_code_review' tool with the MCP server using server.tool(), providing name, description, input schema, and handler.
    function registerCodeReviewTool(server: McpServer) { server.tool( "perform_code_review", "Performs a code review using a specified LLM on git changes. Requires being run from the root of a git repository.", CodeReviewToolParamsSchema.shape, async (params: CodeReviewToolParams) => { try { console.error( `[MCP Server Tool] Received 'perform_code_review' request. Target: ${params.target}, Provider: ${params.llmProvider}, Model: ${params.modelName}` ); // Step 1: Get the diff from git const diffResult = await getGitDiffForReview(params); if (diffResult.noChanges) { return { content: [ { type: "text", text: "No changes detected for review." }, ], }; } // Step 2: Prepare LLM prompt and get the review const reviewResult = await generateLLMReview(params, diffResult.diff); return { content: [{ type: "text", text: reviewResult }], isError: false, // Explicitly set isError }; } catch (error: any) { console.error( "[MCP Server Tool] Error in 'perform_code_review' tool:", error.stack || error.message ); return { isError: true, content: [ { type: "text", text: `Error performing code review: ${error.message}`, }, ], }; } } ); }
  • Helper function getGitDiff that retrieves git diff for specified target, called from tool handler.
    export function getGitDiff(target: ReviewTarget, baseBranch?: string): string { const execOptions: ExecSyncOptionsWithStringEncoding = { encoding: "utf8", maxBuffer: 20 * 1024 * 1024, // Increased to 20MB buffer stdio: ["pipe", "pipe", "pipe"], // pipe stderr to catch git errors }; let command: string = ""; try { // Verify it's a git repository first execSync("git rev-parse --is-inside-work-tree", { ...execOptions, stdio: "ignore", }); } catch (error) { console.error( "[MCP Server Git] Current directory is not a git repository or git is not found." ); throw new Error( "Execution directory is not a git repository or git command is not available. Please run from a git project root." ); } try { switch (target) { case "staged": command = "git diff --staged --patch-with-raw --unified=10"; // More context break; case "HEAD": command = "git diff HEAD --patch-with-raw --unified=10"; break; case "branch_diff": if (!baseBranch || baseBranch.trim() === "") { throw new Error( "Base branch/commit is required for 'branch_diff' target and cannot be empty." ); } // Sanitize baseBranch to prevent command injection // Only allow alphanumeric characters, underscore, dash, dot, and forward slash const sanitizedBaseBranch = baseBranch.replace( /[^a-zA-Z0-9_.\-/]/g, "" ); if (sanitizedBaseBranch !== baseBranch) { throw new Error( `Invalid characters in base branch name. Only alphanumeric characters, underscore, dash, dot, and forward slash are allowed. Received: "${baseBranch}"` ); } // Fetch the base branch to ensure the diff is against the latest version of it // Note: This assumes the remote is named 'origin' const fetchCommand = `git fetch origin ${sanitizedBaseBranch}:${sanitizedBaseBranch} --no-tags --quiet`; try { execSync(fetchCommand, execOptions); } catch (fetchError: any) { // Log a warning but proceed; the branch might be local or already up-to-date console.warn( `[MCP Server Git] Warning during 'git fetch' for base branch '${sanitizedBaseBranch}': ${fetchError.message}. Diff will proceed with local state.` ); } command = `git diff ${sanitizedBaseBranch}...HEAD --patch-with-raw --unified=10`; break; default: // This case should ideally be caught by Zod validation on parameters throw new Error(`Unsupported git diff target: ${target}`); } // Only log the command if in debug mode if (isDebugMode()) { console.log(`[MCP Server Git] Executing: ${command}`); } // Execute the command (execOptions has encoding:'utf8' so the result should already be a string) const diffOutput = execSync(command, execOptions); // Ensure we always have a string to work with // This is for type safety and to handle any unexpected Buffer return types const diffString = Buffer.isBuffer(diffOutput) ? diffOutput.toString('utf8') : String(diffOutput); if (!diffString.trim()) { return "No changes found for the specified target."; } return diffString; } catch (error: any) { const errorMessage = error.stderr?.toString().trim() || error.message || "Unknown git error"; console.error( `[MCP Server Git] Error getting git diff for target "${target}" (base: ${ baseBranch || "N/A" }):` ); console.error(`[MCP Server Git] Command: ${command || "N/A"}`); // Only log the full error details in debug mode if (isDebugMode()) { console.error( `[MCP Server Git] Stderr: ${error.stderr?.toString().trim()}` ); console.error( `[MCP Server Git] Stdout: ${error.stdout?.toString().trim()}` ); } throw new Error( `Failed to get git diff. Git error: ${errorMessage}. Ensure you are in a git repository and the target/base is valid.` ); } }
  • Core helper getLLMReview for calling LLM providers to generate code review text based on prompt and diff.
    export async function getLLMReview<T extends LLMProvider>( provider: T, modelName: ModelName<T>, systemPrompt: string, userMessages: CoreMessage[], maxTokens: number = 32000 ): Promise<string> { // Make sure we have the API key const apiKey = getApiKey(provider); if (!apiKey) { throw new Error( `API key for ${provider} is not configured. Please set the appropriate environment variable.` ); } // Create the LLM client with proper provider configuration let llmClient; switch (provider) { case "google": // Create Google provider with explicit API key const googleAI = createGoogleGenerativeAI({ apiKey, }); llmClient = googleAI(modelName); break; case "openai": // Create OpenAI provider with explicit API key const openaiProvider = createOpenAI({ apiKey, }); llmClient = openaiProvider(modelName); break; case "anthropic": // Create Anthropic provider with explicit API key const anthropicProvider = createAnthropic({ apiKey, }); llmClient = anthropicProvider(modelName); break; default: throw new Error(`Unsupported LLM provider: ${provider}`); } try { if (isDebugMode()) { console.log( `[MCP Server LLM] Requesting review from ${provider} model ${modelName} with max tokens ${maxTokens}.` ); } else { console.log( `[MCP Server LLM] Requesting review from ${provider} model ${modelName}.` ); } const { text, finishReason, usage, warnings } = await generateText({ model: llmClient, system: systemPrompt, messages: userMessages, maxTokens: maxTokens, // Now configurable with default value temperature: 0.2, // Lower temperature for more deterministic and factual reviews }); if (warnings && warnings.length > 0) { warnings.forEach((warning) => console.warn(`[MCP Server LLM] Warning from ${provider}:`, warning) ); } if (isDebugMode() && usage) { console.log( `[MCP Server LLM] Review received from ${provider}. Finish Reason: ${finishReason}, Tokens Used: Input=${usage.promptTokens}, Output=${usage.completionTokens}` ); } else { console.log( `[MCP Server LLM] Review received from ${provider}.` ); } return text; } catch (error: any) { console.error( `[MCP Server LLM] Error getting LLM review from ${provider} (${modelName}):`, error ); let detailedMessage = error.message; if (error.cause) { detailedMessage += ` | Cause: ${JSON.stringify(error.cause)}`; } // Attempt to get more details from common API error structures if (error.response && error.response.data && error.response.data.error) { detailedMessage += ` | API Error: ${JSON.stringify( error.response.data.error )}`; } else if (error.error && error.error.message) { // Anthropic SDK style detailedMessage += ` | API Error: ${error.error.message}`; } throw new Error( `LLM API call failed for ${provider} (${modelName}): ${detailedMessage}` ); } }
Install Server

Other Tools

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/praneybehl/claude-code-review-mcp'

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