kodegen_tools_git/tools/
remote_remove.rs

1//! Git remote remove tool
2
3use kodegen_mcp_tool::{Tool, ToolExecutionContext, ToolResponse, error::McpError};
4use kodegen_mcp_schema::git::{GitRemoteRemoveArgs, GitRemoteRemovePromptArgs, GitRemoteRemoveOutput};
5use rmcp::model::{PromptArgument, PromptMessage, PromptMessageContent, PromptMessageRole};
6use std::path::Path;
7
8/// Tool for removing remote repositories
9#[derive(Clone)]
10pub struct GitRemoteRemoveTool;
11
12impl Tool for GitRemoteRemoveTool {
13    type Args = GitRemoteRemoveArgs;
14    type PromptArgs = GitRemoteRemovePromptArgs;
15
16    fn name() -> &'static str {
17        kodegen_mcp_schema::git::GIT_REMOTE_REMOVE
18    }
19
20    fn description() -> &'static str {
21        "Remove a configured remote repository. \
22         Deletes the remote from repository configuration."
23    }
24
25    fn read_only() -> bool {
26        false // Modifies repository configuration
27    }
28
29    fn destructive() -> bool {
30        true // Removes configuration entries
31    }
32
33    fn idempotent() -> bool {
34        false // Cannot remove non-existent remote
35    }
36
37    async fn execute(&self, args: Self::Args, _ctx: ToolExecutionContext) -> Result<ToolResponse<<Self::Args as kodegen_mcp_tool::ToolArgs>::Output>, McpError> {
38        let path = Path::new(&args.path);
39
40        // Open repository
41        let repo = crate::open_repo(path)
42            .await
43            .map_err(|e| McpError::Other(anyhow::anyhow!("Task execution failed: {e}")))?
44            .map_err(|e| McpError::Other(anyhow::anyhow!("{e}")))?;
45
46        // Execute remove
47        crate::remove_remote(repo, &args.name)
48            .await
49            .map_err(|e| McpError::Other(anyhow::anyhow!("{e}")))?;
50
51        // Terminal summary with ANSI colors and Nerd Font icons
52        let summary = format!(
53            "\x1b[32m Remote Removed\x1b[0m\n\
54             {} deleted from configuration",
55            args.name
56        );
57
58        Ok(ToolResponse::new(summary, GitRemoteRemoveOutput {
59            success: true,
60            name: args.name.clone(),
61            message: format!("Remote '{}' removed", args.name),
62        }))
63    }
64
65    fn prompt_arguments() -> Vec<PromptArgument> {
66        vec![]
67    }
68
69    async fn prompt(&self, _args: Self::PromptArgs) -> Result<Vec<PromptMessage>, McpError> {
70        Ok(vec![
71            PromptMessage {
72                role: PromptMessageRole::User,
73                content: PromptMessageContent::text("How do I remove a Git remote?"),
74            },
75            PromptMessage {
76                role: PromptMessageRole::Assistant,
77                content: PromptMessageContent::text(
78                    "The git_remote_remove tool deletes a configured remote from your Git \
79                     repository. This is useful for:\n\n\
80                     1. **Fork workflows**: After merging PR branches and finishing contribution, \
81                     remove the upstream or fork remote\n\n\
82                     2. **Cleanup**: Remove stale, incorrect, or abandoned remote references\n\n\
83                     3. **Migration**: Reorganizing remotes when moving repositories or changing \
84                     Git hosting\n\n\
85                     4. **Multiple remotes**: Cleaning up when you have too many remotes configured\n\n\
86                     USAGE: git_remote_remove({\"path\": \"/path/to/repo\", \"name\": \"origin\"})\n\n\
87                     PARAMETERS:\n\
88                     - path: Path to the Git repository (required)\n\
89                     - name: Name of the remote to remove, e.g., \"origin\", \"upstream\", \
90                     \"fork\" (required)\n\n\
91                     COMMON SCENARIOS:\n\n\
92                     **Scenario 1: Remove upstream after fork contribution**\n\
93                     Workflow: Clone fork -> add upstream -> fetch -> merge -> remove upstream\n\
94                     git_remote_remove({\"path\": \".\", \"name\": \"upstream\"})\n\n\
95                     **Scenario 2: Remove fork origin and switch to main repo**\n\
96                     After contributing to a project, use the main repository:\n\
97                     git_remote_remove({\"path\": \".\", \"name\": \"origin\"})\n\
98                     Then add the main repo as origin\n\n\
99                     **Scenario 3: Cleanup multiple test remotes**\n\
100                     First, list remotes: git_remote_list({\"path\": \".\"})\n\
101                     Then remove unwanted ones:\n\
102                     git_remote_remove({\"path\": \".\", \"name\": \"test-remote\"})\n\n\
103                     IMPORTANT WARNINGS:\n\n\
104                     DESTRUCTIVE: This operation deletes the remote configuration entry. \
105                     You cannot undo this without manually re-adding the remote.\n\n\
106                     NON-IDEMPOTENT: Attempting to remove a remote that doesn't exist will \
107                     fail. Always verify the remote exists before removing.\n\n\
108                     CONNECTIVITY: Removing a remote doesn't affect branches that were created \
109                     from that remote. Those branches remain in your repository.\n\n\
110                     BEST PRACTICES:\n\n\
111                     1. **Always verify first**: Use git_remote_list to see all configured \
112                     remotes before removing\n\
113                     2. **Understand the context**: Know why the remote was added and what it's \
114                     used for\n\
115                     3. **Document locally**: If removing a shared remote, ensure team knows about \
116                     the change\n\
117                     4. **Consider force sync**: After removing, use git_fetch to update your \
118                     repository state\n\n\
119                     ERROR CASES:\n\
120                     - Remote not found: \"error: Could not remove config section 'remote.xxx'\" \
121                     -> Check spelling with git_remote_list\n\
122                     - Permission denied: Check directory permissions on .git/config\n\
123                     - Not in repo: Run from repository root or provide correct path\n\n\
124                     RECOVERY:\n\
125                     If you accidentally remove a remote, re-add it with the original URL \
126                     using git_remote_add.",
127                ),
128            },
129        ])
130    }
131}