Claude Marketplaces
SkillsMCP serversMarketplacesDigestTools
Submit

This week in Claude

Every Monday: Claude Code, Agent SDK, MCP, and the Anthropic platform moves worth your time.

Skills by category
Frontend DevelopmentBackend & APIsTesting & QASecurityDevOps & CI/CDGit & Pull RequestsDocumentationCode Review & QualityAI & Agent BuildingSkill Development
MCP servers by category
Sales & MarketingWeb & Browser AutomationDatabasesAI & LLM ToolsCloud & InfrastructureCommunication & MessagingDeveloper ToolsDesign & CreativeDocuments & KnowledgeSearch & Web Crawling
Marketplaces by category
AI Agents & OrchestrationLLM IntegrationDevelopment ToolsFrontend & UIBackend & APIsDatabasesTesting & Code QualityDevOps & CloudSecurity & ComplianceGit & Version Control
Claude Marketplaces

An independent directory of skills, plugins and MCP servers for Claude Code. Not affiliated with Anthropic.

Browse

  • Skills
  • MCP servers
  • Marketplaces
  • Weekly digest
  • Skill index
  • MCP index
  • Marketplace index

Site

  • About
  • Tools
  • Submit
  • Feedback
  • Privacy
  • llms.txt
  • Plugins reference

Maker

  • Snug
  • Agent Caffeine
  • knobs
  • Wax
  • Vectoys
  • mertduzgun.com
Crafted at
MCP servers/Developer Tools
zereight avatar

Gitlab Mcp

zereight/gitlab-mcp

The GitLab MCP Server provides comprehensive GitLab project management capabilities to AI clients through a Model Context Protocol interface, enabling operations on projects, merge requests, issues, pipelines, wiki, and releases. It offers multiple authentication methods including Personal Access Tokens, OAuth2 with browser-based flows, and remote authorization support, with compatibility across stdio, SSE, and HTTP transports for clients like Claude, VS Code, Cursor, and Copilot. The server solves the problem of giving AI assistants secure, authenticated access to GitLab resources while supporting various deployment scenarios from local desktop use to remote multi-user server deployments.

GitHub stars
1.6K
tools
80
last updated
May 30, 2026
View on GitHubSave

Install

Verified command
$ claude mcp add gitlab-mcp --env GITLAB_PERSONAL_ACCESS_TOKEN=YOUR_GITLAB_PERSONAL_ACCESS_TOKEN --env GITLAB_JOB_TOKEN=YOUR_GITLAB_JOB_TOKEN --env GITLAB_AUTH_COOKIE_PATH=YOUR_GITLAB_AUTH_COOKIE_PATH --env GITLAB_API_URL=https://gitlab.com/api/v4 --env GITLAB_ALLOWED_PROJECT_IDS=YOUR_GITLAB_ALLOWED_PROJECT_IDS --env GITLAB_READ_ONLY_MODE=false --env USE_GITLAB_WIKI=false --env GITLAB_TOOLSETS=YOUR_GITLAB_TOOLSETS --env GITLAB_TOOLS=YOUR_GITLAB_TOOLS --env GITLAB_DENIED_TOOLS_REGEX=YOUR_GITLAB_DENIED_TOOLS_REGEX --env GITLAB_TOOL_POLICY_APPROVE=YOUR_GITLAB_TOOL_POLICY_APPROVE --env GITLAB_TOOL_POLICY_HIDDEN=YOUR_GITLAB_TOOL_POLICY_HIDDEN --env NODE_TLS_REJECT_UNAUTHORIZED=YOUR_NODE_TLS_REJECT_UNAUTHORIZED --env GITLAB_CA_CERT_PATH=YOUR_GITLAB_CA_CERT_PATH -- npx -y @zereight/mcp-gitlab

Run in your terminal. Replace YOUR_* placeholders with real values; add --scope user to install for every project.

Review the command, arguments and environment values before installing. MCP servers run with your local permissions.

Tools

Verified live · 80 tools

Verified live against the running server on Jun 10, 2026.

merge_merge_requestMerge a merge request8 params

Merge a merge request

Parameters* required
auto_mergeboolean
If true, the merge request merges when the pipeline succeeds.default: false
merge_commit_messagestring
Custom merge commit message
merge_request_iidstring
The IID of a merge request
merge_when_pipeline_succeedsboolean
If true, the merge request merges when the pipeline succeeds.in GitLab 17.11. Usedefault: false
project_id*string
Project ID or complete URL-encoded path to project
should_remove_source_branchboolean
Remove source branch after mergedefault: false
squashboolean
Squash commits into a single commit when mergingdefault: false
squash_commit_messagestring
Custom squash commit message
approve_merge_requestApprove a merge request4 params

Approve a merge request

Parameters* required
approval_passwordstring
Current user's password. Required if 'Require user re-authentication to approve' is enabled in the project settings
merge_request_iid*string
The IID of the merge request to approve
project_id*string
Project ID or complete URL-encoded path to project
shastring
The HEAD of the merge request. Optional, but used to ensure the merge request hasn't changed since you last reviewed it
unapprove_merge_requestUnapprove a merge request2 params

Unapprove a merge request

Parameters* required
merge_request_iid*string
The IID of the merge request to unapprove
project_id*string
Project ID or complete URL-encoded path to project
get_merge_request_approval_stateGet merge request approval details including approvers2 params

Get merge request approval details including approvers

Parameters* required
merge_request_iid*string
The IID of the merge request
project_id*string
Project ID or complete URL-encoded path to project
get_merge_request_conflictsGet the conflicts of a merge request2 params

Get the conflicts of a merge request

Parameters* required
merge_request_iid*string
The IID of the merge request
project_id*string
Project ID or complete URL-encoded path to project
list_merge_request_pipelinesList pipelines for a merge request with pagination4 params

List pipelines for a merge request with pagination

Parameters* required
merge_request_iid*string
The internal ID of the merge request
pagenumber
Page number for pagination (default: 1)
per_pagenumber
Number of items per page (max: 100, default: 20)
project_id*string
Project ID or complete URL-encoded path to project
create_or_update_fileCreate or update a file in a GitLab project8 params

Create or update a file in a GitLab project

Parameters* required
branch*string
Branch to create/update the file in
commit_idstring
Current file commit ID (for update operations)
commit_message*string
Commit message
content*string
Content of the file
file_path*string
Path where to create/update the file
last_commit_idstring
Last known file commit ID
previous_pathstring
Path of the file to move/rename
project_id*string
Project ID or complete URL-encoded path to project
search_repositoriesSearch for GitLab projects4 params

Search for GitLab projects

Parameters* required
pagenumber
Page number for pagination (default: 1)
per_pagenumber
Number of items per page (max: 100, default: 20)
querystring
Search query (alias for 'search')
searchstring
Search query
create_repositoryCreate a new GitLab project4 params

Create a new GitLab project

Parameters* required
descriptionstring
Repository description
initialize_with_readmeboolean
Initialize with README.md
name*string
Repository name
visibilitystring
Repository visibility levelone of private · internal · public
create_groupCreate new group or subgroup5 params

Create new group or subgroup

Parameters* required
descriptionstring
The group's description
name*string
The name of the group
parent_idnumber
The parent group ID for creating a subgroup
path*string
The path of the group
visibilitystring
The group's visibility levelone of private · internal · public
get_file_contentsGet contents of a file or directory from a GitLab project4 params

Get contents of a file or directory from a GitLab project

Parameters* required
file_pathstring
Path to the file or directory. Takes precedence over 'path' when both are provided
pathstring
Alias of file_path
project_idstring
Project ID or URL-encoded path (optional; falls back to env)
refstring
Branch/tag/commit to get contents from
push_filesPush multiple files in a single commit4 params

Push multiple files in a single commit

Parameters* required
branch*string
Branch to push to
commit_message*string
Commit message
files*array
Array of files to push
project_id*string
Project ID or complete URL-encoded path to project
create_issueCreate a new issue8 params

Create a new issue

Parameters* required
assignee_idsarray
Array of user IDs to assign
descriptionstring
Issue description
issue_typestring
The type of issue. One of issue, incident, test_case or task.one of issue · incident · test_case · taskdefault: issue
labelsarray
Array of label names
milestone_idstring
Milestone ID to assign
project_id*string
Project ID or complete URL-encoded path to project
title*string
Issue title
weightnumber
Weight of the issue (numeric, typically hours of work)
create_merge_requestCreate a new merge request13 params

Create a new merge request

Parameters* required
allow_collaborationboolean
Allow commits from upstream members
assignee_idsarray
The ID of the users to assign the MR to
descriptionstring
Merge request description
draftboolean
Create as draft merge request
labelsarray
Labels for the MR
project_id*string
Project ID or complete URL-encoded path to project
remove_source_branchboolean
Flag indicating if a merge request should remove the source branch when merging.
reviewer_idsarray
The ID of the users to assign as reviewers of the MR
source_branch*string
Branch containing changes
squashboolean
If true, squash all commits into a single commit on merge.
target_branch*string
Branch to merge into
target_project_idstring
Numeric ID of the target project.
title*string
Merge request title
fork_repositoryFork a project to your account or specified namespace2 params

Fork a project to your account or specified namespace

Parameters* required
namespacestring
Namespace to fork to (full path)
project_id*string
Project ID or complete URL-encoded path to project
create_branchCreate a new branch3 params

Create a new branch

Parameters* required
branch*string
Name for the new branch
project_id*string
Project ID or complete URL-encoded path to project
refstring
Source branch/commit for new branch
get_branchGet branch details (commit, protection status)2 params

Get branch details (commit, protection status)

Parameters* required
branch_name*string
Name of the branch
project_id*string
Project ID or complete URL-encoded path to project
list_branchesList branches in project with search filter4 params

List branches in project with search filter

Parameters* required
pagenumber
Page number for pagination (default: 1)
per_pagenumber
Number of items per page (max: 100, default: 20)
project_id*string
Project ID or complete URL-encoded path to project
searchstring
Search term to filter branches by name
delete_branchDelete branch from project2 params

