Skip to main content
Glama

get_merge_request_reviews

Retrieve reviews and discussions for a GitLab merge request to track feedback and collaboration progress.

Instructions

Get reviews and discussions for a specific merge request

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
merge_request_iidYesInternal ID of the merge request

Implementation Reference

  • Main tool handler: Fetches and formats comprehensive MR review report including approvals, discussions (resolved/unresolved), details, pipeline status, changes, readiness analysis, detailed threads with icons/authors/files/lines, and prioritized action items.
    async def get_merge_request_reviews(gitlab_url, project_id, access_token, args):
        logging.info(f"get_merge_request_reviews called with args: {args}")
        mr_iid = args["merge_request_iid"]
    
        tasks = [
            api_get_merge_request_reviews(gitlab_url, project_id, access_token, mr_iid),
            get_merge_request_details(gitlab_url, project_id, access_token, mr_iid),
            get_merge_request_pipeline(gitlab_url, project_id, access_token, mr_iid),
            get_merge_request_changes(gitlab_url, project_id, access_token, mr_iid),
        ]
    
        try:
            reviews_result, details_result, pipeline_result, changes_result = await asyncio.gather(*tasks)
        except Exception as e:
            logging.error(f"Error in parallel API calls: {e}")
            raise Exception(f"Error fetching merge request data: {e}")
    
        discussions_status, discussions, discussions_text = reviews_result["discussions"]
        approvals_status, approvals, approvals_text = reviews_result["approvals"]
    
        details_status, mr_details, details_text = details_result
        pipeline_status, pipeline_data, pipeline_text = pipeline_result
        changes_status, changes_data, changes_text = changes_result
    
        if discussions_status != 200:
            logging.error(f"Error fetching discussions {discussions_status}: {discussions_text}")
            raise Exception(f"Error fetching discussions: {discussions_status} - {discussions_text}")
    
        result = f"# šŸ” Reviews & Discussions for MR !{mr_iid}\n\n"
    
        if details_status == 200:
            result += "## šŸ“‹ Merge Request Overview\n"
            result += f"**Title**: {mr_details.get('title', 'N/A')}\n"
            state = mr_details.get("state", "N/A")
            result += f"**Status**: {state} ({get_state_explanation(state)})\n"
            author = mr_details.get("author", {})
            author_name = author.get("name", "N/A")
            author_username = author.get("username", "N/A")
            result += f"**Author**: {author_name} (@{author_username})\n"
            result += f"**Priority**: {get_mr_priority(mr_details)}\n"
    
            if pipeline_status == 200 and pipeline_data:
                pipeline_icon = get_pipeline_status_icon(pipeline_data.get("status"))
                result += f"**Pipeline**: {pipeline_icon} {pipeline_data.get('status', 'unknown')}\n"
    
            if changes_status == 200:
                change_stats = calculate_change_stats(changes_data)
                result += f"**Changes**: {change_stats}\n"
    
            readiness = analyze_mr_readiness(mr_details, pipeline_data, approvals)
            result += f"**Merge Status**: {readiness}\n"
    
            result += f"**Updated**: {format_date(mr_details.get('updated_at', 'N/A'))}\n\n"
    
        result += get_approval_summary(approvals)
    
        result += get_discussion_summary(discussions)
    
        if discussions:
            result += "## šŸ“ Detailed Discussions\n\n"
            for discussion in discussions:
                thread_content = format_discussion_thread(discussion)
                if thread_content:
                    result += thread_content
        else:
            result += "šŸ’¬ No discussions found\n\n"
    
        result += "## šŸ“Š Action Items\n"
        action_items = []
    
        if discussions:
            unresolved_count = sum(1 for d in discussions if not d.get("resolved"))
            if unresolved_count > 0:
                action_items.append(
                    f"🟔 Resolve {unresolved_count} pending discussion{'s' if unresolved_count > 1 else ''}"
                )
    
        if approvals and approvals.get("approvals_left", 0) > 0:
            action_items.append(
                f"šŸ‘„ Obtain {approvals['approvals_left']} more approval{'s' if approvals['approvals_left'] > 1 else ''}"
            )
    
        if pipeline_status == 200 and pipeline_data and pipeline_data.get("status") == "failed":
            action_items.append("āŒ Fix failing pipeline")
    
        if details_status == 200 and mr_details.get("has_conflicts"):
            action_items.append("āš ļø Resolve merge conflicts")
    
        if action_items:
            for item in action_items:
                result += f"• {item}\n"
        else:
            result += "āœ… No action items - ready for next steps\n"
    
        return [TextContent(type="text", text=result)]
  • main.py:69-85 (schema)
    Tool schema definition in list_tools(): Specifies input as object with required integer merge_request_iid >=1.
    Tool(
        name="get_merge_request_reviews",
        description=("Get reviews and discussions for a specific " "merge request"),
        inputSchema={
            "type": "object",
            "properties": {
                "merge_request_iid": {
                    "type": "integer",
                    "minimum": 1,
                    "description": ("Internal ID of the merge request"),
                }
            },
            "required": ["merge_request_iid"],
            "additionalProperties": False,
        },
    ),
    Tool(
  • main.py:304-307 (registration)
    Tool dispatch registration in call_tool(): Maps tool name to handler invocation with config params.
    elif name == "get_merge_request_reviews":
        return await get_merge_request_reviews(
            self.config["gitlab_url"], self.config["project_id"], self.config["access_token"], arguments
        )
  • Core API helper (aliased as api_get_merge_request_reviews): Fetches paginated MR discussions and approvals data.
    async def get_merge_request_reviews(gitlab_url, project_id, access_token, mr_iid):
        discussions_result = await get_merge_request_discussions_paginated(gitlab_url, project_id, access_token, mr_iid)
        discussions_status, discussions, discussions_text = discussions_result
    
        approvals_url = f"{gitlab_url}/api/v4/projects/{project_id}/merge_requests/{mr_iid}/approvals"
        headers = _headers(access_token)
        async with aiohttp.ClientSession() as session:
            async with session.get(approvals_url, headers=headers) as approvals_response:
                if approvals_response.status == 200:
                    approvals = await approvals_response.json()
                else:
                    approvals = None
                approvals_status = approvals_response.status
                approvals_text = await approvals_response.text()
    
        return {
            "discussions": (discussions_status, discussions, discussions_text),
            "approvals": (approvals_status, approvals, approvals_text),
        }
  • Helper function to format approval summary with approver list, status, required vs received counts.
    def get_approval_summary(approvals):
        """Generate enhanced approval summary"""
        if not approvals:
            return "## šŸ‘„ Approvals\nā“ No approval information available\n\n"
    
        result = "## šŸ‘„ Approvals\n"
    
        approved_by = approvals.get("approved_by", [])
        approvals_required = approvals.get("approvals_required", 0)
        approvals_left = approvals.get("approvals_left", 0)
    
        if approved_by:
            result += f"**āœ… Approved by ({len(approved_by)} reviewer"
            result += f"{'s' if len(approved_by) > 1 else ''}):**\n"
            for approval in approved_by:
                user = approval["user"]
                result += f"  • **{user['name']}** (@{user['username']})\n"
            result += "\n"
    
        if approvals_required > 0:
            if approvals_left == 0:
                status = "āœ… Approval requirements met"
            else:
                plural = "s" if approvals_left > 1 else ""
                status = f"ā³ {approvals_left} approval{plural} needed"
            result += f"**Status**: {status}\n"
            received_count = len(approved_by)
            result += f"**Required**: {approvals_required} | **Received**: {received_count}\n\n"
        elif not approved_by:
            result += "šŸ“ No approvals yet\n\n"
    
        return result

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/amirsina-mandegari/gitlab-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server