gitlab-mcp

module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 27, 2026 License: Apache-2.0

README

gitlab-mcp

CI Release Go Reference

An MCP server for gitlab.com. One binary over stdio, signed in as you. It works inside projects: issues, merge requests, reviews, the repository and CI. Instance and group administration, runners, CI variables and tokens are out of scope.

Unofficial, and not affiliated with GitLab Inc. See NOTICE.

What makes this one different

  • A small surface, gated by registration. About fifty tools rather than an API mirror, and a tool that is switched off is not registered, so it cannot be called at all.
  • Nothing it writes runs a quick action. /merge in a comment is refused or escaped, never executed.
  • Content is marked as untrusted. Issues, reviews, files and job logs come back inside boundaries the content cannot close.
  • Signs in like a desktop app. Your own OAuth application, a browser tab, the token in the OS keyring.
  • Verifiable releases. Signed checksums, build provenance and SBOMs.

Status

Stable: the release badge above names the newest tag, and CHANGELOG.md says what each one holds. The tool surface is a contract: tools keep their names and output fields. docs/architecture.md §16 is the plan.

Tools

Tool What it does
get_me Who is signed in, with which scopes, and what GitLab reports about itself
resolve_url Turn a GitLab web URL into the arguments another tool takes, and name that tool
search_projects Find projects by name, or within a group
get_project One project: default branch, visibility, what it has turned on
list_members Who has access to a project, and with which role
find_users Accounts by exact username or by name
search_issues Find issues across gitlab.com, a group or a project
get_issue One issue, its description marked as untrusted content
create_issue Create an issue; labels, assignees and milestone checked first
update_issue Change an issue's fields, refused if it changed since you read it
list_discussions The comment threads on an issue or a merge request
add_comment Comment on an issue or merge request, reply in a thread, or start one, on a diff line or not
resolve_discussion Resolve or reopen a thread on a merge request or an issue
link_issues Link two issues, in one project or two
unlink_issues Remove the link between two issues
search_merge_requests Find merge requests across gitlab.com or a project
get_merge_request One merge request with its approvals
list_mr_files The files a merge request changes, with line counts and GitLab's markers
get_mr_diff A merge request's diffs, file by file, bounded
list_mr_commits A merge request's commits
create_merge_request Open a merge request from a branch
update_merge_request Change a merge request's fields, refused if it changed since you read it
add_review_comment A draft review comment, on the merge request or a diff line
list_review_comments Your unpublished review comments on a merge request
delete_review_comment Delete one of your drafts
submit_review Publish all your drafts at once, with a summary and reviewer state
get_file A file at a ref, bounded
list_tree A directory listing at a ref
list_branches A project's branches
list_commits Commits on a ref or a path
get_commit One commit and its diff, bounded
compare_refs The commits and diffs between two refs, bounded
list_tags A project's tags
create_branch Create a branch from a ref
create_commit Commit file changes to a branch; never the default or a protected one
get_blame Who last changed each line of a file, bounded
cherry_pick_commit Apply a commit to a branch; never the default or a protected one
revert_commit Undo a commit on a branch with a new one; never the default or a protected one
list_pipelines A project's CI pipelines
get_pipeline One pipeline with the jobs that failed, trigger jobs included
list_jobs A pipeline's jobs
get_job_log A window of a job's log, secrets masked; the failing section on request
lint_ci Check a project's CI configuration at a ref, or configuration you pass
list_job_artifacts The files a job kept as artifacts
get_job_artifact One text file of a job's artifacts, secrets masked, bounded
list_labels The labels a project's issues and merge requests can carry
list_milestones A project's or a group's milestones
search Code, commits, comments and more, in a project, a group or everywhere
list_todos Your to-do items
mark_todos_done Mark your to-do items done
merge_merge_request Merge at the head you reviewed, or when the pipeline succeeds (Ship)
approve_merge_request Approve at the head you reviewed (Ship)
unapprove_merge_request Withdraw your approval (Ship)
rebase_merge_request Rebase a merge request's source branch, from the head you reviewed (Ship)
move_issue Move an issue to another project, never to one more people can see (Ship)
run_pipeline Run a pipeline for a ref, with variables whose values are never shown (Ship)
retry_pipeline Retry a pipeline's failed and canceled jobs (Ship)
retry_job Run a finished job again, with inputs (Ship)
play_job Start a manual job, with variables and inputs (Ship)
cancel_pipeline Cancel a running pipeline (Ship)
delete_branch Delete a branch; never the default, a protected or an unmerged one unless asked (Destructive)
delete_comment Delete one of your own comments (Destructive)
list_wiki_pages A project wiki's pages (wiki toolset)
get_wiki_page One wiki page, bounded (wiki toolset)
save_wiki_page Create a wiki page, or change one unchanged since you read it (wiki toolset)
delete_wiki_page Delete a wiki page (wiki toolset, Destructive)
list_snippets A project's snippets, or your own (snippets toolset)
get_snippet One snippet and a file of it, bounded (snippets toolset)
create_snippet Create a snippet, always private (snippets toolset)
list_releases A project's releases (releases toolset)
get_release One release and its notes (releases toolset)
create_release Create a release, and its tag at a ref, with asset links to the project's own pages (releases toolset, Ship)
create_tag Create a tag at a ref; never a protected one (releases toolset)
delete_tag Delete a tag; never a protected one (releases toolset, Destructive)
create_label Create a project label (planning toolset)
update_label Change a project label unchanged since you read it (planning toolset)
delete_label Delete a project label (planning toolset, Destructive)
create_milestone Create a project milestone (planning toolset)
update_milestone Change, close or reopen a milestone unchanged since you read it (planning toolset)
delete_milestone Delete a project milestone (planning toolset, Destructive)
list_environments A project's environments and their last deployment (deployments toolset)
list_deployments What was deployed where, and by which job (deployments toolset)
list_events Recent activity, yours or a project's (activity toolset)

