|
| 1 | +--- |
| 2 | +title: Authentication |
| 3 | +description: "Choose and configure authentication for GitLab MCP Server — Personal Access Token (PAT) for local use or OAuth for team deployments" |
| 4 | +head: |
| 5 | + - - meta |
| 6 | + - name: keywords |
| 7 | + content: gitlab mcp authentication, personal access token, PAT, oauth, token scopes, gitlab api token |
| 8 | +--- |
| 9 | + |
| 10 | +# Authentication |
| 11 | + |
| 12 | +GitLab MCP Server supports two authentication modes. Choose based on your use case. |
| 13 | + |
| 14 | +## Which mode do I need? |
| 15 | + |
| 16 | +| Use Case | Mode | Why | |
| 17 | +|----------|------|-----| |
| 18 | +| Personal local use (Claude Code, Cursor, etc.) | **PAT** | Simple, one token in config | |
| 19 | +| CI/CD pipelines, automation | **PAT** | No user interaction needed | |
| 20 | +| Shared server for a team | **OAuth** | Per-user identity, audit trail | |
| 21 | +| Docker/cloud deployment | **OAuth** | No shared secrets, token rotation | |
| 22 | +| Claude.ai Custom Connector | **OAuth** | Required by Claude.ai | |
| 23 | + |
| 24 | +## Option A: Personal Access Token (PAT) {#pat} |
| 25 | + |
| 26 | +Best for: individual developers running gitlab-mcp locally. |
| 27 | + |
| 28 | +### Step 1: Open Token Settings in GitLab |
| 29 | + |
| 30 | +Navigate to your GitLab instance: |
| 31 | + |
| 32 | +**GitLab.com:** |
| 33 | +`https://gitlab.com/-/user_settings/personal_access_tokens` |
| 34 | + |
| 35 | +**Self-hosted:** |
| 36 | +`https://your-gitlab.com/-/user_settings/personal_access_tokens` |
| 37 | + |
| 38 | +Or via UI: **Avatar (top-left) → Edit profile → Access tokens** (left sidebar) |
| 39 | + |
| 40 | +### Step 2: Create the Token {#create-token} |
| 41 | + |
| 42 | +| Field | Value | Notes | |
| 43 | +|-------|-------|-------| |
| 44 | +| **Token name** | `gitlab-mcp` | Any descriptive name | |
| 45 | +| **Expiration date** | 90 days recommended | GitLab enforces max 365 days | |
| 46 | +| **Select scopes** | See table below | | |
| 47 | + |
| 48 | +### Step 3: Select Scopes {#scopes} |
| 49 | + |
| 50 | +::: danger Required Scopes |
| 51 | +You MUST select `api` scope for full functionality. Without it, most tools will not work. |
| 52 | +::: |
| 53 | + |
| 54 | +| Scope | Required? | What it enables | |
| 55 | +|-------|-----------|-----------------| |
| 56 | +| `api` | **YES** | All 43 scope-gated tools (projects, MRs, issues, pipelines, etc.) | |
| 57 | +| `read_user` | Recommended | User info display, avatar, email | |
| 58 | +| `read_api` | Alternative | Read-only access (use with `GITLAB_READ_ONLY_MODE=true`) | |
| 59 | +| `read_repository` | Optional | File content access (covered by `api`) | |
| 60 | +| `write_repository` | Optional | File mutations (covered by `api`) | |
| 61 | + |
| 62 | +**Minimum for full functionality:** `api` + `read_user` |
| 63 | + |
| 64 | +**Minimum for read-only:** `read_api` + `read_user` |
| 65 | + |
| 66 | +::: warning Common mistake |
| 67 | +Selecting only `read_user` gives access to just 2 of 43 tools (user search and events only). |
| 68 | +GraphQL API is completely blocked without `api` or `read_api`. |
| 69 | +::: |
| 70 | + |
| 71 | +### Step 4: Copy and Configure |
| 72 | + |
| 73 | +1. Click **"Create personal access token"** |
| 74 | +2. **Copy the token immediately** — it's shown only once! |
| 75 | +3. Token format: `glpat-xxxxxxxxxxxxxxxxxxxx` |
| 76 | + |
| 77 | +Add to your MCP client config: |
| 78 | + |
| 79 | +```json |
| 80 | +{ |
| 81 | + "mcpServers": { |
| 82 | + "gitlab": { |
| 83 | + "command": "npx", |
| 84 | + "args": ["-y", "@structured-world/gitlab-mcp"], |
| 85 | + "env": { |
| 86 | + "GITLAB_TOKEN": "glpat-your-token-here", |
| 87 | + "GITLAB_API_URL": "https://gitlab.com" |
| 88 | + } |
| 89 | + } |
| 90 | + } |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +## Scope Detection at Startup {#scope-detection} |
| 95 | + |
| 96 | +GitLab MCP Server automatically detects your token's scopes at startup using the `/api/v4/personal_access_tokens/self` endpoint. Based on the detected scopes, the server: |
| 97 | + |
| 98 | +1. **Skips GraphQL introspection** when `api` or `read_api` scope is missing (avoids 401 errors) |
| 99 | +2. **Registers only matching tools** — tools that would fail are not shown to the AI agent |
| 100 | +3. **Shows a clear message** explaining what's available and how to fix it |
| 101 | + |
| 102 | +### What you see with limited scopes |
| 103 | + |
| 104 | +With full access (`api` + `read_user`): |
| 105 | +``` |
| 106 | +[INFO] Token "gitlab-mcp" detected (scopes: api, read_user) |
| 107 | +``` |
| 108 | + |
| 109 | +With limited access (`read_user` only): |
| 110 | +``` |
| 111 | +[INFO] Token "gitlab-mcp" has limited scopes - 2 of 43 scope-gated tools available |
| 112 | +[INFO] GraphQL introspection skipped (requires 'api' or 'read_api' scope) |
| 113 | +[INFO] For full functionality, create a token with 'api' scope: |
| 114 | + https://gitlab.com/-/user_settings/personal_access_tokens?name=gitlab-mcp&scopes=api%2Cread_user |
| 115 | +``` |
| 116 | + |
| 117 | +### Token expiry warnings |
| 118 | + |
| 119 | +When your token expires within 7 days: |
| 120 | +``` |
| 121 | +[WARN] Token "gitlab-mcp" expires in 3 day(s) |
| 122 | +``` |
| 123 | + |
| 124 | +## Scope Comparison: What Breaks Without `api` {#scope-comparison} |
| 125 | + |
| 126 | +| Token Scopes | Available Tools | GraphQL | REST Projects | What Works | |
| 127 | +|-------------|----------------|---------|---------------|------------| |
| 128 | +| `api, read_user` | **43/43** | Full | Full | Everything | |
| 129 | +| `read_api, read_user` | **23/43** | Read-only | Read-only | All browse_* tools | |
| 130 | +| `read_user` only | **2/43** | Blocked | Blocked | Only browse_users, browse_events | |
| 131 | +| `read_repository` only | **1/43** | Blocked | Blocked | Only browse_files | |
| 132 | +| No scopes | **0/43** | Blocked | Blocked | Nothing | |
| 133 | + |
| 134 | +## Option B: OAuth (Server/Team Deployment) {#oauth} |
| 135 | + |
| 136 | +Best for: shared servers, Docker deployments, team access. |
| 137 | + |
| 138 | +With OAuth, each user authenticates with their own GitLab identity — no shared tokens. |
| 139 | + |
| 140 | +### Step 1: Create GitLab OAuth Application |
| 141 | + |
| 142 | +Navigate to: **GitLab → User Settings → Applications** |
| 143 | +(or **Admin → Applications** for instance-wide) |
| 144 | + |
| 145 | +| Field | Value | |
| 146 | +|-------|-------| |
| 147 | +| **Name** | `GitLab MCP Server` | |
| 148 | +| **Redirect URI** | `https://your-mcp-server.com/oauth/callback` | |
| 149 | +| **Confidential** | No (PKCE provides security) | |
| 150 | +| **Scopes** | `api` and `read_user` | |
| 151 | + |
| 152 | +Click **Save application** and copy the **Application ID**. |
| 153 | + |
| 154 | +### Step 2: Configure Server Environment |
| 155 | + |
| 156 | +```bash |
| 157 | +# Required |
| 158 | +OAUTH_ENABLED=true |
| 159 | +OAUTH_SESSION_SECRET=$(openssl rand -base64 32) |
| 160 | +GITLAB_OAUTH_CLIENT_ID=your-application-id |
| 161 | +GITLAB_API_URL=https://gitlab.com |
| 162 | + |
| 163 | +# Server |
| 164 | +PORT=3333 |
| 165 | +HOST=0.0.0.0 |
| 166 | +``` |
| 167 | + |
| 168 | +### Step 3: Deploy |
| 169 | + |
| 170 | +**Docker:** |
| 171 | +```bash |
| 172 | +docker run -d --name gitlab-mcp \ |
| 173 | + -e OAUTH_ENABLED=true \ |
| 174 | + -e OAUTH_SESSION_SECRET="$(openssl rand -base64 32)" \ |
| 175 | + -e GITLAB_OAUTH_CLIENT_ID=your-app-id \ |
| 176 | + -e GITLAB_API_URL=https://gitlab.com \ |
| 177 | + -e PORT=3333 \ |
| 178 | + -p 3333:3333 \ |
| 179 | + ghcr.io/structured-world/gitlab-mcp:latest |
| 180 | +``` |
| 181 | + |
| 182 | +**Docker Compose:** See [Docker Compose deployment](/guide/installation/docker) |
| 183 | + |
| 184 | +### Step 4: Add HTTPS |
| 185 | + |
| 186 | +OAuth requires HTTPS. Use a reverse proxy: |
| 187 | +- [TLS/HTTPS Configuration](/advanced/tls) |
| 188 | +- Cloudflare, nginx, Caddy, or Traefik |
| 189 | + |
| 190 | +### Step 5: Connect Clients |
| 191 | + |
| 192 | +Each user connects and authenticates individually: |
| 193 | +1. Add server URL to MCP client config |
| 194 | +2. On first use, receive a device code |
| 195 | +3. Enter code in GitLab to authorize |
| 196 | +4. Start using tools with personal identity |
| 197 | + |
| 198 | +See [OAuth details](/security/oauth) for full flow documentation. |
| 199 | + |
| 200 | +## Troubleshooting {#troubleshooting} |
| 201 | + |
| 202 | +### "GraphQL request failed: 401 Unauthorized" |
| 203 | + |
| 204 | +Your token is missing `api` or `read_api` scope. The server will show which scopes are detected: |
| 205 | +``` |
| 206 | +[INFO] Token "mcp" has limited scopes - 2 of 43 scope-gated tools available |
| 207 | +[INFO] GraphQL introspection skipped (requires 'api' or 'read_api' scope) |
| 208 | +``` |
| 209 | + |
| 210 | +**Fix:** Create a new token with `api` + `read_user` scopes. |
| 211 | + |
| 212 | +### "403 Forbidden" on specific operations |
| 213 | + |
| 214 | +Token has `read_api` but not `api`. Write operations (create, update, delete) need `api` scope. |
| 215 | + |
| 216 | +### Token expired |
| 217 | + |
| 218 | +Tokens have an expiration date. Check in **GitLab → Settings → Access Tokens**. |
| 219 | +The server warns when a token expires within 7 days. |
| 220 | + |
| 221 | +### Scope detection not working |
| 222 | + |
| 223 | +The `/personal_access_tokens/self` endpoint requires GitLab 14.0+. On older versions, the server falls back to attempting operations directly. |
| 224 | + |
| 225 | +For more connection issues, see [Troubleshooting](/troubleshooting/connection). |
0 commit comments