Configuration
- One required variable
- Read-only aware
- Safe-mode previews
- Tier detected from the licence
GitLab MCP Server needs almost nothing to start. In stdio mode — the default used by IDE integrations — you set just two things: which GitLab instance to talk to (GITLAB_URL) and a personal access token to talk with (GITLAB_TOKEN). On GitLab.com even the URL is optional, because GITLAB_URL defaults to https://gitlab.com, so a single GITLAB_TOKEN is enough; point GITLAB_URL at your own host for self-managed instances. In HTTP mode the server holds no credentials at all — each client sends its own token (and optionally its own GitLab URL) with every request. Everything else on this page is optional and ships with a safe default.
Stdio mode reads its configuration from environment variables, falling back to ~/.gitlab-mcp-server.env and to any file named in GITLAB_MCP_ENV_FILE; HTTP mode reads CLI flags. This page covers the options most users need; see the repository environment reference and CLI reference for the exhaustive tables.
Variable naming
Section titled “Variable naming”Settings this project defines are read as GITLAB_MCP_<NAME> from 2.8.0.
A stdio MCP server runs in whatever shell its client was started from, next to
every other tool that person uses. Names as generic as LOG_LEVEL, AUTH_MODE
or RATE_LIMIT_RPS may already be owned by something else there, and the
collision is silent: the server reads a value nobody gave it and behaves in a
way nobody configured.
The unprefixed spelling still works and is removed in 3.1.0. When both are set the prefixed one wins, and a warning at startup names the one being ignored.
Some names stay bare on purpose:
| Names | Why they were not renamed |
|---|---|
GITLAB_URL, GITLAB_TOKEN | GitLab’s own convention. Every existing configuration sets them, and they are the two most likely to be written into a client configuration from memory |
GITLAB_MCP_SKIP_TLS_VERIFY, GITLAB_MCP_TIER, GITLAB_MCP_READ_ONLY, GITLAB_MCP_SAFE_MODE, GITLAB_MCP_IGNORE_SCOPES | Already namespaced by GITLAB_. A second prefix would churn every existing configuration and protect against nothing |
OTEL_* | Owned by the OpenTelemetry specification. The exporters read those names themselves and would never see a prefixed spelling |
GITLAB_MCP_YOLO_MODE, AUTOPILOT | Conventions other agent tooling sets. Honoring the name another tool already uses is the entire point of reading them |
MODELEVAL_* | The model evaluation’s own variables, set by make targets in this repository. They configure a test harness the server never links, so they never appear beside another tool’s variables in a user’s shell |
The tables below always give the name to set, so read the name rather than deriving it.
Required variables
Section titled “Required variables”GitLab MCP Server requires exactly one variable to start in stdio mode — the rest are optional and default to safe values:
| Variable | Description | Example |
|---|---|---|
GITLAB_TOKEN | Personal Access Token with api scope | glpat-xxxxxxxxxxxxxxxxxxxx |
Core options
Section titled “Core options”| Variable | Default | Description |
|---|---|---|
GITLAB_URL | https://gitlab.com | GitLab instance base URL. Set this for self-managed instances |
GITLAB_MCP_SKIP_TLS_VERIFY | false | Skip TLS certificate verification for self-signed certs |
GITLAB_MCP_TOOL_SURFACE | dynamic | Canonical tool catalog selector: dynamic, meta, or individual |
GITLAB_MCP_CAPABILITY_SURFACE | full | Resource and prompt catalog selector: full keeps the complete catalog; minimal keeps the gitlab://tools manifest, and disables optional resources, prompts, workflow guides, and resource subscriptions |
GITLAB_MCP_META_PARAM_SCHEMA | opaque | Meta-tool input-schema strategy: opaque (default), compact (8.7x the opaque schema), or full (18.3x). Applies to meta-tool tools/list schemas only; measure the current ratios with go run ./cmd/audit_tokens --compare-schemas |
GITLAB_MCP_TIER | (auto-detect) | GitLab edition selector: free/ce, premium, or ultimate. When set, used verbatim; when unset, detected from GET /license (fallback free). Tier gates Enterprise/Premium tools and prunes per-field schema entries via pruneSchemaFieldsByTier (see internal/tools/action_catalog.go) |
GITLAB_MCP_READ_ONLY | false | Disable all mutating tools (create, update, delete) |
GITLAB_MCP_SAFE_MODE | false | Return structured JSON preview instead of executing mutating tools (dry-run mode) |
GITLAB_MCP_EMBEDDED_RESOURCES | true | Embed the canonical gitlab:// MCP resource URI in the get results that carry one (twenty-two get actions, from projects and groups to snippets and wiki pages); set false for clients that do not tolerate duplicate content blocks |
GITLAB_MCP_EXCLUDE_TOOLS | — | Comma-separated tool names, group names or action IDs (e.g., gitlab_project_delete,gitlab_admin), excluded from the tool surface and from the resources, subscriptions, prompts and argument completions that return the same objects, so the removal holds on every request path |
GITLAB_MCP_IGNORE_SCOPES | false | Skip automatic PAT scope detection — register all tools regardless of token scopes |
GITLAB_MCP_LOG_LEVEL | info | Log verbosity: debug, info, warn, error. The --log-level flag sets the same variable and wins over it |
GITLAB_MCP_PPROF_ADDR | (empty) | Serve Go’s profiling handlers (net/http/pprof) on this loopback address (127.0.0.1:6060), on a listener of their own that starts before the transport; a host that is not loopback is refused at startup, since a heap profile is a copy of the process’s memory. Empty serves nothing. The --pprof-addr flag sets the same variable |
Admin options
Section titled “Admin options”| Variable | Default | Description |
|---|---|---|
GITLAB_MCP_CLIENT_COMPAT | auto | Per-client response compatibility: Codex sessions get fractional annotation priorities rounded to 0/1; off disables. Both transports; the --client-compat flag sets the same variable |
GITLAB_MCP_DESCRIPTION_SUBSTITUTIONS | empty | Rewrite listed descriptions and titles for strict MCP gateway validators: comma-separated old=new pairs applied in order (backslash escapes \, \= \\); malformed values refuse startup. Both transports; the --description-substitutions flag sets the same variable |
GITLAB_MCP_UPLOAD_MAX_FILE_SIZE | 2GB | Size cap for upload and file tools, including raw file reads (streamed and stopped at the limit); supports KB/MB/GB suffixes, 1 TB ceiling. Both transports; the --upload-max-file-size flag sets the same variable |
GITLAB_MCP_YOLO_MODE | false | Skip destructive action confirmations (not recommended). A non-empty value wins over AUTOPILOT; the --yolo-mode flag sets the same variable |
AUTOPILOT | false | Same as GITLAB_MCP_YOLO_MODE — skip destructive confirmations. No flag of its own |
GITLAB_MCP_ALLOWED_IMPORT_DIRS | — | Additional OS path-list-separated directories allowed for local project/group import archives |
GITLAB_MCP_ALLOWED_UPLOAD_DIRS | — | Additional OS path-list-separated directories a tool may read a local file from (every file_path and directory_path input). The working directory (unless it is the filesystem root or the user’s home directory, which are dropped as implicit roots) and the OS temp directory are always allowed, and a path is resolved through symlinks first |
GITLAB_MCP_ALLOWED_DOWNLOAD_DIRS | — | Additional OS path-list-separated directories a tool may write a downloaded file into (output_path). Same syntax and same always-allowed roots |
GITLAB_MCP_ENV_FILE | — | One dotenv file to load besides ~/.gitlab-mcp-server.env. Read from the process environment only, so a file the server loads cannot nominate another. Give an absolute path; a relative one follows the client into every workspace it opens, and the server warns when it sees one |
GITLAB_MCP_STDIO_MAX_LINE_BYTES | 4 MiB | Longest stdio message accepted, in bytes. A longer line is refused and answered, not buffered. It matches the SDK’s own HTTP body default, so both transports refuse the same messages; raise it only for a client that inlines large base64 payloads |
GITLAB_MCP_MAX_LISTEN_STREAMS | 64 | Concurrent subscriptions/listen streams one credential may hold open; 0 removes that ceiling. A further 512 per process is not configurable, since the per-credential figure multiplies by however many tokens a caller holds. Applies to both transports |
GITLAB_MCP_ACTION_TIMEOUT | 65m | Cancel an action still running after this long; 0 disables it (upper bound 24h). Above the longest wait any action offers. Both transports; HTTP mode also has --action-timeout |
GITLAB_MCP_DRAIN_DELAY | 0 | HTTP mode: after SIGTERM, keep the listener open and answer /health with 503 draining for this long before closing it, so a balancer that polls /health removes the instance before the close (upper bound 5m); 0 closes at once. Also --drain-delay |
GITLAB_MCP_RATE_LIMIT_RPS | 0 | Per-credential rate limit, in req/s, on every call that reaches GitLab: tools/call, resources/read, resources/subscribe, subscriptions/listen, prompts/get (0 disables it), plus tools/list on a bucket of its own refilled a tenth as fast and holding the same burst, charged because it spends the processor every tenant shares rather than because it reaches GitLab. Both transports: the default is 0 in stdio and 10 in HTTP mode, where --rate-limit-rps overrides it |
GITLAB_MCP_RATE_LIMIT_BURST | 40 | Token-bucket burst size when GITLAB_MCP_RATE_LIMIT_RPS > 0 |
Example dotenv file
Section titled “Example dotenv file”Write it to ~/.gitlab-mcp-server.env, or to any path you then name in GITLAB_MCP_ENV_FILE. A .env in the working directory is not loaded.
# RequiredGITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
# OptionalGITLAB_MCP_SKIP_TLS_VERIFY=falseGITLAB_MCP_TOOL_SURFACE=dynamicGITLAB_MCP_TIER=freeGITLAB_MCP_READ_ONLY=falseGITLAB_MCP_SAFE_MODE=falseGITLAB_MCP_EXCLUDE_TOOLS=GITLAB_MCP_IGNORE_SCOPES=falseGITLAB_MCP_LOG_LEVEL=infoFor self-managed GitLab, add GITLAB_URL=https://gitlab.example.com.
Client configuration
Section titled “Client configuration”Create .vscode/mcp.json in your workspace:
{ "servers": { "gitlab": { "type": "stdio", "command": "/path/to/gitlab-mcp-server", "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}Secure token configuration using VS Code input variables:
{ "inputs": [ { "id": "gitlab-token", "type": "promptString", "description": "GitLab Personal Access Token", "password": true } ], "servers": { "gitlab": { "type": "stdio", "command": "/path/to/gitlab-mcp-server", "env": { "GITLAB_TOKEN": "${input:gitlab-token}" } } }}Edit claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{ "mcpServers": { "gitlab": { "command": "/path/to/gitlab-mcp-server", "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}Create .cursor/mcp.json in your project:
{ "mcpServers": { "gitlab": { "command": "/path/to/gitlab-mcp-server", "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}Write the token where the server reads it, then register the command:
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 that same file only for self-managed instances. The registration command names no token, so nothing puts it in argv or in Claude Code’s own configuration file.
Add to ~/.continue/config.yaml (or your workspace .continue/config.yaml):
mcpServers: - name: gitlab command: /path/to/gitlab-mcp-server env: GITLAB_TOKEN: glpat-xxxxxxxxxxxxxxxxxxxxReload the Continue window after editing the config. See the Continue MCP docs for HTTP-mode and OAuth alternatives.
Edit ~/.codeium/windsurf/mcp_config.json (Cascade → Plugins → Configure):
{ "mcpServers": { "gitlab": { "command": "/path/to/gitlab-mcp-server", "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}Restart Windsurf or click Refresh in the Plugins panel to pick up changes.
JetBrains IDEs (IntelliJ IDEA, GoLand, PyCharm, etc.) with the AI Assistant plugin support MCP servers via Settings → Tools → AI Assistant → Model Context Protocol.
Add a stdio entry pointing at the binary:
- Name:
gitlab - Command:
/path/to/gitlab-mcp-server - Environment variables:
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
Add GITLAB_URL=https://gitlab.example.com for self-managed GitLab.
Alternatively, create .idea/mcp.json in the project root with the same JSON shape used by VS Code / Cursor. Restart the IDE after editing.
HTTP mode flags
Section titled “HTTP mode flags”In HTTP mode (--http), settings resolve in three layers, highest first: a CLI flag passed explicitly, then the matching environment variable, then the built-in default. A few flags — the listener ones below among them — have no environment counterpart:
| Flag | Default | Description |
|---|---|---|
--http | false | Enable HTTP transport mode |
--http-addr | :8080 | Listen address. host:port binds TCP; a value containing a path separator (e.g. /run/gitlab-mcp.sock) binds a unix socket instead. No environment counterpart |
--http-socket-mode | 0660 | Octal permission mode for a unix socket named by --http-addr — owner and group may connect, nobody else. No environment counterpart |
--tls-cert / --tls-key | (empty) | PEM certificate and key. Serves HTTPS on the listener itself (TLS 1.2 floor, 1.3 negotiated). Both or neither, loaded at startup. No environment counterpart |
--gitlab-url | — | GitLab instance URL. Required unless --allow-any-gitlab-url is passed; repeat it (or comma-separate) to publish several instances, among which the GITLAB-URL header is then required |
--allow-any-gitlab-url | false | Start with no instance published and let GITLAB-URL name any host. Single-user local deployments only; it warns at startup |
--skip-tls-verify | false | Skip TLS verification |
--tool-surface | dynamic | Canonical tool catalog selector: dynamic, meta, or individual |
--meta-param-schema | opaque | Meta-tool params schema mode: opaque, compact, or full; applies to meta-tool schemas only |
--capability-surface | full | Resource and prompt catalog selector: full or minimal; minimal keeps the gitlab://tools manifest, and omits optional resources, workflow guides, and prompts |
--tier | (auto-detect) | Force GitLab edition: free/ce, premium, or ultimate; omit to auto-detect CE/EE per token+URL entry. Replaces the deprecated GITLAB_ENTERPRISE toggle; there is no --enterprise flag |
--read-only | false | Read-only mode |
--safe-mode | false | Intercept mutating tools and return a JSON preview instead of executing them |
--embedded-resources | true | Embed the canonical MCP resource URI in the get results that carry one (twenty-two get actions) |
--exclude-tools | — | Comma-separated tool names, group names or canonical action IDs, excluded from the tool surface and from the resources, subscriptions, prompts and argument completions that return the same objects |
--ignore-scopes | false | Skip PAT scope detection |
--max-http-clients | 100 | Maximum unique (token, GitLab URL) server entries kept in the pool; bounds pooled entries, not sessions or concurrent requests |
--session-timeout | 30m | Idle MCP session timeout; applies to --stateless=false only — under the default stateless transport each POST’s session ends with its response |
--http-idle-timeout | 0 (disabled) | HTTP server idle connection timeout. Default 0 disables idle closure, so --session-timeout is the effective lifetime; set a positive duration to recycle idle connections sooner |
--stateless | true | Sessionless streamable HTTP (protocol 2026-07-28): no Mcp-Session-Id tracking, every POST is self-contained, GET and DELETE answer 405. --stateless=false restores legacy stateful sessions. No environment counterpart |
--json-response | false | Return application/json response bodies instead of text/event-stream (SSE). No environment counterpart |
--max-request-body-bytes | 0 | Maximum streamable HTTP request body size in bytes; 0 uses the SDK default (4 MiB). Oversized bodies are rejected with 413. No environment counterpart |
--auth-mode | legacy | Authentication mode: legacy or oauth |
--oauth-cache-ttl | 15m | OAuth token identity cache TTL (1m–2h) |
--oauth-client-uid | (empty) | Comma-separated GitLab OAuth application uids whose tokens are admitted. Empty admits any credential the instance accepts; setting it also refuses personal access tokens, which belong to no application |
--public-url | (empty) | Externally reachable origin (scheme://host[:port][/path]). Required with --auth-mode=oauth; its origin is also trusted for cross-origin browser requests. Env: GITLAB_MCP_PUBLIC_URL |
--resource-documentation | (empty) | https URL published as RFC 9728 resource_documentation; point it at a page describing your own OAuth application (its client ID and registered redirect URIs). Empty publishes this project’s HTTP server mode page |
--resource-policy-uri | (empty) | https URL published as RFC 9728 resource_policy_uri; your own page on what this deployment does with the data reached through it. Empty omits the field |
--resource-tos-uri | (empty) | https URL published as RFC 9728 resource_tos_uri; your own terms of service. Empty omits the field |
--trusted-origins | (empty) | Comma-separated origins allowed to make cross-origin browser requests; * accepts any origin. Empty adds none, though a configured --public-url origin is trusted regardless. Env: GITLAB_MCP_TRUSTED_ORIGINS |
--action-timeout | 65m | Cancel an action still running after this long; 0 disables it (upper bound: 24h). Falls back to GITLAB_MCP_ACTION_TIMEOUT |
--drain-delay | 0 | After SIGTERM, keep the listener open and answer /health with 503 draining for this long before closing it (upper bound: 5m); 0 closes at once. Falls back to GITLAB_MCP_DRAIN_DELAY |
--pool-idle-timeout | 1h | Reclaim a pooled per-token-and-URL credential entry after this long unused; 0 keeps entries until the pool size bound evicts them (upper bound: 24h). An entry with a live subscription is never idle by this measure |
--revalidate-interval | 15m | Token re-validation interval (upper bound: 24h). 0 stops the periodic check, but an entry whose credential is older than 1h is still rebuilt, which re-runs the probe |
--rate-limit-rps | 10 | Per-credential rate limit, in req/s, on every call that reaches GitLab: tools/call, resources/read, resources/subscribe, subscriptions/listen, prompts/get (0 disables it), plus tools/list on a bucket of its own refilled a tenth as fast and holding the same burst, charged for spending the shared processor rather than for reaching GitLab; on by default because an HTTP deployment is shared |
--rate-limit-burst | 40 | Token-bucket burst size when --rate-limit-rps > 0 |
--trusted-proxies | — | Addresses or CIDR ranges of the reverse proxies whose --trusted-proxy-header is believed (e.g. 127.0.0.1,10.0.0.0/8); from any other peer the header is ignored. Required with --trusted-proxy-header |
--trusted-proxy-header | — | HTTP header with real client IP for rate limiting behind proxies (e.g. CF-Connecting-IP, X-Forwarded-For); believed only from --trusted-proxies |
General flags (both stdio and HTTP modes):
| Flag | Default | Description |
|---|---|---|
--transport | (empty) | stdio, http or auto. Empty defers to --http; auto serves HTTP only when stdin is the null device (a container started without -i) and stdio for the pipe an MCP client connects |
--env-file | (empty) | Dotenv file to load besides ~/.gitlab-mcp-server.env; the same setting as GITLAB_MCP_ENV_FILE, and wins over it |
--log-level | (empty) | debug, info (the effective default), warn or error. Sets GITLAB_MCP_LOG_LEVEL |
--client-compat | (empty) | auto (the effective default) or off. Sets GITLAB_MCP_CLIENT_COMPAT |
--upload-max-file-size | (empty) | Size cap for upload and file-read tools, KB/MB/GB suffixes accepted (2GB when unset). Sets GITLAB_MCP_UPLOAD_MAX_FILE_SIZE |
--yolo-mode | (empty) | true skips the confirmation prompt on destructive actions. Sets GITLAB_MCP_YOLO_MODE |
--description-substitutions | (empty) | Comma-separated old=new pairs applied to every listed description and title. Sets GITLAB_MCP_DESCRIPTION_SUBSTITUTIONS; a malformed value refuses startup |
--pprof-addr | (empty) | Serve Go’s profiling handlers on this loopback address (127.0.0.1:6060), on a listener of their own; any other host is refused at startup. Sets GITLAB_MCP_PPROF_ADDR |
--tool-search | (empty) | Search the action catalog by name, alias, tag or description, then exit; prints each canonical action ID beside the tool the configured surface names it. Reads --tool-surface and --tier, and otherwise GITLAB_MCP_TOOL_SURFACE and GITLAB_MCP_TIER |
--version | false | Print the version and commit, then exit |
--shutdown | false | Terminate all running instances and exit |
--probe | false | Ask the running instance’s /health and exit 0 when it answers; the image’s HEALTHCHECK. Reads the listener off the instance’s own flags, or probes the URL, unix:<path> or host:port given after the flag |
The six flags that set a variable (--log-level through --pprof-addr) exist so one command line can configure the whole server; an explicitly passed flag beats an exported variable. GITLAB_TOKEN deliberately has no flag, since a token on a command line is visible to every user on the machine. The telemetry flags (--telemetry, --telemetry-identity, --telemetry-identity-rotation, --telemetry-tool-name) and the full --help text are in the repository CLI reference.
Example:
# Single GitLab.com instance (fixed URL for all clients; replace for self-managed GitLab)./gitlab-mcp-server \ --http \ --http-addr=0.0.0.0:8080 \ --gitlab-url=https://gitlab.com \ --max-http-clients=200 \ --session-timeout=1h
# Several instances (the GITLAB-URL header is required, and must name one of them)./gitlab-mcp-server \ --http \ --http-addr=0.0.0.0:8080 \ --gitlab-url=https://gitlab.com,https://gitlab.example.comConfiguration load order
Section titled “Configuration load order”The server loads configuration in the following order (later sources override earlier ones):
~/.gitlab-mcp-server.env— User-level defaults (home directory)- The file
GITLAB_MCP_ENV_FILEnames — One extra dotenv file, if the environment names one - System environment variables — What the MCP client passed, or the shell exported
- CLI flags — Command-line arguments (highest priority)
Self-signed certificates
Section titled “Self-signed certificates”For GitLab instances with self-signed TLS certificates:
GITLAB_MCP_SKIP_TLS_VERIFY=trueRead-only mode
Section titled “Read-only mode”Enable GITLAB_MCP_READ_ONLY=true to restrict the server to read-only operations. All tools that create, update, or delete resources are disabled. This is useful for:
- Audit and compliance environments
- Shared servers where users should only query data
- Tokens with
read_apiscope
- What it exposes
every read operation, on every surface: list, get and search keep working exactly as before.
- Requires
GITLAB_MCP_READ_ONLY=truein stdio mode,--read-onlyin HTTP mode.- What it does not do
anything that writes: create, update and delete actions are removed from the catalog per action, so on the dynamic and meta surfaces they stop being reachable rather than merely erroring. When safe mode is also set, read-only wins — mutations disappear instead of previewing.
Safe mode
Section titled “Safe mode”Enable GITLAB_MCP_SAFE_MODE=true to intercept mutating tools and return a structured JSON preview of what would be executed, without actually performing the operation. Read-only tools work normally. This is useful for:
- Reviewing operations before execution (dry-run)
- Training environments where you want to see tool behavior
- Debugging tool parameters without side effects
- What it exposes
every operation’s shape: mutating actions stay callable and return a structured JSON preview naming the canonical action (for example
issue.create) and the parameters it would send; reads execute normally.- Requires
GITLAB_MCP_SAFE_MODE=truein stdio mode,--safe-modein HTTP mode.- What it does not do
actual writes: nothing mutating reaches GitLab. The preview is not a validation either — GitLab-side errors (permissions, conflicts) only surface on a real execution.
Both safe mode and read-only act per action, not per tool. On the dynamic and meta surfaces a single tool serves many actions — gitlab_execute_action routes everything, and gitlab_issue covers list and create alike — so the policy is applied to the underlying action catalog. Reads keep working on every surface, and safe-mode previews name the canonical action (for example issue.create) rather than the dispatcher tool.
Frequently asked questions
What is the minimum configuration?
In stdio mode, a single GITLAB_TOKEN with the api scope is enough to start — every other variable is optional and defaults to a safe value. GITLAB_URL defaults to https://gitlab.com, so you set it only when connecting to a self-managed instance. For a read-only setup, use a read_api token: the server serves it a read-only surface on its own, and GITLAB_MCP_READ_ONLY=true does the same for an api token. In HTTP mode, no token is configured on the server at all; each client sends its own token with every request.
stdio vs HTTP — which mode do I use?
Use stdio mode (the default) for local, single-user setups such as IDE integrations like VS Code, Cursor, and Claude Desktop; it is configured through environment variables, plus ~/.gitlab-mcp-server.env or a file named in GITLAB_MCP_ENV_FILE for what the environment does not carry. Use HTTP mode (--http) for shared or remote deployments such as Docker or Kubernetes, where configuration uses CLI flags and each client authenticates with its own GitLab token per request.
How do I point at a self-managed GitLab instance?
Set GITLAB_URL to your instance base URL, for example GITLAB_URL=https://gitlab.example.com (in HTTP mode, use the --gitlab-url flag instead). If the instance uses a self-signed or internal CA certificate, also set GITLAB_MCP_SKIP_TLS_VERIFY=true (or --skip-tls-verify in HTTP mode), but only on a trusted network — it disables certificate verification for all connections to GitLab.
How do I pick a tool surface (dynamic, meta, or individual)?
Set the GITLAB_MCP_TOOL_SURFACE variable (or the --tool-surface flag in HTTP mode). dynamic is the default and lowest-token catalog: it exposes gitlab_find_action and gitlab_execute_action while keeping every GitLab action reachable through the canonical action catalog. Choose meta when a client prefers consolidated domain dispatchers with an action parameter, and individual to register one MCP tool per GitLab operation.