Docker
La imagen se publica como ghcr.io/jmrplens/gitlab-mcp-server y se replica como docker.io/jmrplens/gitlab-mcp-server en Docker Hub, con una etiqueta <versión> y latest en ambos registros, para linux/amd64 y linux/arm64. Cada release la construye con atestaciones de procedencia y SBOM y la firma por digest con Cosign. Las dos variantes de plataforma se arrancan y se les pide su versión antes de publicar nada, así que ninguna puede salir incapaz de arrancar, que es lo que le pasó a la imagen linux/arm64 de v2.7.5, cuyo binario pedía un cargador dinámico que el runtime Alpine no trae. Dentro: una base Alpine con certificados CA y datos de zona horaria, el binario en /usr/local/bin/gitlab-mcp-server, un usuario no-root appuser (UID 10001), el puerto 8080 expuesto y un HEALTHCHECK que ejecuta gitlab-mcp-server --probe, que lee el listener de los propios flags del servidor en marcha y pregunta por su /health, así que sigue a un puerto cambiado, a un socket unix o a TLS en el listener (la imagen 2.7.5 lanza wget contra http://localhost:8080/health en su lugar, y da por no sano cualquier otro listener).
El binario de la imagen se compila sin -trimpath, a diferencia de los binarios del release, así que su información de compilación registra el release con el que se compiló y el SBOM de la imagen lista el servidor con esa versión, con una URL de paquete versionada que un escáner de vulnerabilidades puede casar. Las imágenes hasta la 3.1.0 incluida lo listan sin versión. A partir del primer release posterior a 3.1.0, la imagen lleva además LICENSE y THIRD_PARTY_NOTICES en /usr/share/licenses/gitlab-mcp-server/: los textos de licencia, aviso y patente de todos los módulos que enlaza ese binario, generados durante la compilación de la imagen a partir de los módulos del propio binario y de los paquetes que enlaza.
Stdio: la imagen como servidor MCP local
Sección titulada «Stdio: la imagen como servidor MCP local»docker run -i --rm -e GITLAB_TOKEN ghcr.io/jmrplens/gitlab-mcp-server:latest-e GITLAB_TOKEN sin valor reenvía la variable desde el entorno que el cliente le da a docker, de modo que el token vive en el bloque env del cliente y no en la línea de comandos. Docker descarga la imagen en la primera ejecución. La entrada de cliente que lanza este comando está en Configura tu cliente más abajo; con Claude Code el registro es esa misma línea de comandos, y tampoco lleva token:
# Pide el token sin mostrarlo, así que queda fuera del historial de la shellprintf 'GitLab token: ' && read -rs GITLAB_TOKEN && export GITLAB_TOKEN && echoclaude mcp add gitlab --transport stdio \ -- docker run -i --rm -e GITLAB_TOKEN ghcr.io/jmrplens/gitlab-mcp-server:latestClaude Code le pasa su propio entorno a docker, que es de donde -e GITLAB_TOKEN toma el valor, así que expórtalo en la shell desde la que lanzas el cliente (tu perfil de shell lo hace duradero) o añádelo después al bloque env de la entrada. Un contenedor tiene su propio sistema de archivos y nunca lee ~/.gitlab-mcp-server.env, que es como el resto de canales aportan el token; el reenvío es el equivalente del contenedor.
Los botones de un clic para VS Code, Cursor, LM Studio y Kiro del Inicio rápido registran exactamente esta entrada, y el manifiesto de Plugins de agente también la ejecuta.
Variables de entorno
Sección titulada «Variables de entorno»En modo stdio cada ajuste es una variable de entorno, y cada una que uses necesita su propio -e NOMBRE para que Docker la copie dentro del contenedor. La lista que reenvía la configuración del plugin incluido es una buena plantilla: GITLAB_URL, GITLAB_TOKEN, GITLAB_MCP_SKIP_TLS_VERIFY, GITLAB_MCP_TOOL_SURFACE, GITLAB_MCP_CAPABILITY_SURFACE, GITLAB_MCP_META_PARAM_SCHEMA, GITLAB_MCP_TIER, GITLAB_MCP_READ_ONLY, GITLAB_MCP_SAFE_MODE, GITLAB_MCP_EMBEDDED_RESOURCES, GITLAB_MCP_EXCLUDE_TOOLS, GITLAB_MCP_IGNORE_SCOPES, GITLAB_MCP_UPLOAD_MAX_FILE_SIZE, GITLAB_MCP_ALLOWED_IMPORT_DIRS, GITLAB_MCP_RATE_LIMIT_RPS, GITLAB_MCP_RATE_LIMIT_BURST, GITLAB_MCP_CLIENT_COMPAT y GITLAB_MCP_LOG_LEVEL. Qué hace cada una está en la página de Configuración. La entrada de la imagen en el MCP Registry (server.json) declara diecinueve variables, las que un cliente del registro ofrece rellenar: esta lista sin GITLAB_MCP_CLIENT_COMPAT, más GITLAB_MCP_ALLOWED_UPLOAD_DIRS y GITLAB_MCP_ALLOWED_DOWNLOAD_DIRS.
HTTP: la imagen como servicio
Sección titulada «HTTP: la imagen como servicio»Arrancado sin -i, el contenedor no tiene una entrada estándar por la que hablar y escucha en el puerto 8080, pero no arranca hasta que le digas a qué GitLab sirve. El comando por defecto no lleva ninguna instancia, así que un docker run -p 8080:8080 ghcr.io/jmrplens/gitlab-mcp-server:latest a secas termina al momento con --gitlab-url is required in HTTP mode. La forma más sencilla conserva el comando por defecto y nombra la instancia en una variable, que rellena la lista sin reemplazar el comando:
docker run --rm -p 8080:8080 -e GITLAB_URL=https://gitlab.com ghcr.io/jmrplens/gitlab-mcp-server:latestUn GITLAB_URL separado por comas publica varias instancias, entre las que elige después la cabecera GITLAB-URL. Para nombrar la instancia en la línea de comandos, pasa los flags de forma explícita; cualquier argumento tras el nombre de la imagen reemplaza el comando por defecto, así que --http y --http-addr vuelven con ellos en lugar de deducirse:
docker run --rm -p 8080:8080 ghcr.io/jmrplens/gitlab-mcp-server:latest \ --http --http-addr=0.0.0.0:8080 --gitlab-url=https://gitlab.comUn despliegue que no nombra ninguna instancia haría peticiones al host que quien llama ponga en la cabecera GITLAB-URL, con el token que esa misma persona enviara, así que se rechaza al arrancar. --allow-any-gitlab-url lo acepta para un despliegue local de un único usuario y avisa, pero solo si --http-addr liga loopback o un socket unix, así que dentro de un contenedor que liga 0.0.0.0 no sirve: publica las instancias. Cada cliente envía además su propio token de GitLab en cada petición, y el servidor no guarda ninguno. Para endurecer el contenedor como hace el despliegue de referencia:
docker run -d \ --name gitlab-mcp \ --read-only \ --tmpfs /tmp:rw,size=64m \ --cap-drop=ALL \ --security-opt=no-new-privileges:true \ -p 8080:8080 \ ghcr.io/jmrplens/gitlab-mcp-server:latest \ --http \ --http-addr=0.0.0.0:8080 \ --gitlab-url=https://gitlab.com# Publica cada instancia; la cabecera GITLAB-URL elige entre ellas y es# obligatoria, porque elegir por quien llama enviaría su token a otra partedocker run -d \ --name gitlab-mcp \ --read-only \ --tmpfs /tmp:rw,size=64m \ --cap-drop=ALL \ --security-opt=no-new-privileges:true \ -p 8080:8080 \ ghcr.io/jmrplens/gitlab-mcp-server:latest \ --http \ --http-addr=0.0.0.0:8080 \ --gitlab-url=https://gitlab.com \ --gitlab-url=https://gitlab.example.comUn cliente HTTP apunta entonces a http://localhost:8080/mcp con type: "http" y su propio token en una cabecera PRIVATE-TOKEN (el modo de autenticación legacy, que es el predeterminado), y http://localhost:8080/health responde sin credencial:
curl -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "PRIVATE-TOKEN: glpat-tu-token" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'En modo HTTP la configuración viene de flags y no de variables (--tool-surface, --tier, --read-only, --safe-mode, --skip-tls-verify, etcétera), que es lo que el docker-compose.yml del repositorio pasa en su línea command. El modo OAuth, la limitación de tasa, TLS en el propio listener, el dimensionado y la configuración de cliente para este transporte están en la página del Servidor HTTP.
Etiquetas y registros
Sección titulada «Etiquetas y registros»latestsigue a la release más nueva;3.2.0y cualquier otra etiqueta de versión se quedan fijas. Fija una etiqueta de versión en producción, o fija el digest para una inmutabilidad total:ghcr.io/jmrplens/gitlab-mcp-server:3.2.0@sha256:<digest>es la forma que usa elserver.jsondel MCP Registry para la release actual, con el digest que el workflow de release anotó al publicar la imagen.curl -fsSL https://raw.githubusercontent.com/jmrplens/gitlab-mcp-server/main/server.json | jq -r '.packages[] | select(.registryType == "oci") | .identifier'imprime esa referencia para los dos registros.ghcr.io/jmrplens/gitlab-mcp-serverydocker.io/jmrplens/gitlab-mcp-serverllevan las mismas imágenes: cada release sube un mismo índice a los dos, así que una etiqueta de versión ylatestresuelven al mismo digest en cada uno. La documentación usaghcr.io; usa el nombre de Docker Hub si ese es el registro que permite tu red.- El
docker-compose.ymldel repositorio nombra su imagen como${DOCKER_REGISTRY:-ghcr.io/jmrplens/gitlab-mcp-server}:${VERSION:-latest}, así queDOCKER_REGISTRYyVERSIONeligen el registro y la etiqueta sin editar el archivo. - La imagen lleva la etiqueta
io.modelcontextprotocol.server.name=io.github.jmrplens/gitlab-mcp-server, que es como el MCP Registry valida su propiedad.
Configura tu cliente
Sección titulada «Configura tu cliente»La entrada stdio para un cliente de escritorio es el comando docker run de arriba, repartido entre command y args, con el token en env:
{ "mcpServers": { "gitlab": { "command": "docker", "args": ["run", "-i", "--rm", "-e", "GITLAB_TOKEN", "ghcr.io/jmrplens/gitlab-mcp-server:latest"], "env": { "GITLAB_TOKEN": "glpat-xxxxxxxxxxxxxxxxxxxx" } } }}Para una instancia autogestionada añade "-e", "GITLAB_URL" a args y "GITLAB_URL": "https://gitlab.example.com" a env: la variable tiene que estar definida y reenviada a la vez. Las pestañas por cliente del Inicio rápido muestran dónde va este JSON en cada cliente; sustituye su command y su env por los de arriba. VS Code usa un mapa servers con "type": "stdio" en lugar de mcpServers.
Actualizar y desinstalar
Sección titulada «Actualizar y desinstalar»El servidor nunca se actualiza a sí mismo, y dentro de un contenedor no debería: descarga la imagen más nueva y arranca un contenedor nuevo a partir de ella.
docker pull ghcr.io/jmrplens/gitlab-mcp-server:latestUn cliente stdio que ejecuta docker run --rm usa la imagen descargada en su siguiente arranque. Para un servicio HTTP, recrea el contenedor (docker compose pull && docker compose up -d con el archivo Compose de referencia, o docker rm -f gitlab-mcp y el docker run de arriba). Con una etiqueta de versión, cambia la etiqueta y descarga esa. Para desinstalar, para cualquier contenedor y elimina la imagen:
docker rmi ghcr.io/jmrplens/gitlab-mcp-server:latesty quita la entrada gitlab de la configuración de tu cliente. Son los comandos estándar de Docker; nada en la imagen los cambia.