gitlab-mcp supports multiple authentication methods. Token behavior depends on whether remote authorization is enabled.
Static PAT (GITLAB_PERSONAL_ACCESS_TOKEN)
└─> OAuth 2.0 PKCE
└─> External token script
└─> Token file
Per-request auth only (required)
In remote authorization mode, each request must include Authorization: Bearer <token> or
Private-Token: <token>, or Job-Token: <token>. If ENABLE_DYNAMIC_API_URL=true, each request must also include
X-GitLab-API-URL.
Cookie-based auth (GITLAB_AUTH_COOKIE_PATH) is applied independently through a cookie jar and is not part of the token chain.
The simplest method. Create a token at GitLab > Settings > Access Tokens with the api scope.
GITLAB_PERSONAL_ACCESS_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxxThis token is the default request token in stdio and HTTP modes when REMOTE_AUTHORIZATION=false.
When REMOTE_AUTHORIZATION=true, request headers are required and PAT fallback is disabled.
Browser-based OAuth flow for interactive use. The server launches a local callback server and opens the browser for authorization.
-
Register an OAuth application in GitLab (Settings > Applications or admin area):
- Redirect URI:
http://127.0.0.1:8765/callback - Scopes:
api - Confidential: No (for PKCE public clients)
- Note the Application ID
- Redirect URI:
-
Configure environment variables:
GITLAB_USE_OAUTH=true
GITLAB_OAUTH_CLIENT_ID=your-application-id
GITLAB_OAUTH_REDIRECT_URI=http://127.0.0.1:8765/callback
GITLAB_OAUTH_SCOPES=apiIf GITLAB_OAUTH_SCOPES is omitted, gitlab-mcp defaults to api, or read_api when GITLAB_READ_ONLY_MODE=true.
# For confidential applications
GITLAB_OAUTH_CLIENT_SECRET=your-client-secret
# Custom GitLab URL (derived from GITLAB_API_URL if not set)
GITLAB_OAUTH_GITLAB_URL=https://gitlab.example.com
# Token storage location (default: ~/.gitlab-mcp-oauth-token.json)
GITLAB_OAUTH_TOKEN_PATH=~/.gitlab-mcp-oauth-token.json
# Disable auto-opening the browser
GITLAB_OAUTH_AUTO_OPEN_BROWSER=false- On first request, the server checks for a stored token at
GITLAB_OAUTH_TOKEN_PATH - If no valid token exists, it generates a PKCE challenge and opens the browser
- The user authorizes the application in GitLab
- GitLab redirects back to the local callback server with an authorization code
- The server exchanges the code for an access token (with PKCE verifier)
- The token is persisted to disk (chmod 600) for future sessions
- On subsequent requests, the stored token is reused until it expires
- Expired tokens are automatically refreshed using the refresh token
- The callback server listens for up to 3 minutes before timing out
- Token files are stored with
0600permissions - If refresh fails, the server falls back to interactive authorization
Execute a shell command to obtain a token dynamically. Useful for integration with secret managers, vault systems, or custom token providers.
GITLAB_TOKEN_SCRIPT=/path/to/get-token.sh
GITLAB_TOKEN_SCRIPT_TIMEOUT_MS=10000 # 500ms–120s (default: 10s)
GITLAB_TOKEN_CACHE_SECONDS=300 # 0–86400s (default: 5min)The script must output one of:
-
Raw token string (plain text on stdout):
glpat-xxxxxxxxxxxxxxxxxxxx -
JSON object with any of these keys:
{ "access_token": "glpat-xxxxxxxxxxxxxxxxxxxx" }{ "token": "glpat-xxxxxxxxxxxxxxxxxxxx" }{ "private_token": "glpat-xxxxxxxxxxxxxxxxxxxx" }
#!/usr/bin/env bash
set -euo pipefail
# Example: read from environment or secret manager
if [[ -n "${GITLAB_OAUTH_ACCESS_TOKEN:-}" ]]; then
printf '{"access_token":"%s"}\n' "${GITLAB_OAUTH_ACCESS_TOKEN}"
exit 0
fi
echo "Token not available" >&2
exit 1The resolved token is cached for GITLAB_TOKEN_CACHE_SECONDS to avoid repeated script executions.
Read a token from a file on disk. The file should contain a raw token string or JSON (same format as the token script output).
GITLAB_TOKEN_FILE=~/.gitlab-tokenBy default, the server enforces strict file permissions — the token file must be readable only by the owner (chmod 600). If the file has group or other permissions, the server rejects it.
To override this check:
GITLAB_ALLOW_INSECURE_TOKEN_FILE=trueThe token is cached for GITLAB_TOKEN_CACHE_SECONDS (default: 300s).
Use browser cookies from a Netscape-format cookie file. This is useful when working with GitLab instances that use SSO or other browser-based authentication.
GITLAB_AUTH_COOKIE_PATH=~/.gitlab-cookies.txt- The server reads cookies from the file in Netscape cookie format
- A cookie jar is created and attached to all API requests via
fetch-cookie - Before the first API call to each GitLab instance, a warmup request is sent to establish the session
- If the cookie file changes on disk, it is automatically reloaded
The warmup request hits a lightweight endpoint to establish the session:
GITLAB_COOKIE_WARMUP_PATH=/user # defaultStandard Netscape cookie format (tab-separated):
# Netscape HTTP Cookie File
.gitlab.example.com TRUE / TRUE 0 _gitlab_session abc123...
Lines starting with #HttpOnly_ are parsed as HttpOnly cookies.
In HTTP transport mode, this enables strict per-request credentials. This is the recommended approach for shared/multi-user deployments.
REMOTE_AUTHORIZATION=trueREMOTE_AUTHORIZATION=true enforces per-request credentials. If a request does not include a token header, the request is rejected.
The server accepts tokens via:
Authorization: Bearer <token>— Standard bearer tokenPrivate-Token: <token>— GitLab private token headerJob-Token: <token>— GitLab CI job token header
When serving multiple GitLab instances, enable dynamic API URL per request:
REMOTE_AUTHORIZATION=true
ENABLE_DYNAMIC_API_URL=trueClients can then send:
X-GitLab-API-URL: https://other-gitlab.example.com/api/v4
- Client sends a request with auth headers
- The server extracts the token and required API URL (when dynamic API URLs are enabled) from headers
- Auth context is stored in
AsyncLocalStoragefor the duration of the request - All GitLab API calls within that request use the per-session credentials
- Requests missing required headers are rejected before tool execution
If your GitLab instance is behind Cloudflare, enable browser-like headers:
GITLAB_CLOUDFLARE_BYPASS=trueThis adds:
- A Chrome-like
User-Agentheader Accept-Language: en-US,en;q=0.9Cache-Control: no-cachePragma: no-cache
You can also set a custom User-Agent:
GITLAB_USER_AGENT="MyApp/1.0"For self-signed or internal CA certificates:
GITLAB_CA_CERT_PATH=/path/to/ca-bundle.pemHTTP_PROXY=http://proxy.example.com:8080
HTTPS_PROXY=http://proxy.example.com:8080To disable TLS certificate verification, you must explicitly acknowledge the risk:
NODE_TLS_REJECT_UNAUTHORIZED=0
GITLAB_ALLOW_INSECURE_TLS=trueBoth settings are required — setting only NODE_TLS_REJECT_UNAUTHORIZED=0 without the acknowledgment flag will cause a startup error.