Ir al contenido

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. 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 pregunta por /health al servidor en marcha allá donde escuche (la imagen 2.7.5 lanza wget contra el puerto 8080 en su lugar).

Ventana de terminal
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:

Ventana de terminal
export GITLAB_TOKEN=glpat-xxxx
claude mcp add gitlab --transport stdio \
-- docker run -i --rm -e GITLAB_TOKEN ghcr.io/jmrplens/gitlab-mcp-server:latest

Claude 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.

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.

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:

Ventana de terminal
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.com

Un 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:

Ventana de terminal
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

Un 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:

Ventana de terminal
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, el rate limiting, 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.

  • latest sigue a la release más nueva; 2.7.5 y 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:2.7.5@sha256:8eec1825b266712cd544bf1b2144e55c1eb711b4540def40e963a664c4e97168 es la forma que usa el server.json del MCP Registry para la release actual.
  • ghcr.io/jmrplens/gitlab-mcp-server y docker.io/jmrplens/gitlab-mcp-server llevan las mismas imágenes: la etiqueta 2.7.5 resuelve al mismo digest en ambos. La documentación usa ghcr.io; usa el nombre de Docker Hub si ese es el registro que permite tu red.
  • La imagen lleva la etiqueta io.modelcontextprotocol.server.name=io.github.jmrplens/gitlab-mcp-server, que es como el MCP Registry valida su propiedad.

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.

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.

Ventana de terminal
docker pull ghcr.io/jmrplens/gitlab-mcp-server:latest

Un 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:

Ventana de terminal
docker rmi ghcr.io/jmrplens/gitlab-mcp-server:latest

y quita la entrada gitlab de la configuración de tu cliente. Son los comandos estándar de Docker; nada en la imagen los cambia.