Ship and Destructive tools are registered only with the settings below, and the six toolsets only when GITLAB_MCP_TOOLSETS names them.

Three resources carry the same text for clients that attach rather than call: an issue, a merge request and a job log.

Install

Download an archive for your platform from the releases page, or:

go install github.com/mmedum/gitlab-mcp/cmd/gitlab-mcp@latest

Claude Desktop users can open the .mcpb bundle from the same release. It does not log you in; do the steps below first.

Sign in

You bring your own OAuth application. Nothing is shipped in the binary, and there are no personal access tokens.

  1. Register an application, once. On gitlab.com: your avatar → Edit profile → Applications (or a group's). Redirect URI http://127.0.0.1/callback, Confidential unchecked, scope api (read_api for read-only). docs/setup.md has the exact values.

  2. Log in from a terminal:

    gitlab-mcp login --client-id <application id>
    

    It prints the scopes it will ask for, opens your browser, and stores the token in the OS keyring. On a machine without a browser, --no-browser prints the URL and the ssh -L line to forward the callback.

  3. Check it:

    gitlab-mcp doctor
    

    doctor walks the connection, TLS, the sign-in, the application, the granted scopes and one call as you, and names what is missing. status and logout do what they say; --profile keeps two gitlab.com logins side by side.

Connect a client

Claude Code:

claude mcp add gitlab -- gitlab-mcp

Any client that takes a JSON server list:

{
  "mcpServers": {
    "gitlab": { "command": "gitlab-mcp" }
  }
}

Claude Desktop can instead open the .mcpb bundle from a release.

Configuration

Every setting is an environment variable with the GITLAB_MCP_ prefix and a matching flag. docs/configuration.md lists them all.

Safety

GitLab content was written by someone other than you, and some of it is written to steer an agent. The server marks it as untrusted data, never fetches what it references, and nothing it adds tells the model to act on it.

What can be registered depends on the settings, because GitLab's api scope cannot separate any of it:

Setting Registers
GITLAB_MCP_READ_ONLY=true Read tools only, with a read_api token
default Read and Write: issues, comments, reviews, branches, merge requests
GITLAB_MCP_ENABLE_SHIP=true adds merging, approving, running CI and releases
GITLAB_MCP_ENABLE_DESTRUCTIVE=true adds deletion, and each call must pass confirm: true
  • No quick actions. GitLab runs /merge, /close and the rest from a description or comment. Every body this server sends is checked, and a quick-action line is refused, or escaped when you ask.
  • Protected branches. Code reaches the default branch or a protected branch only through a merge request; a direct commit there is refused.
  • No blind retries. A create that may or may not have happened is settled by reading, never by creating again.

The default token can still merge and approve; leaving Ship off stops this server doing so, not anything else holding the token. docs/security.md says more.

Verify a release

Each release signs checksums.txt with a keyless Sigstore certificate and attests every archive and the bundle:

sha256sum -c checksums.txt --ignore-missing
cosign verify-blob checksums.txt --bundle checksums.txt.bundle \
  --certificate-identity "https://github.com/mmedum/gitlab-mcp/.github/workflows/release.yml@refs/tags/<tag>" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
gh attestation verify <archive> --repo mmedum/gitlab-mcp

Contributing

CONTRIBUTING.md. Security reports go through SECURITY.md, not an issue.

License

Apache-2.0. See LICENSE and NOTICE.

Directories

Path Synopsis
cmd
gitlab-mcp command
Command gitlab-mcp is an MCP server for GitLab.
Command gitlab-mcp is an MCP server for GitLab.
internal
app
Package app is the startup assembly every entry point shares: open the profile, settle the OAuth application, build the HTTP transport, the token source and the GitLab client, refuse a mode the sign-in cannot serve, and wire the MCP server.
Package app is the startup assembly every entry point shares: open the profile, settle the OAuth application, build the HTTP transport, the token source and the GitLab client, refuse a mode the sign-in cannot serve, and wire the MCP server.
auth
Package auth is the family's sign-in on GitLab's OAuth provider: the person's own OAuth application, a loopback redirect on 127.0.0.1 with a random port, PKCE S256, and a refreshing token source that survives GitLab's immediate rotation (docs/architecture.md §10).
Package auth is the family's sign-in on GitLab's OAuth provider: the person's own OAuth application, a loopback redirect on 127.0.0.1 with a random port, PKCE S256, and a refreshing token source that survives GitLab's immediate rotation (docs/architecture.md §10).
config
Package config loads and validates the runtime configuration.
Package config loads and validates the runtime configuration.
credentials
Package credentials stores and resolves the OAuth token of one profile: access token, refresh token, expiry and type.
Package credentials stores and resolves the OAuth token of one profile: access token, refresh token, expiry and type.
diffpos
Package diffpos computes where an inline comment lands: GitLab's diff position for a line of a merge request's diff, from the file's unified diff and the diff version's refs (docs/architecture.md §7.4).
Package diffpos computes where an inline comment lands: GitLab's diff position for a line of a merge request's diff, from the file's unified diff and the diff version's refs (docs/architecture.md §7.4).
fileperm
Package fileperm restricts a file to the account that wrote it: mode 0600 on Unix, an explicit access list on Windows, where a mode only sets the read-only attribute and protects nothing.
Package fileperm restricts a file to the account that wrote it: mode 0600 on Unix, an explicit access list on Windows, where a mode only sets the read-only attribute and protects nothing.
gapi
Package gapi is the raw REST client for GitLab's API v4.
Package gapi is the raw REST client for GitLab's API v4.
gapi/gitlabtest
Package gitlabtest is an in-memory GitLab behind httptest, for tests.
Package gitlabtest is an in-memory GitLab behind httptest, for tests.
gitlab
Package gitlab holds the wire types of GitLab's REST API v4.
Package gitlab holds the wire types of GitLab's REST API v4.
instance
Package instance normalizes the GitLab base URL (gitlab.com, or the loopback test instance), checks URLs against it, reads the instance's version and edition, and turns GitLab web URLs into tool arguments.
Package instance normalizes the GitLab base URL (gitlab.com, or the loopback test instance), checks URLs against it, reads the instance's version and edition, and turns GitLab web URLs into tool arguments.
model
Package model is the server's view of what GitLab returns: the shapes every tool result carries as structuredContent, under its output schema.
Package model is the server's view of what GitLab returns: the shapes every tool result carries as structuredContent, under its output schema.
quickaction
Package quickaction finds and neutralizes the lines of a Markdown body that GitLab would run as quick actions.
Package quickaction finds and neutralizes the lines of a Markdown body that GitLab would run as quick actions.
redact
Package redact masks what this server prints for a person and must not survive being pasted somewhere else, and the secrets a job log can carry.
Package redact masks what this server prints for a person and must not survive being pasted somewhere else, and the secrets a job log can carry.
render
Package render turns the server's model into the readable half of a tool result, and prepares text other people wrote before anything shows it (docs/architecture.md §4.1, §4.8).
Package render turns the server's model into the readable half of a tool result, and prepares text other people wrote before anything shows it (docs/architecture.md §4.1, §4.8).
scopes
Package scopes is the one source of truth for the OAuth scopes this server requests in each mode, the scope each kind of tool needs, and the text people paste when they register their OAuth application.
Package scopes is the one source of truth for the OAuth scopes this server requests in each mode, the scope each kind of tool needs, and the text people paste when they register their OAuth application.
server
Package server wires the tools onto the MCP SDK and dumps the tool surface.
Package server wires the tools onto the MCP SDK and dumps the tool surface.
service
Package service is the orchestration between the tools and the REST client: resolving a project once per call, the reads that take more than one request, and turning wire types into the model a result carries, with every piece of other people's text prepared by render on the way (docs/architecture.md §4.1, §4.8).
Package service is the orchestration between the tools and the REST client: resolving a project once per call, the reads that take more than one request, and turning wire types into the model a result carries, with every piece of other people's text prepared by render on the way (docs/architecture.md §4.1, §4.8).
tools
Package tools registers the MCP tools.
Package tools registers the MCP tools.
userconfig
Package userconfig stores non-secret, per-profile state between runs: which instance a profile signs in to, which OAuth application it uses, who signed in, where the token went and which scopes GitLab granted.
Package userconfig stores non-secret, per-profile state between runs: which instance a profile signs in to, which OAuth application it uses, who signed in, where the token went and which scopes GitLab granted.
version
Package version reports the binary's version.
Package version reports the binary's version.
scripts
evals command
The evals are behind a build tag so an ordinary `go build ./...` never reaches for a model.
The evals are behind a build tag so an ordinary `go build ./...` never reaches for a model.
gates command
Command gates runs the repository's own checks.
Command gates runs the repository's own checks.
internal/gatekit
Package gatekit is what several gates share that is not git, a TSV record or an MCP session: the repository's names, how a list of problems becomes one failure, and the few readers more than one gate needs.
Package gatekit is what several gates share that is not git, a TSV record or an MCP session: the repository's names, how a list of problems becomes one failure, and the few readers more than one gate needs.
internal/gitx
Package gitx is the few git questions the gates and drivers ask, as one line of plumbing each.
Package gitx is the few git questions the gates and drivers ask, as one line of plumbing each.
internal/mcpstdio
Package mcpstdio is a small MCP client over a child process's stdio, for the programs under scripts/ that drive the built server: the smoke gate, the live driver and the evals.
Package mcpstdio is a small MCP client over a child process's stdio, for the programs under scripts/ that drive the built server: the smoke gate, the live driver and the evals.
internal/redact
Package redact is how the programs under scripts/ that drive a real instance print: through one Printer, which masks what a run can carry.
Package redact is how the programs under scripts/ that drive a real instance print: through one Printer, which masks what a run can carry.
internal/tsv
Package tsv is the one reader for the record files the gates hold the code against — API verdicts, field verdicts, live-driver waivers, coverage exemptions — so they cannot disagree about blank lines, comments, a trailing TAB or a key listed twice.
Package tsv is the one reader for the record files the gates hold the code against — API verdicts, field verdicts, live-driver waivers, coverage exemptions — so they cannot disagree about blank lines, comments, a trailing TAB or a key listed twice.
livegitlab command
The live driver is behind a build tag, so an ordinary `go build ./...` never reaches an instance or an account.
The live driver is behind a build tag, so an ordinary `go build ./...` never reaches an instance or an account.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL