summaryrefslogtreecommitdiff
path: root/servers/gitlab_python/src/mcp_server_gitlab_python
diff options
context:
space:
mode:
authorDawid Rycerz <dawid@rycerz.xyz>2025-07-15 16:05:19 +0300
committerDawid Rycerz <dawid@rycerz.xyz>2025-07-15 16:05:19 +0300
commit7a5eb0b5fb9106dd43377231d4ee03c65420bf85 (patch)
tree4fbb72d2c4fba2db854c0d49325ece225b43a0a8 /servers/gitlab_python/src/mcp_server_gitlab_python
parentb9967d37d7c80d56b9f7e1367708be9b066882fe (diff)
feat: update gitlab-python and cursor rules
Diffstat (limited to 'servers/gitlab_python/src/mcp_server_gitlab_python')
-rw-r--r--servers/gitlab_python/src/mcp_server_gitlab_python/server.py149
1 files changed, 148 insertions, 1 deletions
diff --git a/servers/gitlab_python/src/mcp_server_gitlab_python/server.py b/servers/gitlab_python/src/mcp_server_gitlab_python/server.py
index 3005d30..9173df1 100644
--- a/servers/gitlab_python/src/mcp_server_gitlab_python/server.py
+++ b/servers/gitlab_python/src/mcp_server_gitlab_python/server.py
@@ -51,7 +51,7 @@ def get_token_from_glab_config() -> Optional[str]:
def get_gitlab_settings(working_directory: str) -> tuple[str, str]:
# URL
- url = os.environ.get("GITLAB_URL")
+ url = os.environ.get("GITLAB_HOST")
if not url:
remote_url = get_git_remote_url(working_directory)
if remote_url:
@@ -114,6 +114,118 @@ class GitLabPythonServer:
except Exception as e:
return {"error": str(e)}
+ def get_mr_diff(
+ self,
+ project: str,
+ mr_iid: int,
+ max_size_kb: int = 100,
+ filter_extensions: Optional[list[str]] = None,
+ ) -> dict[str, Any]:
+ import tempfile
+ if filter_extensions is None:
+ filter_extensions = [".lock", ".log"]
+ try:
+ proj = self.gl.projects.get(project)
+ mr = proj.mergerequests.get(mr_iid)
+ # Get the diff as a list of dicts (one per file)
+ diffs = mr.diffs.list(get_all=True)
+ # Build unified diff string
+ diff_content = ""
+ for diff in diffs:
+ old_path = diff.old_path
+ new_path = diff.new_path
+ # Filter by extension
+ if any(
+ old_path.endswith(ext) or new_path.endswith(ext)
+ for ext in filter_extensions
+ ):
+ continue
+ diff_content += f"diff --git a/{old_path} b/{new_path}\n"
+ diff_content += diff.diff + "\n"
+ diff_size_kb = len(diff_content.encode("utf-8")) / 1024
+ if diff_size_kb > max_size_kb:
+ try:
+ with tempfile.NamedTemporaryFile(
+ mode="w",
+ suffix=".diff",
+ prefix="mr_diff_",
+ delete=False,
+ encoding="utf-8"
+ ) as temp_file:
+ temp_file.write(diff_content)
+ temp_path = temp_file.name
+ return {
+ "diff_too_large": True,
+ "size_kb": round(diff_size_kb, 2),
+ "max_size_kb": max_size_kb,
+ "temp_file_path": temp_path,
+ "message": (
+ f"Diff is too large ({diff_size_kb:.2f} KB > "
+ f"{max_size_kb} KB). Content saved to temporary file: "
+ f"{temp_path}"
+ )
+ }
+ except Exception as e:
+ return {
+ "error": (
+ f"Diff is too large ({diff_size_kb:.2f} KB) and failed to "
+ f"create temporary file: {str(e)}"
+ )
+ }
+ return {
+ "diff": diff_content,
+ "size_kb": round(diff_size_kb, 2),
+ "temp_file_path": None
+ }
+ except Exception as e:
+ return {"error": str(e)}
+
+ def run_ci_pipeline(
+ self,
+ project: str,
+ branch: str = None,
+ variables: Optional[dict] = None,
+ web_mode: bool = False,
+ working_directory: str = None,
+ ) -> dict[str, Any]:
+ import subprocess
+ try:
+ proj = self.gl.projects.get(project)
+ ref = branch
+ if not ref:
+ # Try to detect current branch
+ try:
+ result = subprocess.run([
+ "git", "branch", "--show-current"
+ ], capture_output=True, text=True, check=False, cwd=working_directory)
+ if result.returncode == 0 and result.stdout.strip():
+ ref = result.stdout.strip()
+ except Exception:
+ ref = None
+ if not ref:
+ # If still no branch, let GitLab use default
+ ref = proj.default_branch
+ # Prepare variables
+ pipeline_vars = variables.copy() if variables else {}
+ if web_mode:
+ pipeline_vars["CI_PIPELINE_SOURCE"] = "web"
+ pipeline = proj.pipelines.create({
+ "ref": ref,
+ "variables": [
+ {"key": k, "value": v} for k, v in pipeline_vars.items()
+ ] if pipeline_vars else None
+ })
+ info = {
+ "success": True,
+ "pipeline_id": pipeline.id,
+ "pipeline_url": pipeline.web_url,
+ "branch": ref,
+ "web_mode": web_mode,
+ }
+ return info
+ except Exception as e:
+ return {"error": str(e)}
+
def create_server(host: str = "127.0.0.1", port: int = 8080) -> FastMCP:
mcp = FastMCP("GitLab Python", host=host, port=port)
@@ -165,6 +277,41 @@ def create_server(host: str = "127.0.0.1", port: int = 8080) -> FastMCP:
data.update(kwargs)
return server.create_issue(project, title, description, **data)
+ @mcp.tool()
+ def get_mr_diff(
+ project: str,
+ mr_iid: int,
+ working_directory: str,
+ max_size_kb: int = 100,
+ filter_extensions: Optional[list[str]] = None,
+ ) -> dict[str, Any]:
+ """Get the diff for a merge request."""
+ server = GitLabPythonServer(working_directory)
+ return server.get_mr_diff(
+ project=project,
+ mr_iid=mr_iid,
+ max_size_kb=max_size_kb,
+ filter_extensions=filter_extensions,
+ )
+
+ @mcp.tool()
+ def run_ci_pipeline(
+ project: str,
+ working_directory: str,
+ branch: str = None,
+ variables: Optional[dict] = None,
+ web_mode: bool = False,
+ ) -> dict[str, Any]:
+ """Run a CI/CD pipeline on GitLab."""
+ server = GitLabPythonServer(working_directory)
+ return server.run_ci_pipeline(
+ project=project,
+ branch=branch,
+ variables=variables,
+ web_mode=web_mode,
+ working_directory=working_directory,
+ )
+
return mcp
async def main(transport_type: str, host: str, port: int) -> None: