Skip to main content
Glama

get_commit_discussions

Retrieve discussions and comments on commits within a GitLab merge request to review feedback and track changes.

Instructions

Get discussions and comments on commits within a specific merge request

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
merge_request_iidYesInternal ID of the merge request

Implementation Reference

  • The main handler function that implements the tool logic: fetches merge request commits and discussions, matches discussions to commits based on head_sha, and formats a detailed markdown report with summaries and per-commit details.
    async def get_commit_discussions(gitlab_url, project_id, access_token, args):
        """Get discussions/comments on commits within a merge request"""
        logging.info(f"get_commit_discussions called with args: {args}")
        mr_iid = args["merge_request_iid"]
    
        try:
            commits_result = await get_merge_request_commits(gitlab_url, project_id, access_token, mr_iid)
            commits_status, commits_data, commits_error = commits_result
    
            if commits_status != 200:
                logging.error(f"Error fetching merge request commits: " f"{commits_status} - {commits_error}")
                raise Exception(f"Error fetching merge request commits: {commits_error}")
    
            if not commits_data:
                return [TextContent(type="text", text="No commits found in this merge request.")]
    
            logging.info(f"Getting ALL MR discussions for MR #{mr_iid}...")
            discussions_result = await get_merge_request_discussions_paginated(gitlab_url, project_id, access_token, mr_iid)
            discussions_status, discussions_data, discussions_error = discussions_result
    
            if discussions_status != 200:
                logging.error(f"Error fetching MR discussions: " f"{discussions_status} - {discussions_error}")
                discussions_data = []
    
            commit_map = {commit["id"]: commit for commit in commits_data}
    
            commits_with_discussions = {}
            total_discussions = 0
    
            for discussion in discussions_data:
                notes = discussion.get("notes", [])
                for note in notes:
                    position = note.get("position")
                    if position and position.get("head_sha"):
                        commit_sha = position["head_sha"]
                        if commit_sha in commit_map:
                            if commit_sha not in commits_with_discussions:
                                commits_with_discussions[commit_sha] = {"commit": commit_map[commit_sha], "discussions": []}
                            commits_with_discussions[commit_sha]["discussions"].append(
                                {"discussion_id": discussion.get("id"), "note": note, "position": position}
                            )
                            total_discussions += 1
    
            if not commits_with_discussions:
                summary_text = (
                    f"## Commit Discussions for MR #{mr_iid}\n\n"
                    f"**Summary:**\n"
                    f"- Total commits: {len(commits_data)}\n"
                    f"- Commits with discussions: 0\n"
                    f"- Total discussions: 0\n\n"
                    f"No line-level discussions found on any commits in this "
                    f"merge request. Found {len(discussions_data)} total MR discussions."
                )
                return [TextContent(type="text", text=summary_text)]
    
            response_text = (
                f"## Commit Discussions for MR #{mr_iid}\n\n"
                f"**Summary:**\n"
                f"- Total commits: {len(commits_data)}\n"
                f"- Commits with discussions: {len(commits_with_discussions)}\n"
                f"- Total line-level discussions: {total_discussions}\n"
                f"- Total MR discussions: {len(discussions_data)}\n\n"
            )
    
            for _commit_sha, item in commits_with_discussions.items():
                commit = item["commit"]
                discussions = item["discussions"]
    
                response_text += f"### 📝 Commit: {commit['short_id']}\n"
                response_text += f"**Title:** {commit['title']}\n"
                response_text += f"**Author:** {commit['author_name']}\n"
                response_text += f"**Date:** {format_date(commit['committed_date'])}\n"
                response_text += f"**SHA:** `{commit['id']}`\n\n"
    
                for discussion_item in discussions:
                    discussion_id = discussion_item["discussion_id"]
                    note = discussion_item["note"]
                    position = discussion_item["position"]
    
                    author_name = note["author"]["name"]
                    response_text += f"**💬 Comment by {author_name}:**\n"
                    response_text += f"{note['body']}\n"
    
                    if position.get("new_path"):
                        line_info = position.get("new_line", "N/A")
                        response_text += f"*On file: {position['new_path']} " f"(line {line_info})*\n"
    
                    created_at = format_date(note["created_at"])
                    response_text += f"*Posted: {created_at}*\n"
                    response_text += f"*Discussion ID: {discussion_id}*\n\n"
    
                response_text += "---\n\n"
    
            return [TextContent(type="text", text=response_text)]
    
        except Exception as e:
            logging.error(f"Error in get_commit_discussions: {str(e)}")
            return [TextContent(type="text", text=f"Error retrieving commit discussions: {str(e)}")]
  • The tool schema definition including input schema requiring 'merge_request_iid' as input.
    Tool(
        name="get_commit_discussions",
        description=("Get discussions and comments on commits within 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,
        },
    ),
  • main.py:344-347 (registration)
    The dispatch/registration in the call_tool handler that routes calls to the get_commit_discussions function.
    elif name == "get_commit_discussions":
        return await get_commit_discussions(
            self.config["gitlab_url"], self.config["project_id"], self.config["access_token"], arguments
        )
  • main.py:41-277 (registration)
    The list_tools decorator registration where the tool is listed and described for the MCP server.
    @self.server.list_tools()
    async def list_tools() -> List[Tool]:
        logging.info("list_tools called")
        tools = [
            Tool(
                name="list_merge_requests",
                description="List merge requests for the GitLab project",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "state": {
                            "type": "string",
                            "enum": ["opened", "closed", "merged", "all"],
                            "default": "opened",
                            "description": "Filter by merge request state",
                        },
                        "target_branch": {"type": "string", "description": ("Filter by target branch (optional)")},
                        "limit": {
                            "type": "integer",
                            "default": 10,
                            "minimum": 1,
                            "maximum": 100,
                            "description": "Maximum number of results",
                        },
                    },
                    "additionalProperties": False,
                },
            ),
            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(
                name="get_merge_request_details",
                description=("Get detailed information about 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(
                name="get_merge_request_pipeline",
                description=(
                    "Get the last pipeline data for a specific merge "
                    "request, including all jobs and their statuses. "
                    "Returns job IDs that can be used with get_job_log "
                    "to fetch detailed output."
                ),
                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(
                name="get_merge_request_test_report",
                description=(
                    "Get structured test report for a merge request "
                    "with specific test failures, error messages, and "
                    "stack traces. Shows the same test data visible on "
                    "the GitLab MR page. Best for debugging test failures."
                ),
                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(
                name="get_pipeline_test_summary",
                description=(
                    "Get test summary for a merge request - a "
                    "lightweight overview showing pass/fail counts "
                    "per test suite. Faster than full test report. "
                    "Great for quick status checks."
                ),
                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(
                name="get_job_log",
                description=(
                    "Get the trace/log output for a specific pipeline "
                    "job. Perfect for debugging failed tests and "
                    "understanding CI/CD failures."
                ),
                inputSchema={
                    "type": "object",
                    "properties": {
                        "job_id": {
                            "type": "integer",
                            "minimum": 1,
                            "description": ("ID of the pipeline job (obtained from " "get_merge_request_pipeline)"),
                        }
                    },
                    "required": ["job_id"],
                    "additionalProperties": False,
                },
            ),
            Tool(
                name="get_branch_merge_requests",
                description=("Get all merge requests for a specific branch"),
                inputSchema={
                    "type": "object",
                    "properties": {"branch_name": {"type": "string", "description": "Name of the branch"}},
                    "required": ["branch_name"],
                    "additionalProperties": False,
                },
            ),
            Tool(
                name="reply_to_review_comment",
                description=("Reply to a specific discussion thread in a " "merge request review"),
                inputSchema={
                    "type": "object",
                    "properties": {
                        "merge_request_iid": {
                            "type": "integer",
                            "minimum": 1,
                            "description": ("Internal ID of the merge request"),
                        },
                        "discussion_id": {
                            "type": "string",
                            "description": ("ID of the discussion thread to reply to"),
                        },
                        "body": {"type": "string", "description": "Content of the reply comment"},
                    },
                    "required": ["merge_request_iid", "discussion_id", "body"],
                    "additionalProperties": False,
                },
            ),
            Tool(
                name="create_review_comment",
                description=("Create a new discussion thread in a " "merge request review"),
                inputSchema={
                    "type": "object",
                    "properties": {
                        "merge_request_iid": {
                            "type": "integer",
                            "minimum": 1,
                            "description": ("Internal ID of the merge request"),
                        },
                        "body": {"type": "string", "description": ("Content of the new discussion comment")},
                    },
                    "required": ["merge_request_iid", "body"],
                    "additionalProperties": False,
                },
            ),
            Tool(
                name="resolve_review_discussion",
                description=("Resolve or unresolve a discussion thread in a " "merge request review"),
                inputSchema={
                    "type": "object",
                    "properties": {
                        "merge_request_iid": {
                            "type": "integer",
                            "minimum": 1,
                            "description": ("Internal ID of the merge request"),
                        },
                        "discussion_id": {
                            "type": "string",
                            "description": ("ID of the discussion thread to " "resolve/unresolve"),
                        },
                        "resolved": {
                            "type": "boolean",
                            "default": True,
                            "description": ("Whether to resolve (true) or unresolve " "(false) the discussion"),
                        },
                    },
                    "required": ["merge_request_iid", "discussion_id"],
                    "additionalProperties": False,
                },
            ),
            Tool(
                name="get_commit_discussions",
                description=("Get discussions and comments on commits within 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_names = [t.name for t in tools]
        logging.info(f"Returning {len(tools)} tools: {tool_names}")
        return tools
  • Helper function used by the handler to fetch all commits in the merge request with pagination.
    async def get_merge_request_commits(gitlab_url, project_id, access_token, mr_iid):
        """Get all commits in a merge request (handles pagination)"""
        base_url = f"{gitlab_url}/api/v4/projects/{project_id}/" f"merge_requests/{mr_iid}/commits"
        headers = _headers(access_token)
        all_commits = []
        page = 1
        per_page = 100  # Maximum allowed per page
    
        async with aiohttp.ClientSession() as session:
            while True:
                params = {"page": page, "per_page": per_page}
                async with session.get(base_url, headers=headers, params=params) as response:
                    if response.status != 200:
                        return (response.status, await response.json(), await response.text())
    
                    page_data = await response.json()
                    if not page_data:  # No more results
                        break
    
                    all_commits.extend(page_data)
    
                    # If we got fewer results than per_page, we're done
                    if len(page_data) < per_page:
                        break
    
                    page += 1
    
            return (200, all_commits, "Success")

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