diff options
| author | Dawid Rycerz <dawid@rycerz.xyz> | 2025-07-15 16:05:19 +0300 |
|---|---|---|
| committer | Dawid Rycerz <dawid@rycerz.xyz> | 2025-07-15 16:05:19 +0300 |
| commit | 7a5eb0b5fb9106dd43377231d4ee03c65420bf85 (patch) | |
| tree | 4fbb72d2c4fba2db854c0d49325ece225b43a0a8 /servers/gitlab_python/src/mcp_server_gitlab_python | |
| parent | b9967d37d7c80d56b9f7e1367708be9b066882fe (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.py | 149 |
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: |
