A Model Context Protocol (MCP) server that provides GitLab integration tools for Claude Code.
- List Issues: List issues for a GitLab project using project path (namespace/project-name)
- Create Issues: Create new issues with title, description, labels, and assignees
- Update Issues: Update existing issues (title, description, state, labels, assignees)
- List Labels: List project labels with optional filtering and counts
- Add Issue Notes: Add comments/notes to existing issues
- Create Merge Requests: Create new merge requests with source/target branches, title, description, assignees, reviewers, and labels
- Get Project Description: Retrieve the current description of a GitLab project
- Update Project Description: Update the description of a GitLab project
- Get Project Topics: Retrieve the current topics/tags of a GitLab project
- Update Project Topics: Update the topics/tags of a GitLab project (replaces all existing topics)
- Direct project path access - no need to resolve project IDs
- Compatible with Claude Code's MCP architecture
- Go 1.21 or later
- Task for build automation
- Claude Code CLI
- Access to GitLab repositories
# Add the tap and install
brew tap sgaunet/homebrew-tools
brew install sgaunet/tools/gitlab-mcp
-
Download the latest release:
Visit the releases page and download the appropriate binary for your platform:
- macOS:
gitlab-mcp_VERSION_darwin_amd64
(Intel) orgitlab-mcp_VERSION_darwin_arm64
(Apple Silicon) - Linux:
gitlab-mcp_VERSION_linux_amd64
(x86_64) orgitlab-mcp_VERSION_linux_arm64
(ARM64) - Windows:
gitlab-mcp_VERSION_windows_amd64.exe
- macOS:
-
Make it executable (macOS/Linux):
chmod +x gitlab-mcp_*
-
Move to a location in your PATH:
# Example for macOS/Linux sudo mv gitlab-mcp_* /usr/local/bin/gitlab-mcp
-
Clone the repository:
git clone https://github.com/sgaunet/gitlab-mcp.git cd gitlab-mcp
-
Build the project:
task build
Or manually:
go build -o gitlab-mcp
-
Install to your PATH:
sudo mv gitlab-mcp /usr/local/bin/
After installation, add the MCP server to Claude Code:
# If installed via Homebrew (Apple Silicon)
claude mcp add gitlab-mcp -s user -- /opt/homebrew/bin/gitlab-mcp
# If installed via Homebrew (Intel Mac) or manually to /usr/local/bin
claude mcp add gitlab-mcp -s user -- /usr/local/bin/gitlab-mcp
# If installed elsewhere, adjust the path accordingly
claude mcp add gitlab-mcp -s user -- /path/to/gitlab-mcp
Once installed, the MCP server provides the following tools in Claude Code:
Lists issues for a GitLab project using the project path.
Parameters:
project_path
(string, required): GitLab project path including all namespaces (e.g., 'namespace/project-name' or 'company/department/team/project'). Run 'git remote -v' to find the full path from the repository URLstate
(string, optional): Filter by issue state (opened
,closed
,all
) - defaults toopened
labels
(string, optional): Comma-separated list of labels to filter bylimit
(number, optional): Maximum number of issues to return (default: 100, max: 100)
Examples:
List all open issues for project namespace/project_name
List all issues (open and closed) for project namespace/project_name
List issues with state=all and limit=50 for project namespace/project_name
Response Format: Returns a JSON array of issue objects, each containing:
id
: Issue IDiid
: Internal issue IDtitle
: Issue titledescription
: Issue descriptionstate
: Issue state (opened
orclosed
)labels
: Array of label namesassignees
: Array of assignee objectscreated_at
: Creation timestampupdated_at
: Last update timestamp
Creates a new issue for a GitLab project.
Parameters:
project_path
(string, required): GitLab project path including all namespaces (e.g., 'namespace/project-name' or 'company/department/team/project'). Run 'git remote -v' to find the full path from the repository URLtitle
(string, required): Issue titledescription
(string, optional): Issue descriptionlabels
(array, optional): Array of labels to assign to the issueassignees
(array, optional): Array of user IDs to assign to the issue
Examples:
Create an issue with title "Bug fix needed" for project namespace/project_name
Create an issue with title "Feature request", description "Add new functionality", and labels ["enhancement", "feature"] for project namespace/project_name
Response Format: Returns a JSON object of the created issue with the same structure as list_issues.
Updates an existing issue for a GitLab project.
Parameters:
project_path
(string, required): GitLab project path including all namespaces (e.g., 'namespace/project-name' or 'company/department/team/project'). Run 'git remote -v' to find the full path from the repository URLissue_iid
(number, required): Issue internal ID (IID) to updatetitle
(string, optional): Updated issue titledescription
(string, optional): Updated issue descriptionstate
(string, optional): Issue state ('opened' or 'closed')labels
(array, optional): Array of labels to assign to the issueassignees
(array, optional): Array of user IDs to assign to the issue
Examples:
Update the title of issue #5 for project namespace/project_name
Close issue #10 and update its description for project namespace/project_name
Response Format: Returns a JSON object of the updated issue with the same structure as list_issues.
Lists labels for a GitLab project with optional filtering.
Parameters:
project_path
(string, required): GitLab project path including all namespaces (e.g., 'namespace/project-name' or 'company/department/team/project'). Run 'git remote -v' to find the full path from the repository URLwith_counts
(boolean, optional): Include issue and merge request counts (default: false)include_ancestor_groups
(boolean, optional): Include labels from ancestor groups (default: false)search
(string, optional): Filter labels by search keywordlimit
(number, optional): Maximum number of labels to return (default: 100, max: 100)
Examples:
List all labels for project namespace/project_name
List labels with counts for project namespace/project_name
Search for labels containing "bug" in project namespace/project_name
Response Format: Returns a JSON array of label objects, each containing:
id
: Label IDname
: Label namecolor
: Label color (hex code)text_color
: Text color for the labeldescription
: Label descriptionopen_issues_count
: Number of open issues (if with_counts=true)closed_issues_count
: Number of closed issues (if with_counts=true)open_merge_requests_count
: Number of open merge requests (if with_counts=true)
Adds a note/comment to an existing issue for a GitLab project.
Parameters:
project_path
(string, required): GitLab project path including all namespaces (e.g., 'namespace/project-name' or 'company/department/team/project'). Run 'git remote -v' to find the full path from the repository URLissue_iid
(number, required): Issue internal ID (IID) to add note tobody
(string, required): Note/comment body text
Examples:
Add a comment "This looks good to me!" to issue #5 for project namespace/project_name
Add a note "Fixed in latest commit" to issue #12 for project namespace/project_name
Response Format: Returns a JSON object of the created note containing:
id
: Note IDbody
: Note body textauthor
: Author object with id, username, and namecreated_at
: Creation timestampupdated_at
: Last update timestampsystem
: Boolean indicating if this is a system-generated notenoteable
: Object containing information about the issue this note belongs to
Creates a new merge request for a GitLab project.
Parameters:
project_path
(string, required): GitLab project path including all namespaces (e.g., 'namespace/project-name' or 'company/department/team/project'). Run 'git remote -v' to find the full path from the repository URLsource_branch
(string, required): Source branch nametarget_branch
(string, required): Target branch nametitle
(string, required): MR titledescription
(string, optional): MR descriptionassignee_ids
(array, optional): Array of assignee user IDsreviewer_ids
(array, optional): Array of reviewer user IDslabels
(array, optional): Array of labelsmilestone_id
(number, optional): Milestone IDremove_source_branch
(boolean, optional): Auto-remove source branch after merge (default: true)draft
(boolean, optional): Create as draft MR (default: false)
Examples:
Create a merge request from feature-branch to main for project namespace/project_name
Create a merge request with assignees and labels from feature-branch to main for project namespace/project_name
Create a draft merge request with description "New feature implementation" from feature-branch to develop for project namespace/project_name
Response Format: Returns a JSON object of the created merge request containing:
id
: Merge request IDiid
: Internal merge request IDtitle
: MR titledescription
: MR descriptionstate
: MR state (opened, closed, merged)source_branch
: Source branch nametarget_branch
: Target branch nameauthor
: Author object with id, username, and nameassignees
: Array of assignee objectsreviewers
: Array of reviewer objectslabels
: Array of label namesmilestone
: Milestone object (if assigned)web_url
: Web URL to the merge requestdraft
: Boolean indicating if this is a draft MRcreated_at
: Creation timestampupdated_at
: Last update timestamp
Retrieves the description of a GitLab project.
Parameters:
project_path
(string, required): GitLab project path including all namespaces (e.g., 'namespace/project-name' or 'company/department/team/project'). Run 'git remote -v' to find the full path from the repository URL
Examples:
Get the project description for namespace/project_name
Response Format: Returns a JSON object containing:
id
: Project IDname
: Project namepath
: Project pathdescription
: Project description
Updates the description of a GitLab project.
Parameters:
project_path
(string, required): GitLab project path including all namespaces (e.g., 'namespace/project-name' or 'company/department/team/project'). Run 'git remote -v' to find the full path from the repository URLdescription
(string, required): The new description for the project
Examples:
Update the description of namespace/project_name to "A new and improved project description"
Response Format: Returns a JSON object containing:
id
: Project IDname
: Project namepath
: Project pathdescription
: Updated project descriptiontopics
: Array of project topics
Retrieves the topics/tags of a GitLab project.
Parameters:
project_path
(string, required): GitLab project path including all namespaces (e.g., 'namespace/project-name' or 'company/department/team/project'). Run 'git remote -v' to find the full path from the repository URL
Examples:
Get the topics for namespace/project_name
Response Format: Returns a JSON object containing:
id
: Project IDname
: Project namepath
: Project pathtopics
: Array of topic strings
Updates the topics/tags of a GitLab project (replaces all existing topics).
Parameters:
project_path
(string, required): GitLab project path including all namespaces (e.g., 'namespace/project-name' or 'company/department/team/project'). Run 'git remote -v' to find the full path from the repository URLtopics
(array, required): Array of topic strings to set for the project (replaces all existing topics)
Examples:
Update the topics of namespace/project_name to ["golang", "mcp", "gitlab", "api"]
Remove all topics from namespace/project_name by setting an empty array []
Response Format: Returns a JSON object containing:
id
: Project IDname
: Project namepath
: Project pathdescription
: Project descriptiontopics
: Updated array of topic strings
This project uses Task for build automation. Available tasks:
# List all available tasks
task --list
# Build the binary
task build
# Build with coverage support
task build:coverage
# Run linter
task linter
# Run unit tests
task test
# Show test coverage percentage
task coverage
Unit Tests:
task test
Coverage Testing:
# Show coverage percentage
task coverage
The unit tests use interface abstractions and mocking to provide fast, reliable testing without external dependencies. Current test coverage is 78.8%.
See MANUAL_TEST.md for step-by-step manual testing instructions.
Run the test script:
./test_working.sh
The MCP server runs as a subprocess and communicates via JSON-RPC over stdin/stdout. No additional configuration is required.
This server uses stdio (stdin/stdout) for communication, which is the standard and recommended approach for MCP servers:
โ Why stdio is optimal:
- Standard MCP pattern - Most MCP servers use stdio communication
- Simple process model - Started by Claude Code as a subprocess
- No port conflicts - No network port management needed
- Security - Process isolation, no network exposure
- Resource efficiency - Direct pipe communication with minimal overhead
- Cross-platform compatibility - Works everywhere Go works
- Easy configuration - Just specify the executable path in Claude Code
๐ Alternative transports (HTTP/SSE): While MCP supports HTTP and Server-Sent Events, these are better suited for:
- Multi-client scenarios (serving multiple agents simultaneously)
- Containerized environments where process spawning is restricted
- Remote access across network boundaries
- Web-based MCP clients
For GitLab integration with Claude Code, stdio provides the best user experience with simple configuration and reliable performance.
- Parse Error (-32700): Ensure you're using the server through Claude Code's MCP interface, not directly inputting raw URLs
- Invalid URL: Verify the GitLab URL format is correct (SSH or HTTPS)
- Connection Issues: Check network connectivity to GitLab
The server outputs debug information to stderr, which can be helpful for troubleshooting:
go run . < input.txt 2> debug.log
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
MIT License. See LICENSE for details.
For issues and questions, please create an issue in the repository.