diff --git a/src/git/README.md b/src/git/README.md index c94ca7e..caf0129 100644 --- a/src/git/README.md +++ b/src/git/README.md @@ -53,6 +53,13 @@ Please note that mcp-server-git is currently in early development. The functiona - `max_count` (number, optional): Maximum number of commits to show (default: 10) - Returns: Array of commit entries with hash, author, date, and message +8. `git_create_branch` + - Creates a new branch + - Inputs: + - `repo_path` (string): Path to Git repository + - `branch_name` (string): Name of the new branch + - `start_point` (string, optional): Starting point for the new branch + - Returns: Confirmation of branch creation ## Installation @@ -156,6 +163,29 @@ cd path/to/servers/src/git npx @modelcontextprotocol/inspector uv run mcp-server-git ``` +Running `tail -n 20 -f ~/Library/Logs/Claude/mcp*.log` will show the logs from the server and may +help you debug any issues. + +## Development + +If you are doing local development, there are two ways to test your changes: + +1. Run the MCP inspector to test your changes. See [Debugging](#debugging) for run instructions. + +2. Test using the Claude desktop app. Add the following to your `claude_desktop_config.json`: + +```json +"git": { + "command": "uv", + "args": [ + "--directory", + "//mcp-servers/src/git", + "run", + "mcp-server-git" + ] +} +``` + ## License This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository. diff --git a/src/git/src/mcp_server_git/server.py b/src/git/src/mcp_server_git/server.py index fe1e3f5..02fae58 100644 --- a/src/git/src/mcp_server_git/server.py +++ b/src/git/src/mcp_server_git/server.py @@ -39,6 +39,11 @@ class GitLog(BaseModel): repo_path: str max_count: int = 10 +class GitCreateBranch(BaseModel): + repo_path: str + branch_name: str + base_branch: str | None = None + class GitTools(str, Enum): STATUS = "git_status" DIFF_UNSTAGED = "git_diff_unstaged" @@ -47,6 +52,7 @@ class GitTools(str, Enum): ADD = "git_add" RESET = "git_reset" LOG = "git_log" + CREATE_BRANCH = "git_create_branch" def git_status(repo: git.Repo) -> str: return repo.git.status() @@ -81,6 +87,15 @@ def git_log(repo: git.Repo, max_count: int = 10) -> list[str]: ) return log +def git_create_branch(repo: git.Repo, branch_name: str, base_branch: str | None = None) -> str: + if base_branch: + base = repo.refs[base_branch] + else: + base = repo.active_branch + + repo.create_head(branch_name, base) + return f"Created branch '{branch_name}' from '{base.name}'" + async def serve(repository: Path | None) -> None: logger = logging.getLogger(__name__) @@ -132,6 +147,11 @@ async def serve(repository: Path | None) -> None: description="Shows the commit logs", inputSchema=GitLog.schema(), ), + Tool( + name=GitTools.CREATE_BRANCH, + description="Creates a new branch from an optional base branch", + inputSchema=GitCreateBranch.schema(), + ), ] async def list_repos() -> Sequence[str]: @@ -218,6 +238,17 @@ async def serve(repository: Path | None) -> None: text="Commit history:\n" + "\n".join(log) )] + case GitTools.CREATE_BRANCH: + result = git_create_branch( + repo, + arguments["branch_name"], + arguments.get("base_branch") + ) + return [TextContent( + type="text", + text=result + )] + case _: raise ValueError(f"Unknown tool: {name}")