MCP GitLab
Forwards sandboxed MCP requests to a GitLab instance's official MCP server at /api/v4/mcp, adding a fine-grained personal access token on the server side so agents never hold a GitLab token. Exposes the GitLab version's own tools (e.g. project reads), with toolset, tool and name-prefix selection via GitLab's MCP headers, and returns GitLab's permission decisions for each call.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
MCP GitLab
MCP server for sandboxed agents that forwards every request to the official MCP server of a GitLab instance and adds the GitLab token on the server side.
GitLab ships its own MCP server at <instance>/api/v4/mcp, in the Free tier and in the Community Edition. An agent in a sandbox should use it without ever holding a GitLab token. mwaeckerlin/mcp-gitlab stands between the two: the sandbox talks to it exactly as it talks to mwaeckerlin/mcp-github and mwaeckerlin/mcp-gitea, and the server passes each request to GitLab with the token it reads from a Docker secret. The tools are the ones GitLab offers, so they follow the GitLab version without a release of this server.
The numbered feature list is in FEATURES.md, the tests in TESTS.md, the architecture in ARCHITECTURE.md.
Security Model
The sandboxed client calls this server, at
MCP_GITLAB_URL.The server, outside the sandbox, reads the GitLab token from the file
GITLAB_TOKEN_FILEnames and adds it asAuthorization: Bearerto the request it passes to<GITLAB_URL>/api/v4/mcp.GitLab decides with that token what the call may do.
No GitLab token in the sandbox, in a tool argument or in the environment of the server.
Only the one address
<GITLAB_URL>/api/v4/mcpis asked; the path and the query of a request never reach GitLab.Only the headers of the MCP transport and the tool selection of GitLab pass; the
Authorizationheader of the sandbox, which carriesMCP_AUTH_TOKEN, cookies and every other header stay on the server.The OAuth challenge of GitLab stays on the server, so the agent does not start a login of its own; a redirect of GitLab is not followed with the token.
No token appears in an error message of the server.
Related MCP server: GitLab MCP
Configuration
Server
Every variable is optional; an empty value counts as unset.
Variable | Default | Effect |
| empty: nothing is forwarded, MCP requests are answered 503 | address of the GitLab instance, such as |
| empty: no token, GitLab answers 401 | file with the fine-grained personal access token of GitLab, such as the Docker secret |
| empty | file with the shared token that the sandbox presents, such as the Docker secret |
| empty: every request is accepted | the shared token itself, as in |
|
| seconds the server waits for the answer of GitLab before it answers 502 |
|
| address the server listens on |
|
| port the server listens on; 1 to 65535 |
A GitLab with a certificate of a private authority needs that authority in NODE_EXTRA_CA_CERTS, the file variable of Node.js.
The GitLab token is read from a file only. A token in the environment shows in docker inspect and in the environment of every process of the container; a Docker secret keeps it in a file under /run/secrets.
Security Trade-offs
Without
MCP_AUTH_TOKENthe server accepts every request and acts with the token of the server: every client that reaches port 4000 can do in GitLab what the owner of the token may do. Publish no port where the sandbox reaches the server over a Docker network, setBIND_ADDRESS=127.0.0.1for the sample stack, or setMCP_AUTH_TOKEN_FILE.An
http://address inGITLAB_URLsends the token unencrypted and belongs on a closed network only, like the test stack.GITLAB_TIMEOUTbounds the wait for the first answer of GitLab; an event stream that has begun has no bound, because GitLab sends it at its own pace.The
tokenquery parameter can land in the log of a proxy in front of the server; theAuthorization: Bearerheader does not.
Sandbox
Variable | Effect |
| where the MCP client of the sandbox reaches the server, such as |
| the shared token, sent as |
GitLab Token
GitLab accepts two kinds of token at its MCP server: an OAuth access token with the scope mcp, and a fine-grained personal access token. For a server without a person in front of it, the fine-grained token is the one that fits:
Sign in to GitLab as the user the agent acts as; the agent can do exactly what this user may do.
Avatar › Edit profile › Access › Personal access tokens › Generate token › Fine-grained token.
Name and expiry date; under Add resource permissions the tab User, the resource MCP tool, the permission Execute.
Store the token in a file, hand it to the server as a Docker secret, and point
GITLAB_TOKEN_FILEat it.
A legacy personal access token is refused with 403, also with the scope api: GitLab CE 19.5.3 answers {"message":"403 Forbidden"}, its documentation names the error insufficient_scope and the same refusal for project and group access tokens. The administrator of a self-managed instance allows the MCP server with the instance setting «Allow access to the MCP server», which is on in a fresh GitLab CE 19.5.3; while it is off, GitLab answers 403 MCP server disabled for this instance.
Ports
The server listens on port 4000. docker-compose.yml publishes it on every address of the host, IPv4 and IPv6, as long as BIND_ADDRESS is unset or empty. BIND_ADDRESS limits it to one address of the host: 127.0.0.1 serves the local machine alone, an IPv6 address stands in brackets, such as [::1]. 0.0.0.0 publishes on every IPv4 address and on no IPv6 address. Where the sandbox reaches the server over a Docker network, publish no port at all.
Sample Stack
docker-compose.yml reads the token from the file gitlab_token beside it, or from the file GITLAB_TOKEN_SECRET names, and needs GITLAB_URL:
GITLAB_URL=https://gitlab.example.com npm startHealth
GET /healthzanswers 200 while the process runs, withoutMCP_AUTH_TOKEN.With
GITLAB_URLand a token:{ "ok": true, "status": "ready", "gitlabUrlConfigured": true, "gitlabTokenConfigured": true }.Otherwise
statusisdegraded, andmessagenames the missing variable.The image carries a
HEALTHCHECKthat asks/healthzand prints its answer; it runs/usr/bin/nodedirectly, because the image has no shell. The container is healthy in both states, so a compose file or a Swarm stack needs no healthcheck of its own.
Usage through MCP
The sandbox connects with the streamable HTTP transport of MCP to MCP_GITLAB_URL. GitLab answers every POST with JSON and offers no event stream: GET returns its 405. tools/list returns the tools of the GitLab version, with their argument schemas. Three request headers of GitLab choose the tools: X-Gitlab-Enabled-Mcp-Server-Toolsets names toolsets, such as ci; X-Gitlab-Enabled-Mcp-Server-Tools names single tools; X-Gitlab-Mcp-Server-Tool-Name-Prefix puts a prefix before every tool name, such as gitlab_.
Example call, read a project:
{ "name": "get_project", "arguments": { "project_id": "mwaeckerlin/mcp-gitlab" } }SKILL.md carries the instructions for the agent; the image ships it at /app/skills/mcp-gitlab/SKILL.md.
Troubleshooting
Answer | Cause | Action |
401 | the sandbox sent no or a wrong | send |
401 of GitLab | no token on the server, or GitLab does not know it | set |
403 | legacy, project or group token | use a fine-grained token with «MCP tool: Execute» |
403 | the MCP server is switched off in the instance settings | the administrator allows «Allow access to the MCP server» |
502 | GitLab did not answer within | check |
503 |
| set |
start refused: | the file does not exist, is a directory, or the server's user may not read it | mount the secret at that path, or correct |
start refused: | the secret holds no token | recreate the secret with the token |
start refused: | the token has a line break or another control character inside, often two tokens or a text pasted into the secret; no such token can stand in an HTTP header | recreate the secret, or set the variable, with the token alone |
start refused: | both ways of giving the shared token are configured | remove one of them |
Development
npm install
npm run build:ts
npm run build
npm testnpm run dev starts the server from the sources. npm test runs the groups of TESTS.md in one regression run: the feature register check, the compose contract, the type check and the unit tests, the dependency audit, the image contract and the end-to-end suite; a failed group does not stop the others, an interrupted run resumes where it was cut off, and npm test -- --from <ID> --to <ID> runs a range. The end-to-end suite (tests/e2e.sh, test/docker-compose.yml) starts a real GitLab CE from gitlab/gitlab-ce, in which test/gitlab/setup.rb creates a user, a private project, a fine-grained token and a legacy token; four servers with different tokens and a test client run beside it on internal networks, and the stack is removed with its volumes afterwards. npm run test:e2e:up starts and sets up that GitLab once and leaves it standing, so that every following npm run test:e2e and npm test builds and starts only the servers and the test client against it; npm run test:e2e:down removes it. GitLab CE 19.5.3 needed about four minutes until its /-/readiness answered and held 2.8GiB of memory; the health check of its image reports healthy before Rails can start, so the stack waits for /-/readiness, and the root password of the stack contains no common words, because GitLab refuses such a password and its database setup then fails. The image is built, tested and published for linux/amd64 and linux/arm64 by the reusable workflow of mwaeckerlin/scratch; npm run deploy pushes it.
This server cannot be deployed
Maintenance
Related MCP Connectors
GitLab MCP — wraps the GitLab REST API v4 (BYO API key)
Toolstile is a managed MCP gateway that connects remote MCP servers behind one endpoint, with per-agent permissions, shared accounts and activity logs. Connect at https://mcp.toolstile.com/mcp over Streamable HTTP with OAuth; sign in at https://toolstile.com, select a workspace and connect your upstream servers. Available tools, resources and prompts depend on that workspace and the agent's granted access.
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
GitLab Public MCP — wraps the GitLab REST API v4 (public endpoints, no auth)
Related MCP Servers
- AlicenseCqualityAmaintenanceMCP server for interacting with GitLab API, supporting dynamic tool selection and enterprise-grade security.21010MIT
- FlicenseNot gradedqualityDmaintenanceExposes the GitLab REST API to MCP clients for managing projects, issues, merge requests, repositories, and CI/CD pipelines. It is multi-tenant, allowing each user to authenticate with their own token and instance URL.-
- FlicenseBqualityDmaintenanceProvides tools to interact with a self-hosted GitLab instance, enabling project, issue, note, search, todo, and wiki page management through MCP.161-
- AlicenseCqualityAmaintenanceEnables secure interaction with GitLab instances through MCP, supporting projects, merge requests, issues, pipelines, and search.632AGPL 3.0