Getting Started
- Zero-install with Docker
- Any MCP client
GitLab MCP Server connects your AI assistant to GitLab in under five minutes. You install the server — as a Docker image, a native binary, or through a one-click button — give it a GitLab Personal Access Token, and register it with an MCP-compatible client such as VS Code, Claude Desktop, Cursor, or Claude Code. This guide covers every install path and how to verify the connection.
GitLab MCP Server exposes over 1,000 GitLab operations — 865 tools on CE, up to 1091 on GitLab.com — through three tool modes (dynamic, meta-tool, and individual), so a single token unlocks the entire GitLab API surface.
Prerequisites
Section titled “Prerequisites”Before you begin, make sure you have:
- A GitLab instance — GitLab.com, self-hosted CE, or EE
- A Personal Access Token (PAT) with the
apiscope - An MCP-compatible AI client — VS Code + Copilot, Claude Desktop, Cursor, or Claude Code
Creating a personal access token
Section titled “Creating a personal access token”- Go to GitLab → Preferences → Access Tokens
- Create a new token with the
apiscope - Copy the token — you’ll need it for configuration
Quick install
Section titled “Quick install”Pick one: each path ends with you typing a prompt to your assistant. Every channel also has its own page with the full set of commands and the verify, upgrade and uninstall steps; start at Choose a path if you are not sure which one fits. For the full per-client reference, see Manual configuration below.
One-click buttons
Section titled “One-click buttons”These register a Docker-based server (it auto-pulls the image on first run; you need Docker installed). VS Code prompts for your token; Cursor / LM Studio / Kiro add a YOUR_GITLAB_TOKEN placeholder you replace.
For Claude Desktop, download the .mcpb desktop extension instead — a native one-click install (macOS universal + Windows) with no Docker and the token stored in the OS keychain.
Every button runs the container image; the Docker page covers its tags, the HTTP mode and how to update it.
Claude Code (claude mcp add)
Section titled “Claude Code (claude mcp add)”Docker (no install — pulls the image on first run):
export GITLAB_TOKEN=glpat-xxxxclaude mcp add gitlab --transport stdio \ -- docker run -i --rm -e GITLAB_TOKEN ghcr.io/jmrplens/gitlab-mcp-server:latestThe registration command never carries the token. -e GITLAB_TOKEN with no value forwards the variable from the environment Claude Code hands docker, so export it where you launch the client (your shell profile makes that durable) or add it to the entry’s env block afterwards.
Any other channel registers the same way once gitlab-mcp-server is on your PATH, and there the token goes in a file the server reads instead:
echo 'GITLAB_TOKEN=glpat-xxxx' > ~/.gitlab-mcp-server.envclaude mcp add gitlab -- gitlab-mcp-servernpm / npx (any platform)
Section titled “npm / npx (any platform)”Published as @jmrp.io/gitlab-mcp-server. npm downloads only the prebuilt binary for your platform: nothing compiles, and nothing runs at install time, so it works with --ignore-scripts and behind a proxy.
npx -y @jmrp.io/gitlab-mcp-serverPoint any MCP client at npx with no install at all:
{ "mcpServers": { "gitlab": { "command": "npx", "args": ["-y", "@jmrp.io/gitlab-mcp-server"], "env": { "GITLAB_URL": "https://gitlab.com", "GITLAB_TOKEN": "glpat-…" } } }}PyPI / uvx (any platform)
Section titled “PyPI / uvx (any platform)”Published as jmrplens-gitlab-mcp-server using the same model as uv and ruff: each platform wheel carries the native binary, the installer places it on the scripts path as the gitlab-mcp-server command itself, and no Python runs when the server does. The Linux wheels need glibc; on musl systems such as Alpine, use the Docker image instead.
uvx jmrplens-gitlab-mcp-server{ "mcpServers": { "gitlab": { "command": "uvx", "args": ["jmrplens-gitlab-mcp-server"], "env": { "GITLAB_URL": "https://gitlab.com", "GITLAB_TOKEN": "glpat-…" } } }}NuGet / dnx (any platform)
Section titled “NuGet / dnx (any platform)”Published on NuGet.org as gitlab-mcp-server, a .NET tool in the layout the .NET 10 SDK uses for tools that ship a native executable: a pointer package names one package per runtime identifier, each carrying the same binary, and the SDK runs it directly. It needs the .NET 10 SDK or newer, and no .NET code runs once the server is up. The Linux packages need glibc; on musl systems such as Alpine, use the Docker image instead.
dnx gitlab-mcp-server{ "mcpServers": { "gitlab": { "command": "dnx", "args": ["gitlab-mcp-server"], "env": { "GITLAB_URL": "https://gitlab.com", "GITLAB_TOKEN": "glpat-…" } } }}Arguments meant for the server go after -- (dnx gitlab-mcp-server -- --version), because dnx reads its own options anywhere on the line; and dnx installs the tool without asking when its standard input is not a terminal, which is how a client starts it, so the configuration needs no extra flag.
One-line installer (native binary)
Section titled “One-line installer (native binary)”Installs the binary onto your PATH, then registers it. Updates come from whatever installed it (brew upgrade, winget upgrade, or re-running the script); the server does not update itself.
# Linux/macOS (script; verifies the SHA-256 against checksums.txt before installing)curl -fsSL https://raw.githubusercontent.com/jmrplens/gitlab-mcp-server/main/scripts/install.sh | sh
echo 'GITLAB_TOKEN=glpat-xxxx' > ~/.gitlab-mcp-server.envclaude mcp add gitlab -- gitlab-mcp-serverHomebrew, winget and the PowerShell installer put the same binary on your PATH; each has its own page with the command, where the binary lands, and how to upgrade and uninstall:
Self-managed GitLab? Add GITLAB_URL=https://gitlab.example.com to the same file (and GITLAB_MCP_SKIP_TLS_VERIFY=true for self-signed certs), one KEY=value per line.
Try it without installing anything (hosted endpoint)
Section titled “Try it without installing anything (hosted endpoint)”A public instance runs at https://mcp.jmrp.io/gitlab — nothing to install, no account beyond your own GitLab token. Point any HTTP-capable MCP client at it:
{ "mcpServers": { "gitlab": { "type": "http", "url": "https://mcp.jmrp.io/gitlab", "headers": { "Authorization": "Bearer glpat-xxxxxxxxxxxx" } } }}The endpoint runs in OAuth mode, so the credential travels as Authorization: Bearer — a GitLab personal access token works there, verified exactly like an OAuth one. It travels per request and is never stored on the server. A client that speaks the OAuth flow needs no header at all: the 401 carries an RFC 9728 challenge it follows to authorize in the browser. PRIVATE-TOKEN is the legacy-mode header and is not accepted here; the instance is fixed to https://gitlab.com, so GITLAB-URL is ignored. A read_api token is accepted and served a read-only tool surface.
Two pages make it easier still. The server card lists the whole catalog with no credential at all and carries copy-paste config for Claude Code, Cursor and VS Code — including the OAuth client ID those clients need. The browser inspector calls the same endpoint read-only from a browser tab: sign in with OAuth, pick a tool, read the raw JSON-RPC it returns — nothing installed.
It is the fastest way to try the server, and the right way to keep using it is still locally (any option above), for one concrete reason: your token and every request pass through someone else’s machine. Running it locally keeps both on your own computer — the only sensible option for a private self-managed instance.
The endpoint is stateless streamable HTTP on the default dynamic surface: POST is the transport and an authenticated GET answers 405 by design; with no credential, any method answers 401 carrying the RFC 6750 challenge an OAuth client follows — a bare curl that gets 401 is the endpoint working, not failing. https://mcp.jmrp.io/gitlab/health needs no credential and answers 200 with {"status":"ok",…}. It is one of the servers listed at mcp.jmrp.io, a directory of the MCP servers maintained by this author, each reachable at its own endpoint; https://mcp.jmrp.io/servers.json is the same list for automated clients.
It is a personal service, run by one person and offered as-is: no SLA, no support channel, and no promise it is unchanged next week. It adds no quota of its own — every call spends GitLab.com’s own limits, under your own token. And it moves on its own, normally to the newest release, so what it serves is never a pinned version.
Download
Section titled “Download”Prefer to place the binary yourself? Download the latest binary for your platform from the GitHub Releases page:
| Platform | Binary |
|---|---|
| Linux (x86_64) | gitlab-mcp-server-linux-amd64 |
| Linux (ARM64) | gitlab-mcp-server-linux-arm64 |
| macOS (universal) | gitlab-mcp-server-darwin-all |
| macOS (Intel) | gitlab-mcp-server-darwin-amd64 |
| macOS (Apple Silicon) | gitlab-mcp-server-darwin-arm64 |
| Windows (x86_64) | gitlab-mcp-server-windows-amd64.exe |
| Windows (ARM64) | gitlab-mcp-server-windows-arm64.exe |
| Claude Desktop | gitlab-mcp-server.mcpb — see Claude Desktop Extension |
Make it executable (Linux/macOS)
Section titled “Make it executable (Linux/macOS)”chmod +x gitlab-mcp-server-*Optionally, move it to a directory in your PATH:
sudo mv gitlab-mcp-server-linux-amd64 /usr/local/bin/gitlab-mcp-serverChecking the download against checksums.txt and its Cosign signature, upgrading and uninstalling are on the Native binary page.
Running the binary by hand
Section titled “Running the binary by hand”There is no setup wizard. MCP configuration belongs in your client’s own JSON file, which is what Manual configuration below documents, and a wizard writing a dotfile on one machine could not put it there.
Running the binary in a terminal without both GITLAB_TOKEN and GITLAB_URL set (either one missing is enough), or double-clicking it, prints what the server is, the two values it needs, and where the per-client JSON is documented, then waits for Enter so a double-clicked window on Windows does not close before you can read it. An MCP client never sees that screen: a client connects pipes rather than a terminal, so the server starts normally.
Install as an Agent Plugin (Cursor / Claude Code / VS Code)
Section titled “Install as an Agent Plugin (Cursor / Claude Code / VS Code)”This repository ships an Agent Plugins 1.0 manifest (root plugin.json and MCP config mcp.json), plus the legacy Open Plugins manifest (.plugin/plugin.json) for older hosts, so the server installs in one step on a conformant host (Cursor, Claude Code, VS Code, OpenCode). Providing the token is a separate step, described below:
# Cursor / Claude Code (when supported by your version)/plugin install jmrplens/gitlab-mcp-serverThe plugin runs the published Docker image ghcr.io/jmrplens/gitlab-mcp-server:latest through docker run -i --rm and passes no transport flag, so you need Docker installed and running. The image reads the transport off stdin and -i is what puts a pipe there, so keep the -i if you copy the Docker configuration into VS Code or another stdio client; without it the container gets /dev/null, starts an HTTP listener, and the client waits forever for a stdio initialize response.
Required environment
Section titled “Required environment”GITLAB_TOKEN is the one required value; GITLAB_URL matters only for a self-managed instance. The bundled config forwards both into the container, but your host has to put them in the plugin’s environment first: Agent Plugins §9.1 lets a client “inherit, omit, or sanitize” ambient variables, and the spec defines no portable way for a plugin to reference a secret, so a token cannot travel inside mcp.json itself. If the server reports an authorization failure, set GITLAB_TOKEN the way your host documents, or add it to the env block of the installed plugin’s local mcp.json. The full table of forwarded variables is on the Agent Plugins page.
Prefer a native binary instead of Docker?
Section titled “Prefer a native binary instead of Docker?”Install the plugin, then edit the installed plugin’s local mcp.json (commonly under .agents/plugins/gitlab-mcp-server/) and replace the Docker command / args with the path to a binary from any channel above. The Agent Plugins page has the exact file to write, and why a ${GITLAB_TOKEN} placeholder in it would reach the server literally. For detached HTTP deployments, do not use a stdio entry: run the image in HTTP mode and configure the client with type: "http" and a URL such as http://localhost:8080/mcp, as described in HTTP Server Mode.
Manual configuration
Section titled “Manual configuration”GITLAB_URL defaults to https://gitlab.com; add it only for self-managed GitLab instances.
If you prefer to configure manually, choose your AI client:
Create or edit .vscode/mcp.json in your workspace root:
{ "servers": { "gitlab": { "type": "stdio", "command": "/path/to/gitlab-mcp-server", "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{ "mcpServers": { "gitlab": { "command": "/path/to/gitlab-mcp-server", "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}Create or edit .cursor/mcp.json in your project root:
{ "mcpServers": { "gitlab": { "command": "/path/to/gitlab-mcp-server", "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}Write the token where the server reads it, then add the server using the CLI:
echo 'GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx' > ~/.gitlab-mcp-server.envchmod 600 ~/.gitlab-mcp-server.env
claude mcp add gitlab \ --transport stdio \ -- /path/to/gitlab-mcp-serverAdd GITLAB_URL=https://gitlab.example.com to the same file for a self-managed instance. Nothing names the token on the command line, so it stays out of argv and out of Claude Code’s own configuration file.
Edit ~/.codeium/windsurf/mcp_config.json:
{ "mcpServers": { "gitlab": { "command": "/path/to/gitlab-mcp-server", "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}- Open Settings → Tools → AI Assistant → MCP Servers
- Click + Add and select stdio
- Set the command to
/path/to/gitlab-mcp-server - Add
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx - Add
GITLAB_URLonly for self-managed instances - Click OK and restart the IDE
Edit your Zed settings.json and add:
{ "context_servers": { "gitlab": { "command": "/path/to/gitlab-mcp-server", "args": [], "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}Create or edit .kiro/mcp.json in your project root:
{ "mcpServers": { "gitlab": { "command": "/path/to/gitlab-mcp-server", "args": [], "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}Open the Cline sidebar → click the MCP servers icon → Edit Global MCP, or edit the settings file directly:
- macOS:
~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json - Linux:
~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json - Windows:
%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json
{ "mcpServers": { "gitlab": { "command": "/path/to/gitlab-mcp-server", "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}Using a dotenv file
Section titled “Using a dotenv file”Instead of placing secrets in client config files, you can put them in a dotenv file:
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxxAdd GITLAB_URL=https://gitlab.example.com for self-managed GitLab.
The server reads ~/.gitlab-mcp-server.env for values its environment does not already carry. To keep the file somewhere else, name it by absolute path in GITLAB_MCP_ENV_FILE.
A .env in the working directory is not read. Your editor sets that directory to the workspace it opened, so the file arrives with the repository rather than from you; one that exists is named in the startup log with the keys it wanted to set. See Configuration for the full load order.
HTTP mode
Section titled “HTTP mode”For team deployments, you can run the server in HTTP mode where each user authenticates with their own token:
./gitlab-mcp-server --http --http-addr=0.0.0.0:8080 --gitlab-url=https://gitlab.comEach client connects via HTTP and provides their own GitLab token. See HTTP Server Mode for details.
OAuth mode (recommended for production)
Section titled “OAuth mode (recommended for production)”For zero-config token management, use OAuth mode. Users authorize through the browser — no token copying or distribution required:
./gitlab-mcp-server --http --gitlab-url=https://gitlab.com --auth-mode=oauth --public-url=https://mcp.example.comMCP clients that support OAuth 2.1 (VS Code, Claude Code) discover the authorization server automatically via /.well-known/oauth-protected-resource. See docs/guides/oauth-app-setup.md for creating the required GitLab OAuth Application.
Self-hosted GitLab
Section titled “Self-hosted GitLab”If you’re connecting to a self-hosted GitLab instance (Community Edition or Enterprise Edition), the setup is the same — just make sure GITLAB_URL points to your internal instance:
GITLAB_URL=https://gitlab.internal.company.comGITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxxSelf-signed certificates
Section titled “Self-signed certificates”Many self-hosted instances use self-signed or internal CA certificates. If you see x509: certificate signed by unknown authority errors, add:
GITLAB_MCP_SKIP_TLS_VERIFY=trueCommon configurations
Section titled “Common configurations”GITLAB_URL=https://gitlab.internal.company.comGITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxxGITLAB_URL=https://gitlab.company.com:8443GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxxGITLAB_URL=http://gitlab.local:3000GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxxGITLAB_URL=https://gitlab.internal.company.comGITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxxGITLAB_MCP_SKIP_TLS_VERIFY=trueBoth GitLab CE (free) and EE (Premium/Ultimate) are fully supported. For EE-exclusive features like DORA metrics, epics, and vulnerability management, set GITLAB_MCP_TIER=premium (or GITLAB_MCP_TIER=ultimate) in stdio mode or use --tier=premium/--tier=ultimate in HTTP mode. When unset, the tier is detected from GET /license (fallback free). The legacy boolean GITLAB_ENTERPRISE=true environment variable is still honored in stdio mode for compatibility but is deprecated; HTTP mode reads --tier only, and there is no --enterprise flag. See Configuration for all available options.
Verify the setup
Section titled “Verify the setup”Once configured, open your AI client and ask:
Who am I on GitLab?The server should return your GitLab user profile, confirming the connection is working. You can also try:
List my assigned merge requestsShow recent pipelines in my-projectIf you see results, you’re all set!
Understanding tool surfaces
Section titled “Understanding tool surfaces”By default, the server runs in dynamic find/execute mode with gitlab_find_action and gitlab_execute_action. Every GitLab operation is a catalog action with a canonical domain.action ID: the assistant finds the one it needs (with its exact parameter schema) and then executes it. Creating an issue looks like this:
{ "tool": "gitlab_execute_action", "arguments": { "action": "issue.create", "params": { "project_id": "my-group/my-project", "title": "Fix login redirect" } }}Set GITLAB_MCP_TOOL_SURFACE=meta to use 34 domain-level meta-tools (51 on self-managed Enterprise/Premium, 52 on GitLab.com Enterprise/Premium with Orbit) that cover the same functionality through consolidated domain dispatchers. Instead of separate gitlab_issue_list, gitlab_issue_create and gitlab_issue_update tools (the GITLAB_MCP_TOOL_SURFACE=individual shape), there is a single gitlab_issue tool with an action parameter: the same call goes to gitlab_issue as { "action": "create", "params": { ... } }. Meta-tools accept only action and params at the top level, so the parameters stay nested under params on both surfaces.
This is transparent to you: your AI client handles the routing. You just ask naturally, “create an issue for the login bug”, and on the default dynamic surface the assistant finds issue.create and executes it; with GITLAB_MCP_TOOL_SURFACE=meta it picks the gitlab_issue meta-tool and the create action instead.
Next steps
Section titled “Next steps”- Configuration — Fine-tune environment variables and optional features
- Dynamic toolset — How the default find/execute surface discovers and runs every operation
- Meta-tools — The consolidated domain dispatchers behind
GITLAB_MCP_TOOL_SURFACE=meta - Architecture — Understand how the server works under the hood
- Tools Reference — Explore all available tools by domain
Frequently asked questions
What GitLab token scope does GitLab MCP Server need?
GitLab MCP Server needs a Personal Access Token with the api scope for full read and write access to the GitLab REST and GraphQL API. For a read-only setup, create a token with the read_api scope: the server detects the scope at startup and serves only the read actions, and GITLAB_MCP_READ_ONLY=true does the same for a token that could write. Create tokens under GitLab, then Preferences, then Access Tokens.
How do I connect GitLab MCP Server to a self-managed GitLab instance?
Point GITLAB_URL at your instance, for example GITLAB_URL=https://gitlab.example.com. GITLAB_URL defaults to https://gitlab.com, so you set it only for self-managed Community or Enterprise Edition instances. If the instance uses a self-signed or internal CA certificate, also set GITLAB_MCP_SKIP_TLS_VERIFY=true to bypass certificate verification on a trusted network.
Which tool mode does GitLab MCP Server use by default?
By default GitLab MCP Server runs in dynamic mode, which exposes only two tools — gitlab_find_action and gitlab_execute_action — to keep the AI client's context small while still reaching every GitLab operation. Set GITLAB_MCP_TOOL_SURFACE=meta for consolidated domain-level meta-tools, or GITLAB_MCP_TOOL_SURFACE=individual for one tool per operation.
Why does my AI client fail to connect to GitLab MCP Server?
A failed connection usually means GitLab MCP Server cannot reach GitLab or cannot authenticate. Confirm that GITLAB_URL is correct and reachable from your machine, that the token carries the api scope (or read_api in read-only mode) and has not expired, and that self-signed certificates are handled by setting GITLAB_MCP_SKIP_TLS_VERIFY=true.