git_iris/mcp/tools/
codereview.rs

1//! MCP code review tool implementation
2//!
3//! This module provides the MCP tool for generating code reviews with options for
4//! staged changes, unstaged changes, and specific commits.
5
6use crate::commit::service::IrisCommitService;
7use crate::config::Config as GitIrisConfig;
8use crate::git::GitRepo;
9use crate::log_debug;
10use crate::mcp::tools::utils::{
11    GitIrisTool, apply_custom_instructions, create_text_result, resolve_git_repo,
12    validate_repository_parameter,
13};
14
15use rmcp::handler::server::tool::cached_schema_for_type;
16use rmcp::model::{CallToolResult, Tool};
17use rmcp::schemars;
18
19use serde::{Deserialize, Serialize};
20use std::borrow::Cow;
21use std::sync::Arc;
22
23/// Code review tool for generating comprehensive code reviews
24#[derive(Debug, Deserialize, Serialize, schemars::JsonSchema)]
25pub struct CodeReviewTool {
26    /// Include unstaged changes in the review
27    #[serde(default)]
28    pub include_unstaged: bool,
29
30    /// Specific commit to review (hash, branch name, or reference)
31    #[serde(default)]
32    pub commit_id: String,
33
34    /// Preset instruction set to use for the review
35    #[serde(default)]
36    pub preset: String,
37
38    /// Custom instructions for the AI
39    #[serde(default)]
40    pub custom_instructions: String,
41
42    /// Repository path (local) or URL (remote). Required.
43    pub repository: String,
44}
45
46impl CodeReviewTool {
47    /// Returns the tool definition for the code review tool
48    pub fn get_tool_definition() -> Tool {
49        Tool {
50            name: Cow::Borrowed("git_iris_code_review"),
51            description: Cow::Borrowed(
52                "Generate a comprehensive code review with options for staged changes, unstaged changes, or specific commits",
53            ),
54            input_schema: cached_schema_for_type::<Self>(),
55        }
56    }
57}
58
59#[async_trait::async_trait]
60impl GitIrisTool for CodeReviewTool {
61    /// Execute the code review tool with the provided repository and configuration
62    async fn execute(
63        &self,
64        git_repo: Arc<GitRepo>,
65        config: GitIrisConfig,
66    ) -> Result<CallToolResult, anyhow::Error> {
67        log_debug!("Generating code review with: {:?}", self);
68
69        // Validate repository parameter
70        validate_repository_parameter(&self.repository)?;
71        let git_repo = resolve_git_repo(Some(self.repository.as_str()), git_repo)?;
72        log_debug!("Using repository: {}", git_repo.repo_path().display());
73
74        // Check if local operations are required without a specific commit
75        if !self.commit_id.trim().is_empty() {
76            // Specific commit review works with remote repositories
77        } else if git_repo.is_remote()
78            && (self.include_unstaged || self.commit_id.trim().is_empty())
79        {
80            return Err(anyhow::anyhow!(
81                "Cannot review staged/unstaged changes on a remote repository"
82            ));
83        }
84
85        // Create a commit service for processing
86        let repo_path = git_repo.repo_path().clone();
87        let provider_name = &config.default_provider;
88
89        let service = IrisCommitService::new(
90            config.clone(),
91            &repo_path,
92            provider_name,
93            false, // gitmoji not needed for review
94            false, // verification not needed for review
95            GitRepo::new(&repo_path)?,
96        )?;
97
98        // Set up config with custom instructions if provided
99        let mut config_clone = config.clone();
100        apply_custom_instructions(&mut config_clone, &self.custom_instructions);
101
102        // Process the preset
103        let preset = if self.preset.trim().is_empty() {
104            "default"
105        } else {
106            &self.preset
107        };
108
109        // Generate the code review based on parameters
110        let review = if !self.commit_id.trim().is_empty() {
111            // Review a specific commit
112            service
113                .generate_review_for_commit(preset, &self.custom_instructions, &self.commit_id)
114                .await?
115        } else if self.include_unstaged {
116            // Review including unstaged changes
117            service
118                .generate_review_with_unstaged(preset, &self.custom_instructions, true)
119                .await?
120        } else {
121            // Review only staged changes (default behavior)
122            service
123                .generate_review(preset, &self.custom_instructions)
124                .await?
125        };
126
127        // Format and return the review
128        let formatted_review = review.format();
129        Ok(create_text_result(formatted_review))
130    }
131}