diff options
| author | Dawid Rycerz <dawid@rycerz.xyz> | 2025-04-05 21:30:25 +0200 |
|---|---|---|
| committer | Dawid Rycerz <dawid@rycerz.xyz> | 2025-04-05 21:30:25 +0200 |
| commit | fdfb3abd3c595e4c5c42b4d854b152262c3b4614 (patch) | |
| tree | 209a4f23eb83cc3c6197f7097dd068c2ad024783 /servers/gitlab_glab/src/mcp_server_gitlab_glab/server.py | |
| parent | fa91e3fcbdd3b1d70f01de256e1c48fe7726ebd4 (diff) | |
feat: add listing gitlab issues to glab mcp server
Diffstat (limited to 'servers/gitlab_glab/src/mcp_server_gitlab_glab/server.py')
| -rw-r--r-- | servers/gitlab_glab/src/mcp_server_gitlab_glab/server.py | 170 |
1 files changed, 169 insertions, 1 deletions
diff --git a/servers/gitlab_glab/src/mcp_server_gitlab_glab/server.py b/servers/gitlab_glab/src/mcp_server_gitlab_glab/server.py index 958e0a7..d3fd074 100644 --- a/servers/gitlab_glab/src/mcp_server_gitlab_glab/server.py +++ b/servers/gitlab_glab/src/mcp_server_gitlab_glab/server.py @@ -120,7 +120,11 @@ class GitLabServer: or an error message. """ success, result = self.execute_glab_command( - ["api", f"/projects?search_namespaces=true&search={project_name}"], working_directory + [ + "api", + f"/projects?search_namespaces=true&search={project_name}", + ], + working_directory ) if not success: @@ -144,6 +148,109 @@ class GitLabServer: else: return {"error": f"Project '{project_name}' not found"} + def search_issues( + self, + working_directory: str, + author: str | None = None, + assignee: str | None = None, + closed: bool = False, + confidential: bool = False, + group: str | None = None, + issue_type: str | None = None, + iteration: int | None = None, + label: list[str] | None = None, + milestone: str | None = None, + not_assignee: str | None = None, + not_author: str | None = None, + not_label: list[str] | None = None, + page: int = 1, + per_page: int = 30, + project: str | None = None, + ) -> dict[str, Any]: + """Search for GitLab issues with various filters. + + Args: + working_directory: The directory to execute the command in. + author: Filter issue by author username. + assignee: Filter issue by assignee username. + closed: Get only closed issues. + confidential: Filter by confidential issues. + group: Select a group or subgroup. + issue_type: Filter issue by its type (issue, incident, test_case). + iteration: Filter issue by iteration ID. + label: Filter issue by label names. + milestone: Filter issue by milestone ID or title. + not_assignee: Filter issue by not being assigned to username. + not_author: Filter issue by not being by author username. + not_label: Filter issue by lack of label names. + page: Page number. + per_page: Number of items to list per page. + project: Select another repository. + + Returns: + A dictionary containing a list of issues with their IDs, titles, and links. + """ + # Build command arguments + args = ["issue", "list", "-O", "json"] + + # Add filter arguments + if author: + args.extend(["--author", author]) + if assignee: + args.extend(["-a", assignee]) + if closed: + args.append("-c") + if confidential: + args.append("-C") + if group: + args.extend(["-g", group]) + if issue_type: + args.extend(["-t", issue_type]) + if iteration: + args.extend(["-i", str(iteration)]) + if label: + for lbl in label: + args.extend(["-l", lbl]) + if milestone: + args.extend(["-m", milestone]) + if not_assignee: + args.extend(["--not-assignee", not_assignee]) + if not_author: + args.extend(["--not-author", not_author]) + if not_label: + for lbl in not_label: + args.extend(["--not-label", lbl]) + if page != 1: + args.extend(["-p", str(page)]) + if per_page != 30: + args.extend(["-P", str(per_page)]) + if project: + args.extend(["-R", project]) + + # Execute the command + success, result = self.execute_glab_command(args, working_directory) + + if not success: + return result + + # If the result is already a list (JSON parsed), process it + if isinstance(result, list): + issues = [] + for issue in result: + issues.append({ + "id": issue.get("id"), + "iid": issue.get("iid"), + "title": issue.get("title"), + "web_url": issue.get("web_url"), + "state": issue.get("state"), + "created_at": issue.get("created_at"), + "updated_at": issue.get("updated_at"), + }) + return {"issues": issues} + else: + # This shouldn't happen with -O json, but handle it just in case + return {"error": "Failed to parse issues list"} + def create_issue( self, title: str, @@ -251,6 +358,67 @@ def create_server(host: str = "127.0.0.1", port: int = 8080) -> FastMCP: # Add create_issue tool @mcp.tool() + def search_issues( + working_directory: str, + author: str | None = None, + assignee: str | None = None, + closed: bool = False, + confidential: bool = False, + group: str | None = None, + issue_type: str | None = None, + iteration: int | None = None, + label: list[str] | None = None, + milestone: str | None = None, + not_assignee: str | None = None, + not_author: str | None = None, + not_label: list[str] | None = None, + page: int = 1, + per_page: int = 30, + project: str | None = None, + ) -> dict[str, Any]: + """Search for GitLab issues with various filters. + + Args: + working_directory: The directory to execute the command in. + author: Filter issue by author username. + assignee: Filter issue by assignee username. + closed: Get only closed issues. + confidential: Filter by confidential issues. + group: Select a group or subgroup. + issue_type: Filter issue by its type (issue, incident, test_case). + iteration: Filter issue by iteration ID. + label: Filter issue by label names. + milestone: Filter issue by milestone ID or title. + not_assignee: Filter issue by not being assigned to username. + not_author: Filter issue by not being by author username. + not_label: Filter issue by lack of label names. + page: Page number. + per_page: Number of items to list per page. + project: Select another repository. + + Returns: + A dictionary containing a list of issues with their IDs, titles, and links. + """ + return gitlab.search_issues( + working_directory=working_directory, + author=author, + assignee=assignee, + closed=closed, + confidential=confidential, + group=group, + issue_type=issue_type, + iteration=iteration, + label=label, + milestone=milestone, + not_assignee=not_assignee, + not_author=not_author, + not_label=not_label, + page=page, + per_page=per_page, + project=project, + ) + + @mcp.tool() def create_issue( title: str, description: str, |
