Skip to content

Latest commit

 

History

History
496 lines (356 loc) · 30.3 KB

File metadata and controls

496 lines (356 loc) · 30.3 KB

Getting Started

A step-by-step tutorial to get gitlab-mcp-server running and make your first GitLab query through an AI assistant.

Diátaxis type: Tutorial Audience: New users Time: ~5 minutes 📖 User documentation: See the Getting Started on the documentation site for a user-friendly version.


Prerequisites

  • A GitLab instance (self-hosted or gitlab.com)
  • A Personal Access Token with api scope (how to create one)
  • An MCP-compatible AI client (VS Code with GitHub Copilot, Claude Desktop, Cursor, etc.)

Headless / CI usage? See the CI/CD Usage guide for running in pipelines without an interactive client.


Fastest path

If you just want it running, pick one of these and skip the manual steps below. Every channel has a full section in the Installation guide: what it needs, where the binary lands, how to verify a download, and how to upgrade or uninstall.

One-click buttons

Each registers a Docker-based server (auto-pulls the image on first run; needs Docker). VS Code prompts for your token; Cursor / LM Studio / Kiro add a YOUR_GITLAB_TOKEN placeholder you replace.

Install in VS Code Install in Cursor Add to LM Studio Add to Kiro

Claude Code (claude mcp add)

Docker (no install — pulls the image on first run):

export GITLAB_TOKEN=glpat-xxxx
claude mcp add gitlab --transport stdio \
  -- docker run -i --rm -e GITLAB_TOKEN ghcr.io/jmrplens/gitlab-mcp-server:latest

The registration command carries no 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. A container never reads ~/.gitlab-mcp-server.env, which is where the native-binary paths below put it.

npm / npx (any platform)

The server is published as @jmrp.io/gitlab-mcp-server. npm downloads only the prebuilt binary for your platform — nothing compiles, nothing runs at install time.

npx -y @jmrp.io/gitlab-mcp-server          # zero install; clients launch it directly
npm install -g @jmrp.io/gitlab-mcp-server  # or install globally (npm)
pnpm add -g @jmrp.io/gitlab-mcp-server     # or globally (pnpm)

Point 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-…" }
    }
  }
}

Update with npm update -g @jmrp.io/gitlab-mcp-server: npm owns the binary, as every distribution channel does, and the server never replaces itself on disk. The Linux packages declare libc: ["glibc"] because the prebuilt binaries need the glibc dynamic loader, so npm skips them on musl systems such as Alpine; there, run the Docker image (docker run -i --rm -e GITLAB_TOKEN ghcr.io/jmrplens/gitlab-mcp-server:latest) or build from source.

PyPI / uvx (any platform)

The server is also 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 unprefixed PyPI name is an empty registration by an unrelated account, under PEP 541 reclamation.)

uvx jmrplens-gitlab-mcp-server             # zero install; clients launch it directly
pipx install jmrplens-gitlab-mcp-server    # or install globally (pipx)
pip install jmrplens-gitlab-mcp-server     # or into the active environment (pip)
# Linux wheels need glibc; on musl systems such as Alpine use the Docker image instead
{
  "mcpServers": {
    "gitlab": {
      "command": "uvx",
      "args": ["jmrplens-gitlab-mcp-server"],
      "env": { "GITLAB_URL": "https://gitlab.com", "GITLAB_TOKEN": "glpat-…" }
    }
  }
}

Like npm, the Linux wheels need glibc (manylinux); on musl systems such as Alpine use the Docker image instead.

NuGet / dnx (any platform)

The server is also 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; no .NET code runs once the server is up.

dnx gitlab-mcp-server                      # zero install; clients launch it directly
dotnet tool install -g gitlab-mcp-server   # or install globally (dotnet tool)
# Linux packages need glibc; on musl systems such as Alpine use the Docker image instead
{
  "mcpServers": {
    "gitlab": {
      "command": "dnx",
      "args": ["gitlab-mcp-server"],
      "env": { "GITLAB_URL": "https://gitlab.com", "GITLAB_TOKEN": "glpat-…" }
    }
  }
}

