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