Delete branch from project

Parameters* required
branch_name*string
Name of the branch to delete
project_id*string
Project ID or complete URL-encoded path to project
get_merge_requestGet details of a merge request (mergeRequestIid or branchName required)3 params

Get details of a merge request (mergeRequestIid or branchName required)

Parameters* required
merge_request_iidstring
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
source_branchstring
Source branch name
get_merge_request_diffsGet the changes/diffs of a merge request (mergeRequestIid or branchName required)5 params

Get the changes/diffs of a merge request (mergeRequestIid or branchName required)

Parameters* required
excluded_file_patternsarray
Array of regex patterns to exclude files from the diff results. Each pattern is a JavaScript-compatible regular expression that matches file paths to ignore. Examples: ["^vendor/", "^test/mocks/",...
merge_request_iidstring
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
source_branchstring
Source branch name
viewstring
Diff view typeone of inline · parallel
list_merge_request_changed_filesList changed file paths in a merge request without diff content (mergeRequestIid or branchName required)4 params

List changed file paths in a merge request without diff content (mergeRequestIid or branchName required)

Parameters* required
excluded_file_patternsarray
Array of regex patterns to exclude files. Examples: ["^vendor/", "\.pb\.go$"]
merge_request_iidstring
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
source_branchstring
Source branch name
list_merge_request_diffsList merge request diffs with pagination (mergeRequestIid or branchName required)6 params

List merge request diffs with pagination (mergeRequestIid or branchName required)

Parameters* required
merge_request_iidstring
The IID of a merge request
pagenumber
Page number for pagination (default: 1)
per_pagenumber
Number of items per page (max: 100, default: 20)
project_id*string
Project ID or complete URL-encoded path to project
source_branchstring
Source branch name
unidiffboolean
Present diffs in the unified diff format. Default is false. Introduced in GitLab 16.5.
get_merge_request_file_diffGet diffs for specific files from a merge request (mergeRequestIid or branchName required)5 params

Get diffs for specific files from a merge request (mergeRequestIid or branchName required)

Parameters* required
file_paths*array
List of file paths to retrieve diffs for (e.g. ['src/api/users.ts', 'src/repo/user.go']). Call list_merge_request_changed_files first to get the full list of changed paths.
merge_request_iidstring
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
source_branchstring
Source branch name
unidiffboolean
Present diff in the unified diff format. Default is false.
list_merge_request_versionsList all versions of a merge request2 params

List all versions of a merge request

Parameters* required
merge_request_iid*string
The internal ID of the merge request
project_id*string
Project ID or complete URL-encoded path to project
get_merge_request_versionGet a specific version of a merge request4 params

Get a specific version of a merge request

Parameters* required
merge_request_iid*string
The internal ID of the merge request
project_id*string
Project ID or complete URL-encoded path to project
unidiffboolean
Present diffs in the unified diff format. Default is false. Introduced in GitLab 16.5.
version_id*string
The ID of the merge request diff version
get_branch_diffsGet diffs between two branches or commits5 params

Get diffs between two branches or commits

Parameters* required
excluded_file_patternsarray
Array of regex patterns to exclude files from the diff results. Each pattern is a JavaScript-compatible regular expression that matches file paths to ignore. Examples: ["^vendor/", "^test/mocks/",...
from*string
The base branch or commit SHA to compare from
project_id*string
Project ID or complete URL-encoded path to project
straightboolean
Comparison method: false for '...' (default), true for '--'
to*string
The target branch or commit SHA to compare to
update_merge_requestUpdate a merge request (mergeRequestIid or branchName required)13 params

Update a merge request (mergeRequestIid or branchName required)

Parameters* required
assignee_idsarray
The ID of the users to assign the MR to
descriptionstring
The description of the merge request
draftboolean
Work in progress merge request
labelsarray
Labels for the MR
merge_request_iidstring
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
remove_source_branchboolean
Flag indicating if the source branch should be removed
reviewer_idsarray
The ID of the users to assign as reviewers of the MR
source_branchstring
Source branch name
squashboolean
Squash commits into a single commit when merging
state_eventstring
New state (close/reopen) for the MRone of close · reopen
target_branchstring
The target branch
titlestring
The title of the merge request
create_noteCreate a new note (comment) to an issue or merge request4 params

Create a new note (comment) to an issue or merge request

Parameters* required
body*string
Note content
noteable_iid*string
IID of the issue or merge request
noteable_type*string
Type of noteable (issue or merge_request)one of issue · merge_request
project_id*string
Project ID or namespace/project_path
create_merge_request_threadCreate a new thread on a merge request5 params

Create a new thread on a merge request

Parameters* required
body*string
The content of the thread
created_atstring
Date the thread was created at (ISO 8601 format)
merge_request_iid*string
The IID of a merge request
positionobject
Position when creating a diff note
project_id*string
Project ID or complete URL-encoded path to project
resolve_merge_request_threadResolve a thread on a merge request4 params

Resolve a thread on a merge request

Parameters* required
discussion_id*string
The ID of a thread
merge_request_iid*string
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
resolved*boolean
Whether to resolve the thread
mr_discussionsList discussion items for a merge request4 params

List discussion items for a merge request

Parameters* required
merge_request_iid*string
The IID of a merge request
pagenumber
Page number for pagination (default: 1)
per_pagenumber
Number of items per page (max: 100, default: 20)
project_id*string
Project ID or complete URL-encoded path to project
delete_merge_request_discussion_noteDelete a discussion note on a merge request4 params

Delete a discussion note on a merge request

Parameters* required
discussion_id*string
The ID of a thread
merge_request_iid*string
The IID of a merge request
note_id*string
The ID of a thread note
project_id*string
Project ID or complete URL-encoded path to project
update_merge_request_discussion_noteUpdate a discussion note on a merge request6 params

Update a discussion note on a merge request

Parameters* required
bodystring
The content of the note or reply
discussion_idstring
The ID of a thread
merge_request_iidstring
The IID of a merge request
note_idstring
The ID of a thread note
project_idstring
Project ID or complete URL-encoded path to project
resolvedboolean
Resolve or unresolve the note
create_merge_request_discussion_noteAdd a new discussion note to an existing merge request thread5 params

Add a new discussion note to an existing merge request thread

Parameters* required
body*string
The content of the note or reply
created_atstring
Date the note was created at (ISO 8601 format)
discussion_id*string
The ID of a thread
merge_request_iid*string
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
create_merge_request_noteAdd a new note to a merge request3 params

Add a new note to a merge request

Parameters* required
body*string
The content of the note or reply
merge_request_iid*string
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
delete_merge_request_noteDelete an existing merge request note3 params

Delete an existing merge request note

Parameters* required
merge_request_iid*string
The IID of a merge request
note_id*string
The ID of a thread note
project_id*string
Project ID or complete URL-encoded path to project
get_merge_request_noteGet a specific note for a merge request3 params

Get a specific note for a merge request

Parameters* required
merge_request_iid*string
The IID of a merge request
note_id*string
The ID of a thread note
project_id*string
Project ID or complete URL-encoded path to project
get_merge_request_notesList notes for a merge request6 params

List notes for a merge request

Parameters* required
merge_request_iid*string
The IID of a merge request
order_bystring
The field to sort the notes byone of created_at · updated_at
pagenumber
Page number for pagination
per_pagenumber
Number of items per page
project_id*string
Project ID or complete URL-encoded path to project
sortstring
The sort order of the notesone of asc · desc
update_merge_request_noteModify an existing merge request note4 params

Modify an existing merge request note

Parameters* required
body*string
The content of the note or reply
merge_request_iid*string
The IID of a merge request
note_id*string
The ID of a thread note
project_id*string
Project ID or complete URL-encoded path to project
get_draft_noteGet a single draft note from a merge request3 params

Get a single draft note from a merge request

Parameters* required
draft_note_id*string
The ID of the draft note
merge_request_iid*string
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
list_draft_notesList draft notes for a merge request2 params

List draft notes for a merge request

Parameters* required
merge_request_iid*string
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
create_draft_noteCreate a draft note for a merge request6 params

Create a draft note for a merge request

Parameters* required
body*string
The content of the draft note
in_reply_to_discussion_idstring
The ID of a discussion the draft note replies to
merge_request_iid*string
The IID of a merge request
positionobject
Position when creating a diff note
project_id*string
Project ID or complete URL-encoded path to project
resolve_discussionboolean
Whether to resolve the discussion when publishing
update_draft_noteUpdate an existing draft note6 params

Update an existing draft note

Parameters* required
bodystring
The content of the draft note
draft_note_id*string
The ID of the draft note
merge_request_iid*string
The IID of a merge request
positionobject
Position when creating a diff note
project_id*string
Project ID or complete URL-encoded path to project
resolve_discussionboolean
Whether to resolve the discussion when publishing
delete_draft_noteDelete a draft note3 params

Delete a draft note

Parameters* required
draft_note_id*string
The ID of the draft note
merge_request_iid*string
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
publish_draft_notePublish a single draft note3 params

Publish a single draft note

Parameters* required
draft_note_id*string
The ID of the draft note
merge_request_iid*string
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
bulk_publish_draft_notesPublish all draft notes for a merge request2 params

Publish all draft notes for a merge request

Parameters* required
merge_request_iid*string
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
list_merge_request_emoji_reactionsList all emoji reactions on a merge request2 params

List all emoji reactions on a merge request

Parameters* required
merge_request_iid*string
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
list_merge_request_note_emoji_reactionsList all emoji reactions on a merge request note. Pass discussion_id for discussion thread replies.4 params

List all emoji reactions on a merge request note. Pass discussion_id for discussion thread replies.

Parameters* required
discussion_idstring
The ID of a discussion thread. Required for notes that are discussion replies; omit for top-level notes.
merge_request_iid*string
The IID of a merge request
note_id*string
The ID of a note (comment or thread reply)
project_id*string
Project ID or complete URL-encoded path to project
create_merge_request_emoji_reactionAdd an emoji reaction to a merge request (e.g. thumbsup, rocket, eyes)3 params

Add an emoji reaction to a merge request (e.g. thumbsup, rocket, eyes)

Parameters* required
merge_request_iid*string
The IID of a merge request
name*string
Name of the emoji without colons (e.g. 'thumbsup', 'rocket', 'eyes')
project_id*string
Project ID or complete URL-encoded path to project
delete_merge_request_emoji_reactionRemove an emoji reaction from a merge request3 params

Remove an emoji reaction from a merge request

Parameters* required
award_id*string
The ID of the emoji reaction to delete
merge_request_iid*string
The IID of a merge request
project_id*string
Project ID or complete URL-encoded path to project
create_merge_request_note_emoji_reactionAdd an emoji reaction to a merge request note. Pass discussion_id for discussion thread replies.5 params

Add an emoji reaction to a merge request note. Pass discussion_id for discussion thread replies.

Parameters* required
discussion_idstring
The ID of a discussion thread. Required for notes that are discussion replies; omit for top-level notes.
merge_request_iid*string
The IID of a merge request
name*string
Name of the emoji without colons (e.g. 'thumbsup', 'rocket', 'eyes')
note_id*string
The ID of a note (comment or thread reply)
project_id*string
Project ID or complete URL-encoded path to project
delete_merge_request_note_emoji_reactionRemove an emoji reaction from a merge request note. Pass discussion_id for discussion thread replies.5 params

Remove an emoji reaction from a merge request note. Pass discussion_id for discussion thread replies.

Parameters* required
award_id*string
The ID of the emoji reaction to delete
discussion_idstring
The ID of a discussion thread. Required for notes that are discussion replies; omit for top-level notes.
merge_request_iid*string
The IID of a merge request
note_id*string
The ID of a note (comment or thread reply)
project_id*string
Project ID or complete URL-encoded path to project
update_issue_noteModify an existing issue thread note6 params

Modify an existing issue thread note

Parameters* required
bodystring
The content of the note or reply
discussion_idstring
The ID of a thread
issue_iidstring
The IID of an issue
note_idstring
The ID of a thread note
project_idstring
Project ID or complete URL-encoded path to project
resolvedboolean
Resolve or unresolve the note
create_issue_noteAdd a note to an issue, optionally replying to a discussion thread5 params

Add a note to an issue, optionally replying to a discussion thread

Parameters* required
body*string
The content of the note or reply
created_atstring
Date the note was created at (ISO 8601 format)
discussion_idstring
The ID of a thread. If provided, replies to that thread; otherwise creates a top-level note
issue_iid*string
The IID of an issue
project_id*string
Project ID or complete URL-encoded path to project
list_issue_emoji_reactionsList all emoji reactions on an issue2 params

List all emoji reactions on an issue

Parameters* required
issue_iid*string
The IID of an issue
project_id*string
Project ID or complete URL-encoded path to project
list_issue_note_emoji_reactionsList all emoji reactions on an issue note. Pass discussion_id for discussion thread replies.4 params

List all emoji reactions on an issue note. Pass discussion_id for discussion thread replies.

Parameters* required
discussion_idstring
The ID of a discussion thread. Required for notes that are discussion replies; omit for top-level notes.
issue_iid*string
The IID of an issue
note_id*string
The ID of a note (comment or thread reply)
project_id*string
Project ID or complete URL-encoded path to project
create_issue_emoji_reactionAdd an emoji reaction to an issue (e.g. thumbsup, rocket, eyes)3 params

Add an emoji reaction to an issue (e.g. thumbsup, rocket, eyes)

Parameters* required
issue_iid*string
The IID of an issue
name*string
Name of the emoji without colons (e.g. 'thumbsup', 'rocket', 'eyes')
project_id*string
Project ID or complete URL-encoded path to project
delete_issue_emoji_reactionRemove an emoji reaction from an issue3 params

Remove an emoji reaction from an issue

Parameters* required
award_id*string
The ID of the emoji reaction to delete
issue_iid*string
The IID of an issue
project_id*string
Project ID or complete URL-encoded path to project
create_issue_note_emoji_reactionAdd an emoji reaction to an issue note. Pass discussion_id for discussion thread replies.5 params

Add an emoji reaction to an issue note. Pass discussion_id for discussion thread replies.

Parameters* required
discussion_idstring
The ID of a discussion thread. Required for notes that are discussion replies; omit for top-level notes.
issue_iid*string
The IID of an issue
name*string
Name of the emoji without colons (e.g. 'thumbsup', 'rocket', 'eyes')
note_id*string
The ID of a note (comment or thread reply)
project_id*string
Project ID or complete URL-encoded path to project
delete_issue_note_emoji_reactionRemove an emoji reaction from an issue note. Pass discussion_id for discussion thread replies.5 params

Remove an emoji reaction from an issue note. Pass discussion_id for discussion thread replies.

Parameters* required
award_id*string
The ID of the emoji reaction to delete
discussion_idstring
The ID of a discussion thread. Required for notes that are discussion replies; omit for top-level notes.
issue_iid*string
The IID of an issue
note_id*string
The ID of a note (comment or thread reply)
project_id*string
Project ID or complete URL-encoded path to project
list_issuesList issues (default: created by current user; use scope='all' for all)21 params

List issues (default: created by current user; use scope='all' for all)

Parameters* required
assignee_idstring
Return issues assigned to the given user ID. user id or none or any
assignee_usernamearray
Return issues assigned to the given username
author_idstring
Return issues created by the given user ID
author_usernamestring
Return issues created by the given username
confidentialboolean
Filter confidential or public issues
created_afterstring
Return issues created after the given time
created_beforestring
Return issues created before the given time
due_datestring
Return issues that have the due date
issue_typestring
Filter to a given type of issue. One of issue, incident, test_case or taskone of issue · incident · test_case · task
iteration_idstring
Return issues assigned to the given iteration ID. None returns issues that do not belong to an iteration. Any returns issues that belong to an iteration.
labelsarray
Array of label names
milestonestring
Milestone title
pagenumber
Page number for pagination (default: 1)
per_pagenumber
Number of items per page (max: 100, default: 20)
project_idstring
Project ID or URL-encoded path (optional - if not provided, lists issues across all accessible projects)
scopestring
Return issues from a specific scopeone of created_by_me · assigned_to_me · all
searchstring
Search for specific terms
statestring
Return issues with a specific stateone of opened · closed · all
updated_afterstring
Return issues updated after the given time
updated_beforestring
Return issues updated before the given time

+1 more parameters. See the server's own documentation for the full schema.

my_issuesList issues assigned to the authenticated user11 params

List issues assigned to the authenticated user

Parameters* required
created_afterstring
Return issues created after the given time (ISO 8601)
created_beforestring
Return issues created before the given time (ISO 8601)
labelsarray
Array of label names to filter by
milestonestring
Milestone title to filter by
pagenumber
Page number for pagination (default: 1)
per_pagenumber
Number of items per page (default: 20, max: 100)
project_idstring
Project ID or URL-encoded path (optional when GITLAB_PROJECT_ID is set)
searchstring
Search for specific terms in title and description
statestring
Return issues with a specific state (default: opened)one of opened · closed · all
updated_afterstring
Return issues updated after the given time (ISO 8601)
updated_beforestring
Return issues updated before the given time (ISO 8601)
get_issueGet details of a specific issue2 params

Get details of a specific issue

Parameters* required
issue_iid*string
The internal ID of the project issue
project_id*string
Project ID or URL-encoded path
update_issueUpdate an issue13 params

Update an issue

Parameters* required
assignee_idsarray
Array of user IDs to assign issue to
confidentialboolean
Set the issue to be confidential
descriptionstring
The description of the issue
discussion_lockedboolean
Flag to lock discussions
due_datestring
Date the issue is due (YYYY-MM-DD)
issue_iid*string
The internal ID of the project issue
issue_typestring
The type of issue. One of issue, incident, test_case or task.one of issue · incident · test_case · task
labelsarray
Array of label names
milestone_idstring
Milestone ID to assign
project_id*string
Project ID or URL-encoded path
state_eventstring
Update issue state (close/reopen)one of close · reopen
titlestring
The title of the issue
weightnumber
Weight of the issue (numeric, typically hours of work)
update_issue_description_patchApply a patch (search/replace or unified diff) to an issue description. Reduces token usage by allowing small changes without sending the full description. Supports dry_run to preview changes and create_note to summarize updates.7 params

Apply a patch (search/replace or unified diff) to an issue description. Reduces token usage by allowing small changes without sending the full description. Supports dry_run to preview changes and create_note to summarize updates.

Parameters* required
allow_multipleboolean
For search_replace: allow multiple matches to all be replaced (default: false — fail on duplicate)
create_noteboolean
If true, add a note summarizing the change after update
dry_runboolean
If true, preview changes without updating the issue
issue_iid*string
The internal ID of the project issue
patch*string
The patch content to apply to the issue description
patch_type*string
Type of patch format to applyone of search_replace · unified_diff
project_id*string
Project ID or URL-encoded path
delete_issueDelete an issue2 params

Delete an issue

Parameters* required
issue_iid*string
The internal ID of the project issue
project_id*string
Project ID or URL-encoded path
list_todosList GitLab to-do items for the current user8 params

List GitLab to-do items for the current user

Parameters* required
actionstring
Filter by to-do actionone of assigned · mentioned · build_failed · marked · approval_required · unmergeable
author_idnumber
Filter by author ID
group_idnumber
Filter by group ID
pagenumber
Page number for pagination (default: 1)
per_pagenumber
Number of items per page (max: 100, default: 20)
project_idnumber
Filter by project ID
statestring
Filter by to-do stateone of pending · done
typestring
Filter by to-do target typeone of Issue · MergeRequest · Commit · Epic · DesignManagement::Design · AlertManagement::Alert
mark_todo_doneMark a GitLab to-do item as done1 params

Mark a GitLab to-do item as done

Parameters* required
id*number
The ID of the to-do item
mark_all_todos_doneMark all pending GitLab to-do items as done for the current user

Mark all pending GitLab to-do items as done for the current user

No parameters. Call it with no arguments.

list_issue_linksList all issue links for a specific issue2 params

List all issue links for a specific issue

Parameters* required
issue_iid*string
The internal ID of a project's issue
project_id*string
Project ID or URL-encoded path
list_issue_discussionsList discussions for an issue4 params

List discussions for an issue

Parameters* required
issue_iid*string
The internal ID of the project issue
pagenumber
Page number for pagination (default: 1)
per_pagenumber
Number of items per page (max: 100, default: 20)
project_id*string
Project ID or URL-encoded path
get_issue_linkGet a specific issue link3 params

Get a specific issue link

Parameters* required
issue_iid*string
The internal ID of a project's issue
issue_link_id*string
ID of an issue relationship
project_id*string
Project ID or URL-encoded path
create_issue_linkCreate an issue link between two issues5 params

Create an issue link between two issues

Parameters* required
issue_iid*string
The internal ID of a project's issue
link_typestring
The type of the relation, defaults to relates_toone of relates_to · blocks · is_blocked_by
project_id*string
Project ID or URL-encoded path
target_issue_iid*string
The internal ID of a target project's issue
target_project_id*string
The ID or URL-encoded path of a target project
delete_issue_linkDelete an issue link3 params

Delete an issue link

Parameters* required
issue_iid*string
The internal ID of a project's issue
issue_link_id*string
The ID of an issue relationship
project_id*string
Project ID or URL-encoded path
list_namespacesList all namespaces (users and groups) available to the current user. Filter by kind='group' for groups only.4 params

List all namespaces (users and groups) available to the current user. Filter by kind='group' for groups only.

Parameters* required
ownedboolean
Filter for namespaces owned by current user
pagenumber
Page number for pagination (default: 1)
per_pagenumber
Number of items per page (max: 100, default: 20)
searchstring
Search term for namespaces
get_namespaceGet details of a namespace (user or group) by ID or path. Groups are namespaces with kind='group'.1 params

Get details of a namespace (user or group) by ID or path. Groups are namespaces with kind='group'.

Parameters* required
namespace_id*string
Namespace ID or full path
verify_namespaceVerify if a namespace path exists1 params

Verify if a namespace path exists

Parameters* required
path*string
Namespace path to verify
get_projectGet details of a specific project1 params

Get details of a specific project

Parameters* required
project_id*string
Project ID or URL-encoded path
list_projectsList projects accessible by the current user15 params

List projects accessible by the current user

Parameters* required
archivedboolean
Filter for archived projects
membershipboolean
Filter for projects where current user is a member
min_access_levelnumber
Filter by minimum access level
order_bystring
Return projects ordered by fieldone of id · name · path · created_at · updated_at · last_activity_at
ownedboolean
Filter for projects owned by current user
pagenumber
Page number for pagination (default: 1)
per_pagenumber
Number of items per page (max: 100, default: 20)
searchstring
Search term for projects
search_namespacesboolean
Needs to be true if search is full path
simpleboolean
Return only limited fields
sortstring
Return projects sorted in ascending or descending orderone of asc · desc
topicstring
Filter by topic (projects tagged with this topic)
visibilitystring
Filter by project visibilityone of public · internal · private
with_issues_enabledboolean
Filter projects with issues feature enabled
with_merge_requests_enabledboolean
Filter projects with merge requests feature enabled

Sponsors

SnugThe clipboard manager you and your agent can use, safelyAgent CaffeineClose your lid, come back to finished workWaxBlock anything with supervision, without erasing your iPhoneOpen StepsSponsoredFree and open-source skills that make AI coding agents easier to understand, verify, and control.

Configuration

GITLAB_PERSONAL_ACCESS_TOKEN*secret

GitLab personal access token for local stdio use. Create a token with the GitLab scopes needed by the tools you plan to use, such as api or read_api.

GITLAB_JOB_TOKENsecret

Optional GitLab CI job token to use instead of a personal access token when running inside GitLab CI.

GITLAB_AUTH_COOKIE_PATH

Optional path to a GitLab authentication cookie file for cookie-based authentication.

GITLAB_API_URLdefault: https://gitlab.com/api/v4

GitLab API base URL. Use https://gitlab.com/api/v4 for GitLab.com or your self-managed GitLab API URL.

GITLAB_ALLOWED_PROJECT_IDS

Optional comma-separated list of GitLab project IDs that this server is allowed to access.

GITLAB_READ_ONLY_MODEdefault: false

Set to true to expose only read-only tools and block write operations.

USE_GITLAB_WIKIdefault: false

Set to true to enable GitLab wiki tools.

GITLAB_TOOLSETS

Optional comma-separated list of toolsets to enable, such as projects, issues, merge_requests, pipelines, releases, users, groups, wiki, or search.

GITLAB_TOOLS

Optional comma-separated list of individual tool names to add on top of enabled toolsets.

GITLAB_DENIED_TOOLS_REGEX

Optional regular expression used to hide matching tools from the server.

GITLAB_TOOL_POLICY_APPROVE

Optional comma-separated list of tool names that require explicit approval before execution.

GITLAB_TOOL_POLICY_HIDDEN

Optional comma-separated list of tool names to hide from tools/list.

NODE_TLS_REJECT_UNAUTHORIZED

Set to 0 only when you intentionally need to connect to a GitLab instance with invalid or self-signed TLS certificates.

GITLAB_CA_CERT_PATH

Optional path to a custom CA certificate file for self-managed GitLab instances.

Readme

GitLab MCP Server

GitHub stars npm downloads npm GitHub License Ask DeepWiki MCP Toplist mcpindex

English | 한국어 | 简体中文 | Português (Brasil)

📖 Documentation → · llms.txt · llms-full.txt

Default: 40 tools (38 core + discover_tools + help). 288 tools exist in total (285 in toolsets + execute_graphql + discover_tools + help). Start lean; call discover_tools to activate more for this session.

Install the zereight-mcp-gitlab binary first with npm install -g @zereight/mcp-gitlab, or Homebrew brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp and brew install zereight/gitlab-mcp/zereight-mcp-gitlab. Official MCP Registry listing: io.github.zereight/gitlab-mcp. One-liner: npx -y @zereight/mcp-gitlab@latest.

Without → With

Without this MCPWith this MCP
Paste MR URLs and diffs into chatlist_merge_request_changed_files → batched get_merge_request_file_diff
Hunt job logs in the GitLab UIget_pipeline_job_output with pagination
Re-explain the project path every turnproject_id=group%2Fproject and merge_request_iid=123

Three install paths

PathWhenHow
Local IDECursor, Claude Code, Codex on your machinestdio + PAT or local OAuth
Shared HTTPTeam or hosted MCPStreamable HTTP URL + remote auth or MCP OAuth
Claude.aiClaude web connectorsPublic HTTPS + GITLAB_MCP_OAUTH

Install

Install in Cursor

Install the binary first (npm install -g @zereight/mcp-gitlab, or Homebrew brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp then brew install zereight/gitlab-mcp/zereight-mcp-gitlab). Read the token without echo:

read -rs GITLAB_PERSONAL_ACCESS_TOKEN && export GITLAB_PERSONAL_ACCESS_TOKEN
# Claude Code
claude mcp add gitlab --transport stdio --scope local --env GITLAB_PERSONAL_ACCESS_TOKEN="$GITLAB_PERSONAL_ACCESS_TOKEN" --env GITLAB_API_URL=https://gitlab.com/api/v4 -- zereight-mcp-gitlab

# Codex
codex mcp add gitlab --env GITLAB_PERSONAL_ACCESS_TOKEN="$GITLAB_PERSONAL_ACCESS_TOKEN" --env GITLAB_API_URL=https://gitlab.com/api/v4 -- zereight-mcp-gitlab

Other clients: VS Code · GitHub Copilot · JSON clients · Cursor details

Agent paste-prompt

Copy this into an agent that can edit MCP config:

Install the GitLab MCP server (@zereight/mcp-gitlab) for this workspace.
Binary: zereight-mcp-gitlab (npm i -g @zereight/mcp-gitlab, or npx -y @zereight/mcp-gitlab@latest).
Auth: GITLAB_PERSONAL_ACCESS_TOKEN plus GITLAB_API_URL=https://gitlab.com/api/v4 (or GITLAB_USE_OAUTH=true).
Local: claude mcp add gitlab --transport stdio --scope local --env GITLAB_PERSONAL_ACCESS_TOKEN="$GITLAB_PERSONAL_ACCESS_TOKEN" --env GITLAB_API_URL=https://gitlab.com/api/v4 -- zereight-mcp-gitlab
Or: codex mcp add gitlab --env GITLAB_PERSONAL_ACCESS_TOKEN="$GITLAB_PERSONAL_ACCESS_TOKEN" --env GITLAB_API_URL=https://gitlab.com/api/v4 -- zereight-mcp-gitlab
Cursor: use the README deeplink or docs/clients/cursor.md.
Remote HTTP: point the client at https://mcp.example.com/mcp (Streamable HTTP). Claude.ai needs GITLAB_MCP_OAUTH on that host.
Default list: 40 tools (38 core + discover_tools + help). Call discover_tools to expand. Do not enable the api toolset unless you accept its bypass risk.
Equal non-MCP path: npx skills add zereight/gitlab-mcp --skill gitlab-mcp-skill plus the zereight-mcp-gitlab CLI.

Remote HTTP

First-class option for a hosted or self-hosted server. Point the client at a Streamable HTTP URL:

{
  "mcpServers": {
    "gitlab": {
      "type": "http",
      "url": "https://mcp.example.com/mcp"
    }
  }
}
  • Hosted / Claude.ai: GITLAB_MCP_OAUTH=true on the server (see MCP OAuth)
  • Per-user PAT headers: REMOTE_AUTHORIZATION=true (see Remote Authorization)
  • Local Docker examples are in Usage

Skill + CLI (no MCP required)

Skill + CLI is an equal path, not a fallback. Same workflows, full payloads in a terminal, no MCP registration.

npx skills add zereight/gitlab-mcp --skill gitlab-mcp-skill
zereight-mcp-gitlab user whoami
zereight-mcp-gitlab mr list

See CLI without MCP and skills/gitlab-mcp/.

MCP vs Human CLI

Use MCP whenUse the CLI when
The agent needs structured tools in chatYou need the full payload (diffs, logs, artifacts)
jmespath or compact results are enoughGITLAB_MCP_COMPACT_RESULTS is on and you want the rest in a terminal
You already registered the serverYou have a PAT or ran auth and do not want MCP

Human CLI is never compacted. Destructive tools and GITLAB_TOOL_POLICY_APPROVE tools need --yes.

Tips

project_id is a numeric ID or a URL-encoded path. Example: group group, project project, merge request !123 → project_id=group%2Fproject, merge_request_iid=123. Nested groups use %2F between every segment (group%2Fsubgroup%2Fproject).

FAQ

How do I authenticate? Local desktop: GITLAB_PERSONAL_ACCESS_TOKEN (or GITLAB_PERSONAL_ACCESS_TOKEN_FILE) is the simplest. Local OAuth is GITLAB_USE_OAUTH=true. Remote Claude.ai uses GITLAB_MCP_OAUTH. Multi-user HTTP uses REMOTE_AUTHORIZATION and a per-request token header.

Why do I only see ~40 tools? The default core toolset is 38 tools plus always-on discover_tools and help. Call discover_tools with no args to list categories, then pass a category (pipelines, wiki, …) to activate it for this session. GITLAB_TOOLSETS=all still does not enable api.

Local OAuth vs MCP OAuth vs remote auth? Local OAuth opens a browser on the same machine as the server. MCP OAuth is for a public HTTPS server and clients such as Claude.ai. Remote authorization forwards the caller's PAT or job token; there is no OAuth dance.

How do I shrink huge replies? Pass jmespath on any tool call. Or set GITLAB_MCP_COMPACT_RESULTS=true so oversized MCP replies become a preview plus a CLI command. Use the CLI when you need the full payload.

Why is the api toolset dangerous? gitlab_api_request bypasses group/project allowlists, other tool filters, and per-tool safety checks. Prompt injection can drive it. Enable it only by listing api in GITLAB_TOOLSETS. all, discover_tools, and GITLAB_TOOLS do not.

Cursor rule / CLAUDE.md snippet

GitLab merge requests, issues, and pipelines go through this MCP (@zereight/mcp-gitlab).
Start with the default core tools. Call discover_tools to expand.
Prefer list_merge_request_changed_files, then batched get_merge_request_file_diff.
Use jmespath or compact results; use the CLI for full diffs and job logs.

Star History Chart

@zereight/mcp-gitlab

Agent-workflow-optimized GitLab MCP — manage projects, merge requests, issues, pipelines, wiki, releases, tags, milestones, and more through stdio, SSE, and Streamable HTTP.

Supports PAT, OAuth, read-only mode, dynamic API URLs, and remote authorization for VS Code, Claude, Cursor, Copilot, and other MCP clients.

Why use this GitLab MCP?

  • Default 40 tools (38 core + discover_tools + help); 288 total — start lean; call discover_tools to activate more without CQRS-style grouping
  • MR 2-step review — list_merge_request_changed_files → batched get_merge_request_file_diff
  • Agent Skill built in — workflow guidance in skills/gitlab-mcp/
  • Flexible auth — Personal Access Token, local OAuth2 browser flow, MCP OAuth proxy, and per-request remote authorization
  • Multiple transports — stdio for local clients, SSE for legacy clients, and Streamable HTTP for modern remote deployments
  • Client-friendly setup — examples for Claude Code, Codex, Antigravity, OpenCode, Copilot, Cline, Roo Code, Cursor, Kilo Code, and Amp Code
  • Self-hosted ready — works with custom GitLab instances, proxy settings, and dynamic API URL routing
  • JMESPath result filtering — optional jmespath on tool calls (see tools/list) shrinks JSON results without changing GitLab API requests; when response masking is enabled, JMESPath runs on masked data.

How we compare

@zereight/mcp-gitlabGitLab MCP A (community CQRS-style)GitLab official MCP server
Best forAI agent workflowsEnterprise multi-instance / grouped toolsBuilt into GitLab, no separate install
Tool model288 tools: 285 in toolsets + execute_graphql + discover_tools + help~50–60 grouped browse_* / manage_* toolsToolsets chosen with an HTTP header
MR review2-step batched diffVariesget_merge_request with diffs
Node.js>=20.0.0Often >=24Node.js 20+ for stdio via mcp-remote
LicenseMITVariesPart of GitLab

tools/list size (measured 2026-10-24)

A client sends the whole tools/list result to the model at session start. Token estimate is UTF-8 bytes / 4.

ProfileToolsJSON bytesEst. tokens
Default (core + discover_tools + help)4050,68212,671
GITLAB_TOOL_PROFILE=slim3949,64612,412
GITLAB_TOOLSETS=all276285,67771,420

Re-measure with npm run test:mock (test/tools-list-budget.test.ts) after description or schema changes.

GitLab also ships an official MCP server.

  • Free, Premium, and Ultimate. Moved from Premium to Free in GitLab 19.2. Generally available in GitLab 19.5.
  • On GitLab.com, a top-level group Owner allows access to the MCP server. On GitLab Self-Managed and GitLab Dedicated, an administrator controls the instance setting. Default rules are on the official page.
  • Remote clients use HTTP https://<gitlab.example.com>/api/v4/mcp with OAuth 2.0 dynamic client registration.
  • stdio goes through mcp-remote and needs Node.js 20 or later.
  • Toolsets use the X-Gitlab-Enabled-Mcp-Server-Toolsets header. An optional X-Gitlab-Mcp-Server-Tool-Name-Prefix header keeps the first 32 characters of a tool-name prefix.

Full comparison with the official GitLab MCP server →

Quick start: choose either Personal Access Token or OAuth2 setup below, install @zereight/mcp-gitlab, and use zereight-mcp-gitlab in your MCP client configuration.

Client Setup Guides

  • Claude Code Setup Guide
  • VS Code Setup Guide
  • GitHub Copilot Setup Guide
  • Codex Setup Guide
  • Cursor Setup Guide
  • JSON-Based MCP Clients Setup Guide - for Factory AI Droid, OpenClaw, and OpenCode style clients
  • OAuth2 Authentication Setup Guide
  • Environment Variables Reference
  • Stateless Mode — Multi-Pod HPA
  • Custom Agents and Multiple PAT Setup

Usage

Setup Overview

Authentication Methods

The server supports four authentication methods:

For local/desktop use (most common):

  1. Personal Access Token (GITLAB_PERSONAL_ACCESS_TOKEN or GITLAB_PERSONAL_ACCESS_TOKEN_FILE) — simplest setup
  2. OAuth2 — Local Browser (GITLAB_USE_OAUTH) — recommended for better security

For server/remote deployments:

  1. OAuth2 — MCP Proxy (GITLAB_MCP_OAUTH) — for remote MCP clients such as Claude.ai
  2. Remote Authorization (REMOTE_AUTHORIZATION) — multi-user deployments where each caller provides their own token
Quick setup paths
  • Claude Code: see Claude Code Setup Guide
  • VS Code: see VS Code Setup Guide
  • GitHub Copilot: see GitHub Copilot Setup Guide
  • Codex: see Codex Setup Guide
  • Cursor: see Cursor Setup Guide
  • Factory AI Droid / OpenClaw / OpenCode style clients: see JSON-Based MCP Clients Setup Guide
  • OAuth browser flow details: see OAuth2 Authentication Setup Guide
  • OAuth without a localhost callback (SSO, remote shell, background clients): run zereight-mcp-gitlab auth (GitLab 17.9+ device flow; 17.2–17.8 need oauth2_device_grant_flow), then start the server with GITLAB_USE_OAUTH=true. See standalone device-flow command.

For the simplest local setup, start with a Personal Access Token. For browser-based local auth, use OAuth2. For remote or multi-user deployments, continue to the MCP OAuth and Remote Authorization sections later in this README.

Install the server once:

brew tap zereight/gitlab-mcp https://github.com/zereight/gitlab-mcp
brew install zereight/gitlab-mcp/zereight-mcp-gitlab

Or with npm:

npm install -g @zereight/mcp-gitlab

Or with Nix, by adding this flake to your own:

# flake.nix
inputs.gitlab-mcp.url = "github:zereight/gitlab-mcp";

# wherever you configure your MCP client:
command = lib.getExe inputs.gitlab-mcp.packages.${system}.default;

The store path is pinned by your lock file; update it with nix flake update gitlab-mcp.

The examples use zereight-mcp-gitlab, a less collision-prone alias for the legacy mcp-gitlab binary. If your MCP client cannot find it, use the absolute path from which zereight-mcp-gitlab.

No global install? Pin npx to the previous stable release (the version these docs recommend), for example npx -y @zereight/mcp-gitlab@2.3.18. If you always want the newest release, use npx -y @zereight/mcp-gitlab@latest instead. To try a fix merged to main before the next stable release, use npx -y @zereight/mcp-gitlab@next, a pre-release build that is not meant for production. The server prints a notice to stderr on startup when a newer version is available (disable with GITLAB_DISABLE_VERSION_CHECK=true).

Claude Desktop one-click install (MCP Bundle)

Every GitHub release after v2.3.1 ships a gitlab-mcp.mcpb MCP Bundle. Download the latest bundle and open it with Claude Desktop (or drag it into Settings → Extensions). Claude Desktop asks for your Personal Access Token (stored as a sensitive value) and lets you set GITLAB_API_URL, GITLAB_PERMISSION_MODE, GITLAB_TOOLSETS, and GITLAB_MASKING_ENABLED. No separate Node.js or npm install is needed.

To build the bundle from source, run npm run pack:mcpb (writes gitlab-mcp.mcpb).

Using CLI Arguments (for clients with env var issues)

Some MCP clients (like GitHub Copilot CLI) have issues with environment variables. Use CLI arguments instead:

{
  "mcpServers": {
    "gitlab": {
      "command": "zereight-mcp-gitlab",
      "args": ["--token=YOUR_GITLAB_TOKEN", "--api-url=https://gitlab.com/api/v4"],
      "tools": ["*"]
    }
  }
}

Available CLI arguments:

  • --token - GitLab Personal Access Token (replaces GITLAB_PERSONAL_ACCESS_TOKEN)
  • --api-url - GitLab API URL (replaces GITLAB_API_URL)
  • --read-only=true - Deprecated (removed in next major (v3.0.0)); use --permission-mode=readonly instead (replaces GITLAB_READ_ONLY_MODE)
  • --permission-mode - Permission level: readonly, modify (no delete or teardown tools), or full (replaces GITLAB_PERMISSION_MODE, default full)
  • --toolsets=all - Enable named toolsets except the explicit-only api toolset (replaces GITLAB_TOOLSETS; unset uses the lean core default). gitlab_api_request needs --toolsets=api
  • --tools=list_issues - Add individual tools (replaces GITLAB_TOOLS)
  • --use-wiki=true - Deprecated (removed in next major (v3.0.0)); use --toolsets=core,wiki instead (replaces USE_GITLAB_WIKI)
  • --use-milestone=true - Deprecated (removed in next major (v3.0.0)); use --toolsets=core,milestones instead (replaces USE_MILESTONE)
  • --use-pipeline=true - Deprecated (removed in next major (v3.0.0)); use --toolsets=core,pipelines and append validate_ci_lint,validate_project_ci_lint to the existing --tools list (or set --tools=validate_ci_lint,validate_project_ci_lint when that list is unset) (replaces USE_PIPELINE)
  • --disable-version-check=true - Disable the startup new-version notice (replaces GITLAB_DISABLE_VERSION_CHECK)
  • --masking-enabled=true - Enable text-response masking (replaces GITLAB_MASKING_ENABLED)
  • --masking-config - Path to a masking configuration file (replaces GITLAB_MASKING_CONFIG)
  • --masking-policy-file - Path to a protected managed-policy file (replaces GITLAB_MASKING_POLICY_FILE)
  • --masking-workspace-dir - Directory used to resolve masking files (replaces GITLAB_MASKING_WORKSPACE_DIR)
  • --download-dir - Directory download_attachment and download_job_artifacts save files under (replaces GITLAB_DOWNLOAD_DIR; default .gitlab-mcp-downloads)
  • --compact-results=true - Truncate oversized MCP tool replies and attach a CLI command for the full payload (replaces GITLAB_MCP_COMPACT_RESULTS; default off)
  • --compact-result-chars - Character threshold for compacting (replaces GITLAB_MCP_COMPACT_RESULT_CHARS; default 4000)
  • --compact-tools - Comma-separated tool names to compact when oversized, without turning global compact on (replaces GITLAB_MCP_COMPACT_TOOLS)
  • --list-summary-default=true - list_* tools and mr_discussions treat an omitted summary argument as true; summary: false still returns the full JSON (replaces GITLAB_MCP_LIST_SUMMARY_DEFAULT; default off)
  • --tool-profile - full (default) or slim. slim drops draft notes, emoji reactions, labels, CI catalog tools, and create_group from the initial list. Ignored when GITLAB_TOOLSETS is set (replaces GITLAB_TOOL_PROFILE)

If you already set GITLAB_TOOLSETS or --toolsets, append wiki, milestones, or pipelines to that list instead of replacing it. If you already set GITLAB_TOOLS or --tools, append validate_ci_lint and validate_project_ci_lint to that list instead of replacing it. An explicit list replaces the default core toolset; it does not merge.

CLI arguments take precedence over environment variables.

zereight-mcp-gitlab auth is a subcommand (not an MCP server flag). It runs GitLab device flow and exits. See CLI Arguments.

The same binary is also a gh-style GitLab CLI (tool <name> or curated forms such as mr list). No MCP registration is needed — set a PAT, or run auth and set GITLAB_USE_OAUTH=true: see CLI without MCP. setup --cursor / setup --claude prints client config; doctor checks token, API URL, toolsets, and version. Use it for the full payload in a terminal. MCP replies stay in the chat unless you set GITLAB_MCP_COMPACT_RESULTS=true (or --compact-results), which replaces oversized tool replies with a preview and a CLI command. Human CLI is never compacted. Same permission mode, toolsets, denied-tools regex, and tool-policy filters. Destructive tools and GITLAB_TOOL_POLICY_APPROVE tools need --yes. See Human CLI.

Fine-grained tool filtering: use GITLAB_PERMISSION_MODE=modify to allow create/update while blocking every delete tool and the destructive teardown tools (cancel_pipeline, cancel_pipeline_job, stop_environment, stop_stale_environments, unprotect_branch, unprotect_tag) — including destructive mutations (deletion and teardown verbs) through execute_graphql and push_files delete/move actions — or GITLAB_PERMISSION_MODE=readonly for read-only access. You can also enable toolset groups with GITLAB_TOOLSETS=<group,…>, allow-list individual tools with GITLAB_TOOLS=<tool,…> (e.g. read-only groups plus a few specific write tools), and deny-list by pattern with GITLAB_DENIED_TOOLS_REGEX. The legacy USE_GITLAB_WIKI / USE_MILESTONE / USE_PIPELINE flags are deprecated (removed in next major (v3.0.0)). Use GITLAB_TOOLSETS=core,wiki, core,milestones, or core,pipelines (USE_PIPELINE also needs validate_ci_lint,validate_project_ci_lint appended to an existing GITLAB_TOOLS list instead of replacing it). If you already set GITLAB_TOOLSETS, append the toolset to your existing list instead of replacing it. If GITLAB_TOOLS is unset, set GITLAB_TOOLS=validate_ci_lint,validate_project_ci_lint. If it is already set, append validate_ci_lint,validate_project_ci_lint instead of replacing that list. See Tools Reference and Environment Variables.

[!CAUTION] gitlab_api_request (toolset api) bypasses GITLAB_ALLOWED_GROUPS and other group restrictions, project allowlists, tool-level restrictions (GITLAB_TOOLS, GITLAB_DENIED_TOOLS_REGEX on other tools), and individual tool safety checks. The full token permission scope is exposed. Prompt injection can drive this tool. Operators who rely on these restrictions must NOT enable it. Enable it only by listing api in GITLAB_TOOLSETS (GITLAB_TOOLSETS=all, discover_tools, GITLAB_TOOLS, legacy USE_* flags, and GITLAB_TOOL_PROFILE do not). With GITLAB_ALLOWED_PROJECT_IDS or a session project scope, only /projects/:id paths for an allowed project are accepted. Endpoints such as /search, /users, /groups/:id, and /runners are rejected. Body and query parameters that name another project are not checked. GITLAB_PROJECT_ID and OAuth group allowlists are not enforced.

  • sse

Pass the variable name only. The Docker client copies the exported GITLAB_PERSONAL_ACCESS_TOKEN into the container.

docker run -i --rm \
  -e HOST=0.0.0.0 \
  -e GITLAB_PERSONAL_ACCESS_TOKEN \
  -e GITLAB_API_URL="https://gitlab.com/api/v4" \
  -e GITLAB_PERMISSION_MODE=readonly \
  -e GITLAB_TOOLSETS=core,wiki,milestones,pipelines \
  -e SSE=true \
  -e SSE_AUTH_TOKEN=your_mcp_sse_token \
  -p 3333:3002 \
  zereight050/gitlab-mcp
{
  "mcpServers": {
    "gitlab": {
      "type": "sse",
      "url": "http://localhost:3333/sse",
      "headers": {
        "Authorization": "Bearer your_mcp_sse_token"
      }
    }
  }
}
  • streamable-http
docker run -i --rm \
  -e HOST=0.0.0.0 \
  -e REMOTE_AUTHORIZATION=true \
  -e GITLAB_API_URL="https://gitlab.com/api/v4" \
  -e GITLAB_PERMISSION_MODE=readonly \
  -e GITLAB_TOOLSETS=core,wiki,milestones,pipelines \
  -e STREAMABLE_HTTP=true \
  -p 3333:3002 \
  zereight050/gitlab-mcp
{
  "mcpServers": {
    "gitlab": {
      "type": "streamable-http",
      "url": "http://localhost:3333/mcp",
      "headers": {
        "Authorization": "Bearer glpat-..."
      }
    }
  }
}
Using MCP OAuth Proxy (GITLAB_MCP_OAUTH)

For server/remote deployments only. This mode requires the MCP server to be deployed with a publicly accessible HTTPS URL. For local/desktop use, see GITLAB_USE_OAUTH above.

For remote MCP clients that support the MCP OAuth specification (e.g. Claude.ai). The server acts as a full OAuth 2.0 authorization server — unauthenticated requests receive a 401 + WWW-Authenticate response, which triggers the OAuth browser flow automatically on the client side.

Remote MCP clients such as OpenCode, MCPJam, and Claude.ai can send their own callback URL during authorization. If you cannot register every client callback URL in GitLab, enable GITLAB_OAUTH_CALLBACK_PROXY=true. With callback proxy mode, GitLab only needs one registered redirect URI: {MCP_SERVER_URL}/callback.

GITLAB_OAUTH_REDIRECT_URI is for local OAuth (GITLAB_USE_OAUTH) only. It does not override remote MCP OAuth client callback URLs and should not be used to fix remote Unregistered redirect_uri errors.

This variable exists because the local OAuth flow starts a browser on the same machine as the MCP server and listens for the callback on a local HTTP server, for example http://127.0.0.1:8888/callback.

Remote MCP OAuth is different. In GITLAB_MCP_OAUTH=true mode, the MCP client provides its own callback URL during /authorize. GITLAB_OAUTH_REDIRECT_URI does not replace that client-provided URL.

ModeEnable withCallback variableGitLab redirect URI
Local OAuthGITLAB_USE_OAUTH=trueGITLAB_OAUTH_REDIRECT_URIhttp://127.0.0.1:8888/callback or your local callback
Remote MCP OAuthGITLAB_MCP_OAUTH=trueGITLAB_OAUTH_CALLBACK_PROXY=true{MCP_SERVER_URL}/callback

Use GITLAB_OAUTH_REDIRECT_URI only when the MCP server itself owns the local browser callback. Use GITLAB_OAUTH_CALLBACK_PROXY=true when a remote MCP client owns the callback URL.

How it works: You deploy this MCP server somewhere with a public HTTPS URL. MCP clients connect to {MCP_SERVER_URL}/mcp. The server handles the OAuth 2.0 flow, exchanging credentials with GitLab on behalf of the client.

Prerequisites:

  1. A publicly accessible HTTPS server URL (MCP_SERVER_URL) — use ngrok for local testing
  2. A pre-registered GitLab OAuth application with api (or read_api) scopes — Go to Admin area → Applications, set Redirect URI to {MCP_SERVER_URL}/callback
Environment VariableRequiredDescription
GITLAB_MCP_OAUTH✅Set to true to enable
GITLAB_API_URL✅GitLab API base URL. Do not embed credentials (user:pass@) in the URL; they are ignored. A comma in a password must be written as %2C.
GITLAB_OAUTH_APP_ID✅GitLab OAuth Application ID
MCP_SERVER_URL✅Public HTTPS URL of this MCP server
STREAMABLE_HTTP✅Must be true
GITLAB_OAUTH_CALLBACK_PROXYoptionalSet to true to use the MCP server's fixed /callback URL
GITLAB_OAUTH_ALLOWED_REDIRECT_URISoptionalClient callback URLs that callback proxy mode will redirect to (default: Claude, ChatGPT, Cursor and loopback callbacks; defaults,<url> to add one)
GITLAB_OAUTH_SCOPESoptionalComma-separated scopes (default: api,read_api,read_user)
GITLAB_OAUTH_ALLOWED_GROUPSoptionalComma-separated group full paths — only members (and subgroup members) may use the server (replaces deprecated GITLAB_ALLOWED_GROUPS)
OAUTH_DISABLE_REFRESH_TOKENoptionalSet to true to issue no refresh tokens: users re-authorize in the browser each time the GitLab access token expires (2 h), regardless of the session TTL

When STREAMABLE_HTTP=true, server-side GitLab credentials (GITLAB_PERSONAL_ACCESS_TOKEN, GITLAB_JOB_TOKEN, GITLAB_AUTH_COOKIE_PATH, or GITLAB_USE_OAUTH) require REMOTE_AUTHORIZATION=true, GITLAB_MCP_OAUTH=true, or STREAMABLE_HTTP_AUTH_TOKEN.

Troubleshooting Unregistered redirect_uri

Check the redirect_uri in the browser URL. If it points to a client callback such as http://127.0.0.1:xxxxx/.../callback, enable:

GITLAB_OAUTH_CALLBACK_PROXY=true

Do not fix remote MCP OAuth by changing GITLAB_OAUTH_REDIRECT_URI. That variable is for local OAuth (GITLAB_USE_OAUTH) only.

docker run -i --rm \
  -e HOST=0.0.0.0 \
  -e GITLAB_MCP_OAUTH=true \
  -e GITLAB_OAUTH_CALLBACK_PROXY=true \
  -e STREAMABLE_HTTP=true \
  -e MCP_SERVER_URL=https://your-server.example.com \
  -e GITLAB_API_URL="https://gitlab.com/api/v4" \
  -e GITLAB_OAUTH_APP_ID=your_app_id \
  -p 3000:3002 \
  zereight050/gitlab-mcp

MCP client configuration:

{
  "mcpServers": {
    "gitlab": {
      "type": "http",
      "url": "https://your-server.example.com/mcp"
    }
  }
}
Using Remote Authorization (REMOTE_AUTHORIZATION)

For server/remote deployments only. Each HTTP caller provides their own GitLab token directly in request headers — no OAuth flow involved.

For multi-user or multi-tenant deployments where each caller provides their own GitLab token in the HTTP request header. No OAuth flow — the MCP server forwards the token to GitLab on behalf of the caller.

Header priority: Private-Token > JOB-TOKEN > Authorization: Bearer

Environment VariableRequiredDescription
REMOTE_AUTHORIZATION✅Set to true to enable
STREAMABLE_HTTP✅Must be true
ENABLE_DYNAMIC_API_URLoptionalAllow per-request GitLab URL via X-GitLab-API-URL header
GITLAB_ALLOWED_HOSTSoptionalComma-separated allowed X-GitLab-API-URL hosts; GITLAB_API_URL hosts are always allowed. Also trusted as download redirect targets (release assets, job artifacts, uploaded attachments); list private-network hosts here
GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERYoptionalAllow unauthenticated initialize, notifications/initialized, tools/list, and server/discover only (tool calls still require auth)
MCP_SERVER_URL / MCP_ALLOWED_HOSTS / MCP_ALLOWED_ORIGINSoptionalAllowed public /mcp host/origin values for DNS rebinding protection
MCP_TRUST_PROXYoptionalTrust Forwarded / X-Forwarded-* headers behind a reverse proxy (download URLs, Express req.ip, /mcp IP rate limits, OAuth rate limits)

GITLAB_ALLOW_UNAUTHENTICATED_TOOL_DISCOVERY=true is intended for MCP gateways or admin UIs that need to inspect tool metadata before a user provides a GitLab token. Leave it disabled unless the tool list is safe to expose in your deployment.

When MCP_SERVER_URL is not set, remote download URLs fall back to the local server address. Set MCP_TRUST_PROXY=true only if the server is reachable through a trusted reverse proxy and direct client access to the MCP server is blocked. This enables Express trust proxy for Streamable HTTP and SSE, derives public download URLs from Forwarded / X-Forwarded-Proto / X-Forwarded-Host / X-Forwarded-Prefix, and keeps OAuth endpoint rate limiting working when proxies send X-Forwarded-For with a client port (for example 1.2.3.4:5678). Existing OAuth+proxy deployments must set this explicitly after the flag was introduced.

Example request headers:

Private-Token: glpat-xxxxxxxxxxxxxxxxxxxx

or using a Bearer token:

Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxx

⚠️ REMOTE_AUTHORIZATION is not compatible with SSE transport. STREAMABLE_HTTP=true is required.

Environment Variables

Use the dedicated reference for the full environment variable list:

  • Environment Variables Reference

Most users only need one of these starting sets:

  • Local PAT: GITLAB_PERSONAL_ACCESS_TOKEN, GITLAB_API_URL
  • Local OAuth: GITLAB_USE_OAUTH=true, GITLAB_OAUTH_CLIENT_ID, GITLAB_OAUTH_REDIRECT_URI, GITLAB_API_URL
  • Remote multi-user HTTP: STREAMABLE_HTTP=true, REMOTE_AUTHORIZATION=true (or GITLAB_MCP_OAUTH=true), MCP_TRUST_PROXY=true (behind a reverse proxy), MAX_REQUESTS_PER_MINUTE=300, MCP_SERVER_URL or MCP_ALLOWED_HOSTS, HOST, PORT
  • Multiple side-by-side deployments: set a distinct MCP_SERVER_NAME per instance (e.g. gitlab-selfhosted-readonly) so clients, logs, and telemetry can tell them apart
  • Multi-pod HPA (stateless): above + OAUTH_STATELESS_MODE=true, OAUTH_STATELESS_SECRET (same across all pods). See Stateless Mode.

Commonly referenced variables:

  • GITLAB_API_URL
  • GITLAB_PERSONAL_ACCESS_TOKEN
  • GITLAB_USE_OAUTH
  • REMOTE_AUTHORIZATION
  • MCP_TRUST_PROXY
  • MAX_REQUESTS_PER_MINUTE
  • MAX_SESSIONS
  • MCP_ALLOWED_HOSTS
  • MCP_ALLOWED_ORIGINS
  • GITLAB_MCP_OAUTH
  • GITLAB_OAUTH_CALLBACK_PROXY
  • GITLAB_OAUTH_ALLOWED_REDIRECT_URIS
  • OAUTH_REGISTER_RATE_LIMIT_PER_HOUR
  • OAUTH_DISABLE_REFRESH_TOKEN
  • OAUTH_STATELESS_MODE
  • OAUTH_STATELESS_SECRET

The reference document also covers:

  • auth and OAuth variables
  • MCP OAuth proxy variables
  • project and tool filtering variables
  • dynamic tool discovery via discover_tools (on-demand toolset activation)
  • transport and session variables
  • proxy and TLS variables

For callback proxy mode details, see GitLab MCP OAuth Callback Proxy.

SSE session limits

GET /sse is subject to the same remote-transport controls as Streamable HTTP:

  • Capacity: at most MAX_SESSIONS concurrent SSE sessions (default 1000); further connections get 503.
  • Creation rate limit: new connections are limited to MAX_REQUESTS_PER_MINUTE per client IP (default 60); excess connections get 429.
  • Idle timeout: a session that receives no POST /messages request for SESSION_TIMEOUT_SECONDS (default 1 hour) is closed, so an idle client must reconnect instead of holding a capacity slot. Unlike Streamable HTTP, holding the SSE stream open does not count as activity.
  • /health returns 503 with status: "degraded" while the instance is at capacity.

Tune these with MAX_SESSIONS, MAX_REQUESTS_PER_MINUTE, and SESSION_TIMEOUT_SECONDS.

Streamable HTTP session timeout

Streamable HTTP sessions use the same SESSION_TIMEOUT_SECONDS idle timeout in every mode, including a server-side token without REMOTE_AUTHORIZATION or GITLAB_MCP_OAUTH: a session with no POST /mcp request for that long is closed, and its next request gets 404 so the client re-initializes. An open GET /mcp stream pauses the timer until the stream closes or the next POST /mcp arrives, so a client with a stream open still expires SESSION_TIMEOUT_SECONDS after its last POST.

Remote Authorization Setup (Multi-User Support)

When using REMOTE_AUTHORIZATION=true, the MCP server can support multiple users, each with their own GitLab token passed via HTTP headers. This is useful for:

  • Shared MCP server instances where each user needs their own GitLab access
  • IDE integrations that can inject user-specific tokens into MCP requests

Setup Example:

# Start server with remote authorization
docker run -d \
  -e HOST=0.0.0.0 \
  -e STREAMABLE_HTTP=true \
  -e REMOTE_AUTHORIZATION=true \
  -e GITLAB_API_URL="https://gitlab.com/api/v4" \
  -e GITLAB_PERMISSION_MODE=readonly \
  -e SESSION_TIMEOUT_SECONDS=3600 \
  -p 3333:3002 \
  zereight050/gitlab-mcp

Client Configuration:

Your IDE or MCP client must send one of these headers with each request:

Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxx

or

Private-Token: glpat-xxxxxxxxxxxxxxxxxxxx

The token is stored per session (identified by mcp-session-id header) and reused for subsequent requests in the same session. The session belongs to the GitLab user of that token: a request with another user's token gets 404 Session not found, and GET / DELETE /mcp without a token get 401.

Remote Authorization Client Configuration Example with Cursor
{
  "mcpServers": {
    "GitLab": {
      "url": "http(s)://<your_mcp_gitlab_server>/mcp",
      "headers": {
        "Authorization": "Bearer glpat-..."
      }
    }
  }
}

Important Notes:

  • Remote authorization only works with Streamable HTTP transport
  • Each session is isolated - tokens from one session cannot access another session's data Tokens are automatically cleaned up when sessions close
  • Session timeout: Auth tokens expire after SESSION_TIMEOUT_SECONDS (default 1 hour) of inactivity. After timeout the session is closed and its next request gets 404, so the client re-initializes with its auth headers.
  • Each request resets the timeout timer for that session
  • Rate limiting: /mcp requests are limited to MAX_REQUESTS_PER_MINUTE per client IP, and per MCP session when using OAuth or remote authorization (default 60). The per-IP limit uses a fixed 60-second window, counts per server process, and also covers GET /mcp; stateless mode skips the per-session limit. See environment-variables.md.
  • Capacity limit: Server accepts up to MAX_SESSIONS concurrent sessions (default 1000)

MCP OAuth Setup (Claude.ai Native OAuth)

When using GITLAB_MCP_OAUTH=true, the server acts as an OAuth proxy to your GitLab instance. Claude.ai (and any MCP-spec-compliant client) handles the entire browser authentication flow automatically — no manual Personal Access Token management needed.

Prerequisites:

A pre-registered GitLab OAuth application is required. GitLab restricts dynamically registered (unverified) applications to the mcp scope, which is insufficient for API calls (need api or read_api).

  1. Go to your GitLab instance → Admin Area > Applications (instance-wide) or User Settings > Applications (personal)
  2. Create a new application with:
    • Confidential: unchecked
    • Scopes: api, read_api, read_user (or whichever scopes you intend to request via GITLAB_OAUTH_SCOPES)
  3. Save and copy the Application ID — this is your GITLAB_OAUTH_APP_ID

How it works:

  1. User adds your MCP server URL in Claude.ai
  2. Claude.ai discovers OAuth endpoints via /.well-known/oauth-authorization-server
  3. Claude.ai registers itself via Dynamic Client Registration (POST /register) — handled locally by the MCP server (each client gets a virtual client ID)
  4. Claude.ai redirects the user's browser to GitLab's login page using the pre-registered OAuth application
  5. User authenticates; GitLab redirects back to https://claude.ai/api/mcp/auth_callback
  6. Claude.ai sends Authorization: Bearer <token> on every MCP request
  7. Server validates the token with GitLab and stores it per session

Server setup:

docker run -d \
  -e STREAMABLE_HTTP=true \
  -e GITLAB_MCP_OAUTH=true \
  -e GITLAB_OAUTH_APP_ID="your-gitlab-oauth-app-client-id" \
  -e GITLAB_API_URL="https://gitlab.example.com/api/v4" \
  -e MCP_SERVER_URL="https://your-mcp-server.example.com" \
  -p 3002:3002 \
  zereight050/gitlab-mcp

For local development (HTTP allowed):

MCP_DANGEROUSLY_ALLOW_INSECURE_ISSUER_URL=true \
STREAMABLE_HTTP=true \
GITLAB_MCP_OAUTH=true \
GITLAB_OAUTH_APP_ID=your-gitlab-oauth-app-client-id \
MCP_SERVER_URL=http://localhost:3002 \
GITLAB_API_URL=https://gitlab.com/api/v4 \
node build/index.js

Claude.ai configuration:

{
  "mcpServers": {
    "GitLab": {
      "url": "https://your-mcp-server.example.com/mcp"
    }
  }
}

No headers field is needed — Claude.ai obtains the token via OAuth automatically.

Environment variables:

VariableRequiredDescription
GITLAB_MCP_OAUTHYesSet to true to enable
GITLAB_OAUTH_APP_IDYesClient ID of the pre-registered GitLab OAuth application
MCP_SERVER_URLYesPublic HTTPS URL of your MCP server; also allowed for /mcp Host/Origin checks
GITLAB_API_URLYesYour GitLab instance API URL (e.g. https://gitlab.com/api/v4). Do not embed credentials (user:pass@) in the URL; they are ignored. A comma in a password must be written as %2C.
STREAMABLE_HTTPYesMust be true (SSE is not supported)
GITLAB_OAUTH_SCOPESNoComma-separated GitLab scopes to request (e.g. api,read_user). Defaults to api (or read_api when the effective permission mode is readonly). The pre-registered application must be configured with at least these scopes.
OAUTH_REGISTER_RATE_LIMIT_PER_HOURNoPer-IP limit (fixed 1-hour window) for Dynamic Client Registration (POST /register). Default 20/hour; range 1–1000. Raise when clients (e.g. multiple IDE windows) hit registration throttling. Not a GitLab API limit.
OAUTH_DISABLE_REFRESH_TOKENNoSet true to drop refresh_token from /token responses and reject the refresh grant with invalid_grant, so users re-authorize in the browser when the GitLab access token expires. Default false. In callback proxy mode, MCP clients that follow this server's flow never receive a GitLab refresh token (in passthrough the client can get one from GitLab directly). This is a re-authorization policy for standard MCP clients, not a security boundary. Refresh tokens issued before enabling stay valid until revoked in GitLab under User Settings → Applications → Authorized applications → Revoke.
MCP_DANGEROUSLY_ALLOW_INSECURE_ISSUER_URLNoSet true for local HTTP dev only

Important Notes:

  • MCP OAuth only works with Streamable HTTP transport (SSE=true is incompatible)
  • Each user session stores its own OAuth token — sessions are fully isolated
  • Session timeout, rate limiting, and capacity limits apply identically to the REMOTE_AUTHORIZATION mode (SESSION_TIMEOUT_SECONDS, MAX_REQUESTS_PER_MINUTE, MAX_SESSIONS)
  • DCR rate limiting: POST /register is limited to OAUTH_REGISTER_RATE_LIMIT_PER_HOUR per client IP (default 20/hour). Separate from /mcp limits and GitLab API quotas. See environment-variables.md.
  • Header auth fallback: when Private-Token or JOB-TOKEN request headers are present, OAuth validation is skipped and the raw token is used directly for that session. This allows PATs and CI job tokens to be used alongside the OAuth flow on the same server instance. Authorization: Bearer is always treated as an OAuth token — use Private-Token for PAT-based header auth.

Agent Skill Files

Skill + CLI is an equal path to MCP (see Skill + CLI). Pre-built skill files are available in skills/gitlab-mcp/ for AI agents that support skill/instruction loading (Claude Code, GitHub Copilot, Cursor, etc.).

  • SKILL.md — Core guide (~800 tokens) with toolset overview, key workflows, and parameter hints
  • reference/ — Detailed workflow docs for code review, merge requests, issues, pipelines, and vulnerability triage

Install with the skills CLI:

npx skills add zereight/gitlab-mcp --skill gitlab-mcp-skill

Register the skill directory in your AI client to get optimal tool usage guidance without relying solely on the full ListTools response.

Tools 🛠️

Click to expand

View the full README on GitHub

Details

Repository
github.com/zereight/gitlab-mcp
Categories
Developer Tools, Documents & Knowledge
Package
@zereight/mcp-gitlab
Transport
STDIO
Auth
Required
Registry
MCP registry, active
Tools verified
Jun 10, 2026

Related Developer Tools MCP servers

View all
1jetbrains avatarJetBrains MCP Proxy Serverjetbrains/mcp-jetbrainsA model context protocol server to work with JetBrains IDEs: IntelliJ, PyCharm, WebStorm, etc. Also, works with Android Studio952stars
2atlassian avatarAtlassian Mcp Serveratlassian/atlassian-mcp-serverAtlassian Rovo MCP Server774stars
3getsentry avatarSentry Mcpgetsentry/sentry-mcpMCP server for Sentry - error monitoring, issue tracking, and debugging for AI assistants724stars
4mark3labs avatarFilesystemmark3labs/mcp-filesystem-serverGo server implementing Model Context Protocol (MCP) for filesystem operations.640stars
5sonarsource avatarSonarqube Mcp Serversonarsource/sonarqube-mcp-serverAn MCP server that enables integration with SonarQube Server or Cloud for code quality and security.571stars
6ooo0ooo avatarLean LSPooo0ooo/lean-lsp-mcpProvides agentic access to Lean through LSP, including diagnostics, goals, hover info, and multiple search tools.379stars