Two dnx habits worth knowing: it parses its own options anywhere on the line, so arguments meant for the server go after -- (dnx gitlab-mcp-server -- --version; without the separator --version is dnx's own option and prints its usage), and it installs the tool without asking when its standard input is not a terminal, which is how a client starts it, so the configuration above needs no extra flag.

One-line installer (native binary)

# macOS/Linux (Homebrew)
brew install jmrplens/tap/gitlab-mcp-server
# Linux/macOS (script)
curl -fsSL https://raw.githubusercontent.com/jmrplens/gitlab-mcp-server/main/scripts/install.sh | sh
# Windows (winget)
winget install --id jmrplens.gitlab-mcp-server -e
# Windows (PowerShell)
irm https://raw.githubusercontent.com/jmrplens/gitlab-mcp-server/main/scripts/install.ps1 | iex

echo 'GITLAB_TOKEN=glpat-xxxx' > ~/.gitlab-mcp-server.env
claude mcp add gitlab -- gitlab-mcp-server

Claude Desktop one-click extension (.mcpb)

Claude Desktop users can skip all of the above: download gitlab-mcp-server.mcpb and open it with Claude Desktop — see the Claude Desktop Extension guide.

The server reads ~/.gitlab-mcp-server.env for values its environment does not already carry, one KEY=value per line, which is why the registration command names no token. Self-managed GitLab? Add GITLAB_URL=https://gitlab.example.com to that same file (and GITLAB_MCP_SKIP_TLS_VERIFY=true for self-signed certs). The per-client JSON for every supported client is in Step 2.

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.com token. It runs in OAuth mode: a client that speaks the OAuth flow authorizes in the browser and stores its own token, and anything that cannot open a browser sends a personal access token as Authorization: Bearer instead:

{
  "mcpServers": {
    "gitlab": {
      "type": "http",
      "url": "https://mcp.jmrp.io/gitlab",
      "headers": { "Authorization": "Bearer glpat-xxxxxxxxxxxx" }
    }
  }
}

The server card carries copy-paste config for Claude Code, Cursor and VS Code, including the OAuth client ID those clients need — without it they fall back to dynamic registration and receive a scope this server cannot use. The browser inspector signs in with OAuth and calls the same endpoint read-only, with nothing to install.

It is a personal service run best-effort, with no SLA: your token and every request pass through a machine you do not control, and the instance is fixed to https://gitlab.com. For a self-managed GitLab, or for anything you would rather keep on your own computer, use one of the paths above. The full property table is in HTTP Server Mode — Public Hosted Endpoint.


Step 1: Download the Binary

Prefer the fast paths above? Skip to Step 3. This section is the manual walkthrough.

Download the latest release for your platform from the project Releases page:

Platform Binary
Linux amd64 gitlab-mcp-server-linux-amd64
Linux arm64 gitlab-mcp-server-linux-arm64
Windows amd64 gitlab-mcp-server-windows-amd64.exe
Windows arm64 gitlab-mcp-server-windows-arm64.exe
macOS Intel gitlab-mcp-server-darwin-amd64
macOS Apple Silicon gitlab-mcp-server-darwin-arm64
macOS universal gitlab-mcp-server-darwin-all

On Linux/macOS, make it executable:

chmod +x gitlab-mcp-server-linux-amd64

Every release also ships checksums.txt and a keyless Cosign signature (checksums.txt.sigstore.json); releases after v2.7.5 add one SPDX SBOM per binary and a SLSA build provenance attestation you can check with gh attestation verify <file> -R jmrplens/gitlab-mcp-server (steps in release integrity, and the per-release detail in the Installation guide). The install.sh and install.ps1 scripts verify the SHA-256 against checksums.txt before installing and abort on a mismatch.


Step 2: Configure Your MCP Client

Configuration lives in your MCP client's own file, not in this binary. Each client has its own path and JSON shape; Manual Configuration below has the snippet for yours, and IDE Configuration has the full set.

You need two values:

  1. GitLab URL — your instance base URL, for example https://gitlab.example.com. On GitLab.com you can leave it out.
  2. Personal Access Token — a glpat-... token with the api scope, created under User settings > Access tokens. A read_api token also works for reads: the server detects the scope at startup and serves a read-only tool surface for it, on stdio as in HTTP mode, and gitlab_find_action reports a write action as withheld by the token rather than missing.

If you would rather not paste a token into a config file at all, the HTTP mode supports OAuth against your GitLab instance instead: see OAuth App Setup.

Running the binary by hand

There is no interactive setup to run. Started in a terminal, or double-clicked on Windows, with neither value set, the server prints what it is and what it needs and waits for you to read it before closing. That is a signpost, not a configuration step: the settings still go in your client's JSON.


Step 3: Open Your AI Client

Open your configured AI client (e.g., VS Code with GitHub Copilot). The MCP server starts automatically when the client connects.

You should see the GitLab MCP server listed in your client's MCP server panel. In VS Code, check the MCP Servers section in the Copilot chat sidebar.


Step 4: Make Your First Query

Type a natural language request in the AI chat:

"List my GitLab projects"

In the default dynamic mode, the AI assistant finds the project-list action with gitlab_find_action, executes it with gitlab_execute_action, and returns a formatted list of your projects with names, URLs, and descriptions. In meta-tool mode it calls gitlab_project; in individual mode it calls gitlab_project_list.

Expected Output

The response includes a Markdown table like:

| ID | Name | Path | Visibility | ⭐ |
|----|------|------|------------|---|
| 12 | [my-app](https://gitlab.example.com/user/my-app) | user/my-app | private | 3 |
| 15 | [api-service](https://gitlab.example.com/user/api-service) | user/api-service | internal | 1 |

Plus structured JSON data for the AI to process programmatically.


Step 5: Try More Operations

Here are some things to try next:

Browse a project:

"Show me the branches in project my-app"

Check merge requests:

"List open merge requests in project 42"

Read a file:

"Show me the contents of README.md in project my-app"

Create an issue:

"Create an issue in project my-app titled 'Fix login bug' with label 'bug'"

Pipeline status:

"What's the latest pipeline status for project my-app?"

The server handles all GitLab API calls. You do not need to know project IDs, endpoints, or JSON syntax — the AI figures that out.


Tool Modes

By default, the server registers the dynamic find/execute surface: gitlab_find_action and gitlab_execute_action. The same canonical GitLab action catalog remains reachable, and gitlab_find_action returns exact schemas before execution. Set GITLAB_MCP_TOOL_SURFACE=meta to use 34 meta-tools on Free/CE (40 on Premium, 51 on self-managed Ultimate, 52 on GitLab.com Ultimate with Orbit).

To register the complete individual tool set instead (one tool per GitLab operation; 866 on Free/CE, 1019 on Premium, 1085 on self-managed Ultimate and 1091 on GitLab.com Ultimate with Orbit), set:

GITLAB_MCP_TOOL_SURFACE=individual

To switch away from the default dynamic surface and register the consolidated meta-tool catalog instead, set:

GITLAB_MCP_TOOL_SURFACE=meta

For the smallest startup surface with the default dynamic mode, also set GITLAB_MCP_CAPABILITY_SURFACE=minimal. This keeps the gitlab://tools manifest, and omits optional GitLab data resources, prompts, and workflow guides. Dynamic action find and execute remain available because dynamic discovery returns action schemas inline.

See Dynamic Tools for the default find/execute workflow and Meta-Tools for the explicit meta-tool catalog reference.


Alternative: Agent Plugins (Cursor / Claude Code / VS Code)

The repository ships an Agent Plugins 1.0 manifest (root plugin.json + mcp.json), and keeps the legacy Open Plugins manifest (.plugin/plugin.json) for older hosts, so the server can be installed in a single step on conformant hosts:

/plugin install jmrplens/gitlab-mcp-server

The bundled mcp.json runs the published Docker image ghcr.io/jmrplens/gitlab-mcp-server:latest, so Docker must be installed. It is configured for stdio MCP clients and needs no transport flag: the image reads the transport off stdin, and docker run -i is what puts a pipe there. Keep the -i if you copy the Docker configuration into VS Code or another stdio client; without it the container is handed /dev/null, reads that as nobody speaking to it, starts an HTTP listener, and the client waits forever for a stdio initialize response.

The bundled config forwards these environment variables into the container, but the 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 GITLAB_TOKEN cannot travel inside mcp.json itself. If the server reports an authorization failure, set it the way your host documents, or add it to the env block of the installed plugin's local mcp.json.

Note that Agent Plugins expands only ${PLUGIN_ROOT} and ${PLUGIN_DATA}: any other ${...} reaches the process literally, so a placeholder such as "GITLAB_TOKEN": "${GITLAB_TOKEN}" in a local mcp.json hands the server that exact string rather than the token.

Variable Required Description
GITLAB_URL No GitLab instance URL. Defaults to https://gitlab.com; set for self-managed instances
GITLAB_TOKEN Yes Personal Access Token
GITLAB_MCP_SKIP_TLS_VERIFY No true for self-signed certs (default false)
GITLAB_MCP_TOOL_SURFACE No Canonical tool catalog selector: dynamic, meta, or individual (default dynamic)
GITLAB_MCP_CAPABILITY_SURFACE No Resource and prompt catalog selector: full or minimal (default full)
GITLAB_MCP_META_PARAM_SCHEMA No Meta-tool input schema detail: opaque, compact, or full (default opaque)
GITLAB_MCP_TIER No Licensing tier: free/ce, premium, ultimate; unset detects from license (fallback free)
GITLAB_MCP_READ_ONLY No Disable mutating tools (default false)
GITLAB_MCP_SAFE_MODE No Preview mutating tool inputs (default false)
EMBEDDED_RESOURCES No Append embedded MCP resource links to get-style tool results (default true). Deprecated spelling of GITLAB_MCP_EMBEDDED_RESOURCES, still read with a startup warning
GITLAB_MCP_EXCLUDE_TOOLS No Comma-separated tool names to exclude from registration
GITLAB_MCP_IGNORE_SCOPES No Skip token scope detection and register all tools (default false)
GITLAB_MCP_UPLOAD_MAX_FILE_SIZE No Maximum attachment upload size in bytes (default 2147483648)
GITLAB_MCP_ALLOWED_IMPORT_DIRS No Extra path-list-separated directories allowed for local GitLab import archives
GITLAB_MCP_RATE_LIMIT_RPS No Per-credential rate limit, in requests per second, on every call that reaches GitLab (tools/call, resources/read, resources/subscribe, subscriptions/listen, prompts/get), plus tools/list on a bucket of its own refilled a tenth as fast, charged for spending the processor every tenant shares rather than for reaching GitLab; 0 disables it (default 0)
GITLAB_MCP_RATE_LIMIT_BURST No Token-bucket burst size when GITLAB_MCP_RATE_LIMIT_RPS is greater than 0 (default 40)
GITLAB_MCP_CLIENT_COMPAT No Per-client response compatibility (default auto)
GITLAB_MCP_LOG_LEVEL No debug, info, warn, error (default info)

GITLAB_MCP_TOOL_SURFACE selects the catalog: dynamic is the default two-tool low-token find/execute surface, meta exposes consolidated domain dispatchers, and individual exposes every tool separately. It is the variable the plugin config forwards.

The Agent Plugins spec starts every entry in the referenced MCP config automatically and does not support runtime variants, so the manifest ships with a single Docker stdio entry. To use the native binary instead, locate the installed gitlab-mcp-server plugin directory from your host's plugin UI or installation output, then edit its local mcp.json (commonly under .agents/plugins/gitlab-mcp-server/) and replace command / args with the path to the binary downloaded from GitHub Releases.

For detached HTTP deployments, do not use a stdio client entry. Run the Docker image in HTTP mode and configure the MCP client with type: "http" and a URL such as http://localhost:8080/mcp. See HTTP Server Mode.


Alternative: Manual Configuration

To keep credentials out of client config files, create ~/.gitlab-mcp-server.env (or any file you then name in GITLAB_MCP_ENV_FILE). A .env in the working directory is not read, because that directory is whatever workspace the client opened:

GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx

For self-managed GitLab, add GITLAB_URL=https://gitlab.example.com.

Then add the server to your MCP client config manually.

VS Code / GitHub Copilot

Add to .vscode/mcp.json in your project:

{
  "servers": {
    "gitlab": {
      "type": "stdio",
      "command": "/path/to/gitlab-mcp-server",
      "env": {
        "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "gitlab": {
      "command": "/path/to/gitlab-mcp-server",
      "env": {
        "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

Cursor

Add to .cursor/mcp.json:

{
  "mcpServers": {
    "gitlab": {
      "command": "/path/to/gitlab-mcp-server",
      "env": {
        "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

See Configuration for all supported clients and HTTP mode setup.


HTTP Mode (Team Deployment)

For shared server deployments, run in HTTP mode:

# Use https://gitlab.com for GitLab.com, or replace it with your self-managed URL.
gitlab-mcp-server --http --gitlab-url=https://gitlab.com --http-addr=:8080

Each client provides its own token via HTTP header:

{
  "servers": {
    "gitlab": {
      "type": "http",
      "url": "http://your-server:8080/mcp",
      "headers": {
        "PRIVATE-TOKEN": "glpat-your-token"
      }
    }
  }
}

OAuth Mode (Recommended for Production)

For production deployments, enable server-side token verification with OAuth mode:

gitlab-mcp-server --http \
  --gitlab-url=https://gitlab.com \
  --auth-mode=oauth \
  --public-url=https://mcp.example.com \
  --oauth-cache-ttl=15m

OAuth mode validates every Bearer token against GitLab's /api/v4/user endpoint and serves an RFC 9728 metadata endpoint that allows MCP clients with OAuth 2.1 support to discover the GitLab authorization server automatically.

MCP clients that support OAuth can connect by providing the clientId from the GitLab OAuth Application:

{
  "servers": {
    "gitlab": {
      "type": "http",
      "url": "http://your-server:8080/mcp",
      "oauth": {
        "clientId": "YOUR_GITLAB_APPLICATION_ID",
        "scopes": ["api"]
      }
    }
  }
}

The client discovers the GitLab authorization server via /.well-known/oauth-protected-resource and handles token acquisition through the standard OAuth 2.1 PKCE flow.

Important: Without clientId, clients fall back to Dynamic Client Registration (DCR). GitLab's DCR assigns the mcp scope instead of api, causing most operations to fail. Always configure clientId explicitly.

Prerequisite: A GitLab OAuth Application must be created. See OAuth App Setup for a step-by-step guide and IDE Configuration for per-client examples.

See HTTP Server Mode for the full architecture and deployment details.


Next Steps