Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/git/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ Please note that mcp-server-git is currently in early development. The functiona
- `not_contains` (string, optional): The commit sha that branch should NOT contain. Do not pass anything to this param if no commit sha is specified
- Returns: List of branches

13. `git_push`
- Pushes changes to a remote repository
- Inputs:
- `repo_path` (string): Path to the Git repository
- `remote` (string, optional): The remote repository to push to (default: 'origin')
- `branch` (string, optional): The branch to push. If not specified, pushes the current branch
- `force` (boolean, optional): Force push the branch, overwriting remote history if necessary (default: false)
- `set_upstream` (boolean, optional): Set the upstream branch when pushing (git push -u) (default: false)
- Returns: Confirmation of push operation with output details

## Installation

### Using uv (recommended)
Expand Down
60 changes: 59 additions & 1 deletion src/git/src/mcp_server_git/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,28 @@ class GitBranch(BaseModel):
description="The commit sha that branch should NOT contain. Do not pass anything to this param if no commit sha is specified",
)

class GitPush(BaseModel):
repo_path: str = Field(
...,
description="The path to the Git repository.",
)
remote: str = Field(
default="origin",
description="The remote repository to push to (default: 'origin').",
)
branch: Optional[str] = Field(
None,
description="The branch to push. If not specified, pushes the current branch.",
)
force: bool = Field(
default=False,
description="Force push the branch, overwriting remote history if necessary.",
)
set_upstream: bool = Field(
default=False,
description="Set the upstream branch when pushing (git push -u).",
)


class GitTools(str, Enum):
STATUS = "git_status"
Expand All @@ -103,6 +125,7 @@ class GitTools(str, Enum):
CREATE_BRANCH = "git_create_branch"
CHECKOUT = "git_checkout"
SHOW = "git_show"
PUSH = "git_push"

BRANCH = "git_branch"

Expand Down Expand Up @@ -230,6 +253,24 @@ def git_branch(repo: git.Repo, branch_type: str, contains: str | None = None, no

return branch_info

def git_push(repo: git.Repo, remote: str = "origin", branch: str | None = None, force: bool = False, set_upstream: bool = False) -> str:
args = []
if force:
args.append("--force")
if set_upstream:
args.append("-u")

if branch:
args.extend([remote, branch])
else:
args.append(remote)

try:
result = repo.git.push(*args)
return f"Pushed successfully to {remote}: {result}"
except git.GitCommandError as e:
return f"Error pushing to {remote}: {e}"


async def serve(repository: Path | None) -> None:
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -302,7 +343,11 @@ async def list_tools() -> list[Tool]:
description="Shows the contents of a commit",
inputSchema=GitShow.model_json_schema(),
),

Tool(
name=GitTools.PUSH,
description="Pushes changes to a remote repository",
inputSchema=GitPush.model_json_schema(),
),
Tool(
name=GitTools.BRANCH,
description="List Git branches",
Expand Down Expand Up @@ -447,6 +492,19 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent]:
text=result
)]

case GitTools.PUSH:
result = git_push(
repo,
arguments.get("remote", "origin"),
arguments.get("branch", None),
arguments.get("force", False),
arguments.get("set_upstream", False),
)
return [TextContent(
type="text",
text=result
)]

case _:
raise ValueError(f"Unknown tool: {name}")

Expand Down
6 changes: 5 additions & 1 deletion src/git/tests/test_server.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest
from pathlib import Path
import git
from mcp_server_git.server import git_checkout, git_branch, git_add
from mcp_server_git.server import git_checkout, git_branch, git_add, git_push
import shutil

@pytest.fixture
Expand Down Expand Up @@ -91,3 +91,7 @@ def test_git_add_specific_files(test_repository):
assert "file1.txt" in staged_files
assert "file2.txt" not in staged_files
assert result == "Files staged successfully"

def test_git_push_no_remote(test_repository):
result = git_push(test_repository)
assert "Error pushing to origin" in result