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
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It states the action ('Get') but does not describe traits like read-only nature, potential rate limits, authentication needs, response format, or pagination. This leaves significant gaps for an agent to understand how the tool behaves beyond its basic function.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, direct sentence with no wasted words, front-loading the core action and resource. It efficiently communicates the essential purpose without unnecessary elaboration, making it easy for an agent to parse quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the lack of annotations and output schema, the description is incomplete for a tool that retrieves data. It does not explain what 'reviews and discussions' entail, the return format, or any behavioral constraints. For a read operation with no structured output documentation, more context is needed to guide effective use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% description coverage, with the parameter 'merge_request_iid' clearly documented as the 'Internal ID of the merge request'. The description adds no additional semantic context beyond this, such as examples or usage notes, so it meets the baseline of 3 where the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('Get') and resource ('reviews and discussions for a specific merge request'), making the purpose unambiguous. However, it does not explicitly differentiate from sibling tools like 'get_merge_request_details' or 'get_commit_discussions', which might also retrieve related information, preventing a score of 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives, such as 'get_merge_request_details' for general info or 'get_commit_discussions' for commit-specific discussions. It lacks any context about prerequisites, exclusions, or recommended scenarios, relying solely on the implied need for merge request reviews.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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