Modo Servidor HTTP
Por defecto, GitLab MCP Server se ejecuta en modo stdio — cada cliente de IA inicia su propio proceso de servidor. El modo HTTP es una alternativa donde un único proceso de servidor atiende a múltiples clientes a través de la red, cada uno autenticándose con su propio token de GitLab.
Cuándo usar el modo HTTP
Sección titulada «Cuándo usar el modo HTTP»| Escenario | Modo Recomendado |
|---|---|
| Desarrollador individual, cliente de IA local | stdio |
| Equipo compartiendo una instancia de servidor | HTTP |
| Despliegue en servidor remoto/sin pantalla | HTTP |
| Integración CI/CD con MCP | HTTP |
| Pruebas con curl o clientes HTTP | HTTP |
Iniciar el servidor
Sección titulada «Iniciar el servidor»# Instancia única de GitLab.com (URL fija para todos los clientes; reemplázala para GitLab autogestionado)gitlab-mcp-server --http --gitlab-url=https://gitlab.com
# Multi-instancia (cada cliente especifica su URL de GitLab mediante la cabecera GITLAB-URL)gitlab-mcp-server --http --http-addr=:8080El servidor comienza a escuchar en el puerto 8080 por defecto. El endpoint MCP está disponible en /mcp.
Flags de CLI
Sección titulada «Flags de CLI»| Flag | Por Defecto | Descripción |
|---|---|---|
--http | (desactivado) | Habilitar modo de transporte HTTP |
--http-addr | :8080 | Dirección de escucha HTTP (host:puerto) |
--gitlab-url | (opcional) | URL fija de la instancia de GitLab. Omítela para requerir GITLAB-URL en cada petición |
--skip-tls-verify | false | Omitir verificación de certificados TLS para certificados autofirmados |
--meta-tools | true | Habilitar meta-herramientas de dominio. Establécelo a false para herramientas individuales |
--tool-surface | (vacío) | Selector explícito del catálogo; consulta Opciones de superficie de herramientas y capacidades. Sobrescribe --meta-tools |
--capability-surface | full | Selector de recursos y prompts; consulta Opciones de superficie de herramientas y capacidades |
--meta-param-schema | opaque | Modo de esquema de entrada de meta-herramientas: opaque, compact o full |
--enterprise | false | Forzar herramientas Enterprise/Premium; omítelo para autodetectar CE/EE por entrada token+URL |
--read-only | false | Modo solo lectura: desactivar todas las herramientas de escritura |
--safe-mode | false | Intercepta herramientas modificantes y devuelve una vista previa JSON en lugar de ejecutarlas |
--embedded-resources | true | Incrustar URIs canónicas de recursos MCP en resultados de herramientas get_* |
--max-http-clients | 100 | Máximo de entradas únicas token+URL en el pool del servidor |
--session-timeout | 30m | Timeout de sesión MCP inactiva |
--auto-update | true | Modo de actualización automática: true, check o false |
--auto-update-repo | jmrplens/gitlab-mcp-server | Repositorio de GitHub para assets del release |
--auto-update-interval | 1h | Intervalo de verificación periódica de actualizaciones |
--auth-mode | legacy | Modo de autenticación: legacy u oauth (RFC 9728) |
--oauth-cache-ttl | 15m | TTL de caché de identidad de token OAuth (rango: 1m–2h) |
--revalidate-interval | 15m | Intervalo de revalidación de token; 0 para desactivar (límite: 24h) |
--rate-limit-rps | 0 | Límite de tasa por servidor para tools/call en req/s (0 = desactivado) |
--rate-limit-burst | 40 | Tamaño máximo del token bucket cuando --rate-limit-rps > 0 |
--trusted-proxy-header | — | Cabecera HTTP con la IP real del cliente para rate limiting detrás de proxies (ej. Fly-Client-IP, X-Forwarded-For) |
Opciones de superficie de herramientas y capacidades
Sección titulada «Opciones de superficie de herramientas y capacidades»--tool-surface selecciona el catálogo de herramientas MCP visible para cada entrada del pool del servidor HTTP:
meta: meta-herramientas por dominio, el catálogo consolidado por defecto.individual: cada operación de GitLab se expone como una herramienta independiente.dynamic: la superficie actual de bajo consumo con tres herramientas:gitlab_search_tools,gitlab_describe_toolsygitlab_execute_tool.dynamic-3: selector explícito para la misma superficie dinámica de tres herramientas, útil para configuraciones fijadas.dynamic-2: superficie experimental de dos herramientas congitlab_find_actionygitlab_execute_tool.
--capability-surface controla recursos y prompts de forma independiente a las herramientas: full registra todos los recursos y prompts, mientras que minimal conserva solo el recurso de roots del workspace para despliegues dinámicos de bajo consumo.
Precedencia de configuración
Sección titulada «Precedencia de configuración»Los clientes HTTP solo controlan su token de GitLab y, en modo multi-instancia, el selector GITLAB-URL. Las opciones de política del servidor como --tool-surface, --capability-surface, --meta-param-schema, --rate-limit-rps, --read-only, --safe-mode, --auth-mode y --trusted-proxy-header quedan fijadas por el proceso MCP y no pueden cambiarse por usuario, sesión ni petición JSON-RPC.
Si un cliente envía cabeceras con aspecto de configuración, como TOOL-SURFACE, CAPABILITY-SURFACE, META-PARAM-SCHEMA, RATE-LIMIT-RPS o GITLAB-SAFE-MODE, el servidor las ignora y registra sus nombres en ignored_options sin registrar sus valores.
Autenticación
Sección titulada «Autenticación»Los clientes deben proporcionar su Token de Acceso Personal de GitLab en cada solicitud HTTP usando una de dos cabeceras.
Cuando el servidor arranca sin --gitlab-url, los clientes deben especificar a qué instancia de GitLab dirigirse mediante la cabecera GITLAB-URL:
GITLAB-URL: https://gitlab.ejemplo.comSi --gitlab-url se estableció al iniciar, esta cabecera se ignora y se registra. Si --gitlab-url no se estableció y la cabecera se omite, la solicitud se rechaza.
Cabecera private-token (recomendada)
Sección titulada «Cabecera private-token (recomendada)»PRIVATE-TOKEN: glpat-xxxxxxxxxxxxxxxxxxxxCabecera authorization Bearer
Sección titulada «Cabecera authorization Bearer»Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxxSi ambas cabeceras están presentes, PRIVATE-TOKEN tiene precedencia. Las solicitudes sin un token válido son rechazadas.
Modo OAuth
Sección titulada «Modo OAuth»El modo OAuth (--auth-mode=oauth) habilita autenticación OAuth 2.1 compatible con RFC 9728. En lugar de gestionar tokens manualmente, los clientes MCP descubren el servidor de autorización automáticamente y manejan el flujo OAuth:
gitlab-mcp-server --http --gitlab-url=https://gitlab.com --auth-mode=oauthCómo funciona:
- El servidor expone
/.well-known/oauth-protected-resourcecon metadatos que apuntan a tu instancia de GitLab como servidor de autorización - Los clientes MCP (VS Code, Claude Code) descubren este endpoint e inician el flujo OAuth 2.1 PKCE
- Los usuarios autorizan en el navegador — no se requiere copiar tokens
- El servidor valida los tokens Bearer contra la API de GitLab y cachea la identidad durante
--oauth-cache-ttl(por defecto: 15 minutos)
Configuración del cliente en modo OAuth:
{ "servers": { "gitlab": { "type": "http", "url": "http://tu-servidor:8080/mcp", "oauth": { "clientId": "TU_APPLICATION_ID_DE_GITLAB", "scopes": ["api"] } } }}clientId: El Application ID de tu Aplicación OAuth de GitLab (verdocs/oauth-app-setup.md)scopes: Debe incluirapipara funcionalidad completa de herramientas
VS Code maneja el descubrimiento OAuth y la autorización automáticamente.
claude mcp add gitlab \ --transport http \ --client-id TU_APPLICATION_ID_DE_GITLAB \ --callback-port 8090 \ http://tu-servidor:8080/mcpClaude Code descubre los metadatos OAuth y abre el navegador para la autorización.
Gestión de sesiones
Sección titulada «Gestión de sesiones»Arquitectura del pool de servidores
Sección titulada «Arquitectura del pool de servidores»El núcleo del modo HTTP es un pool LRU limitado de instancias de servidor MCP, indexado por el hash SHA-256 del token y la URL de GitLab de cada cliente.
graph TD
subgraph "Arquitectura del Modo HTTP"
REQ1["Cliente A<br/>Token: glpat-aaa<br/>URL: gitlab.com"] --> HANDLER[StreamableHTTPHandler]
REQ2["Cliente B<br/>Token: glpat-bbb<br/>URL: gitlab.com"] --> HANDLER
REQ3["Cliente C<br/>Token: glpat-aaa<br/>URL: self-hosted.ejemplo.com"] --> HANDLER
HANDLER --> POOL[Pool de Servidores]
POOL --> ENTRY1["hash(glpat-aaa + gitlab.com)<br/>Servidor MCP + Cliente GitLab"]
POOL --> ENTRY2["hash(glpat-bbb + gitlab.com)<br/>Servidor MCP + Cliente GitLab"]
POOL --> ENTRY3["hash(glpat-aaa + self-hosted)<br/>Servidor MCP + Cliente GitLab"]
end
ENTRY1 --> GL1["API de GitLab<br/>como usuario A @ gitlab.com"]
ENTRY2 --> GL2["API de GitLab<br/>como usuario B @ gitlab.com"]
ENTRY3 --> GL3["API de GitLab<br/>como usuario A @ self-hosted"]
Propiedades clave:
- Los clientes con el mismo token y la misma URL de GitLab comparten la misma instancia del servidor MCP
- Los clientes con diferentes tokens o diferentes URLs de GitLab obtienen instancias completamente aisladas
- Los tokens sin procesar nunca se almacenan — solo se mantienen hashes SHA-256 de token+URL en memoria
- Cuando el pool alcanza
--max-http-clients, la entrada menos usada recientemente es desalojada
Ciclo de vida de la sesión
Sección titulada «Ciclo de vida de la sesión»- Primera solicitud: El token y la URL de GitLab se extraen, se combinan y hashean, y se crea un nuevo servidor MCP + cliente GitLab
- Solicitudes posteriores: La entrada existente se encuentra y se promueve en la lista LRU
- Timeout de inactividad: Después de
--session-timeoutde inactividad, la sesión MCP se cierra (pero la entrada del pool permanece) - Desalojo del pool: Cuando se alcanza la capacidad, la entrada más antigua se elimina completamente
Rate limiting
Sección titulada «Rate limiting»El modo HTTP incluye un rate limiter por servidor con token bucket opcional que regula las solicitudes tools/call. El limitador está desactivado por defecto (--rate-limit-rps=0) y se aplica a cada entrada del pool de forma independiente — es decir, el ámbito es la misma clave (token + URL de GitLab) que usa el pool de servidores.
Configuración
Sección titulada «Configuración»| Flag | Por defecto | Significado |
|---|---|---|
--rate-limit-rps | 0 | Tasa sostenida de relleno, en solicitudes por segundo. 0 desactiva el limitador |
--rate-limit-burst | 40 | Capacidad máxima del bucket (pico de ráfaga durante 1s) |
Cuando --rate-limit-rps > 0, cada entrada del pool obtiene su propio token bucket dimensionado en --rate-limit-burst tokens, rellenado a --rate-limit-rps por segundo. Solo las solicitudes tools/call consumen tokens; tools/list, resources/*, prompts/*, initialize y otras RPCs de bajo coste no están limitadas.
Comportamiento al agotarse
Sección titulada «Comportamiento al agotarse»Cuando una solicitud agotaría el bucket, el servidor devuelve un CallToolResult con IsError: true y un mensaje de texto como rate limit exceeded for <tool>; retry after a short backoff. Los clientes deben aplicar backoff (exponencial o detectando ese mensaje) y reintentar. El limitador no devuelve HTTP 429 porque el límite se aplica después del enrutado JSON-RPC, dentro de la capa MCP.
Guía de dimensionado
Sección titulada «Guía de dimensionado»- Despliegue de un solo usuario (dev local típico): déjalo desactivado (
--rate-limit-rps=0) - Instancia compartida tras un proxy (Fly.io, Kubernetes): empieza con
--rate-limit-rps=10 --rate-limit-burst=40. Cada par token+URL obtiene su propia cuota, lo que protege frente a un único cliente ruidoso sin afectar a los demás - Despliegue multi-tenant grande: combina con rate limiting a nivel de infraestructura (Cloudflare, Caddy, nginx). El limitador a nivel MCP es una red de seguridad, no un sustituto del control en el edge
Configuración del cliente
Sección titulada «Configuración del cliente»Añadir a .vscode/mcp.json:
{ "servers": { "gitlab": { "type": "http", "url": "http://tu-servidor:8080/mcp", "headers": { "PRIVATE-TOKEN": "glpat-tu-token" } } }}{ "mcpServers": { "gitlab": { "url": "http://tu-servidor:8080/mcp", "headers": { "PRIVATE-TOKEN": "glpat-tu-token" } } }}curl -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "PRIVATE-TOKEN: glpat-tu-token" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'Despliegue con Docker
Sección titulada «Despliegue con Docker»El proyecto publica una imagen Docker multi-arquitectura en ghcr.io/jmrplens/gitlab-mcp-server para linux/amd64 y linux/arm64. La imagen se ejecuta como usuario no-root (UID 10001), expone el puerto 8080, incluye un endpoint /health para orquestadores e inicia en modo HTTP por defecto.
Inicio rápido con docker run
Sección titulada «Inicio rápido con docker run»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# Omitir --gitlab-url; los clientes envían la cabecera GITLAB-URL por peticióndocker 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:8080Docker Compose
Sección titulada «Docker Compose»services: gitlab-mcp: image: ghcr.io/jmrplens/gitlab-mcp-server:latest ports: - "8080:8080" command: # Modo instancia única (URL fija de GitLab.com para todos los clientes; reemplázala para GitLab autogestionado): - "--http" - "--gitlab-url=https://gitlab.com" - "--http-addr=:8080" - "--max-http-clients=200" - "--session-timeout=1h" # O modo multi-instancia (eliminar --gitlab-url, los clientes envían la cabecera GITLAB-URL) # Endurecimiento de seguridad (mínimo privilegio, OWASP Docker security) read_only: true tmpfs: - /tmp:rw,size=64m,mode=1777 cap_drop: - ALL security_opt: - no-new-privileges:true healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"] interval: 30s timeout: 5s retries: 3 start_period: 10s restart: unless-stoppedIniciar el servicio:
docker compose up -dModelo de seguridad de la imagen
Sección titulada «Modelo de seguridad de la imagen»La imagen sigue las guías OWASP Docker Top 10:
| Propiedad | Valor |
|---|---|
| Imagen base | alpine:3.23 (mínima, parcheada regularmente) |
| Usuario | appuser (UID 10001, no-root) |
| Sistema de archivos | Solo lectura con tmpfs escribible para /tmp |
| Capabilities | Todas eliminadas (--cap-drop=ALL) |
| Escalada de privilegios | Deshabilitada (no-new-privileges:true) |
| Flags de compilación | -trimpath -buildmode=pie (binario PIE, sin rutas de fuente en stack traces) |
| Etiquetas OCI | org.opencontainers.image.* con versión, commit, URL de origen |
Auto-actualización dentro de contenedores
Sección titulada «Auto-actualización dentro de contenedores»La auto-actualización está deshabilitada por defecto cuando se usa el docker-compose.yml de referencia (que establece --auto-update=false). La inmutabilidad del contenedor es el patrón recomendado: descargar una imagen con etiqueta nueva y reiniciar el contenedor. Si necesitas actualizaciones in-situ (ej. en un despliegue de host único sin un mirror de registro de imágenes), establece --auto-update=true y monta la ruta del binario como un volumen escribible.
Despliegue en Fly.io
Sección titulada «Despliegue en Fly.io»Fly.io es una plataforma gestionada que ejecuta imágenes Docker globalmente con TLS integrado, enrutamiento anycast y escalado de máquinas por región. El repositorio incluye un fly.toml de referencia configurado en modo multi-instancia — cada cliente suministra su propio token de GitLab y la cabecera GITLAB-URL por petición, por lo que una única app de Fly puede servir a usuarios conectados a diferentes instancias de GitLab.
Requisitos previos
Sección titulada «Requisitos previos»- Una cuenta de Fly.io y la CLI
flyctlinstalada - Un clon del repositorio (o un fork con tu propio
fly.toml)
Despliegue inicial
Sección titulada «Despliegue inicial»# 1. Iniciar sesiónflyctl auth login
# 2. Crear la app (usa un nombre único; el por defecto en fly.toml es gitlab-mcp-server)flyctl launch --no-deploy --copy-config --name nombre-de-tu-app
# 3. Desplegarflyctl deployEl fly.toml incluido usa el Dockerfile multi-stage de la raíz del repositorio y sobrescribe el CMD del contenedor con flags de modo HTTP:
[experimental] cmd = [ "--http", "--http-addr", "0.0.0.0:8080", "--meta-tools", "--auto-update=false", "--trusted-proxy-header", "Fly-Client-IP" ]Comandos operativos
Sección titulada «Comandos operativos»flyctl status # Estado de máquinas y despliegues recientesflyctl logs # Seguimiento en vivo de logs estructuradosflyctl scale count 2 # Ejecutar dos máquinas (ej. para HA)flyctl scale memory 512 # Subir memoria a 512 MB (por defecto en fly.toml: 256 MB)Salud y TLS
Sección titulada «Salud y TLS»- El proxy de Fly sondea
GET /healthcada 30s con timeout de 5s (configurado en[[http_service.checks]]) - TLS se termina en el edge de Fly con
force_https = true— el tráfico interno a la máquina en el puerto 8080 es HTTP auto_stop_machines = "stop"ymin_machines_running = 0permiten que los despliegues inactivos escalen a cero entre peticiones
Auto-actualización en Fly
Sección titulada «Auto-actualización en Fly»La auto-actualización está deshabilitada en la configuración incluida (--auto-update=false). En Fly.io, el flujo de actualización recomendado es redesplegar con una imagen nueva:
flyctl deploy --image ghcr.io/jmrplens/gitlab-mcp-server:<version>Esto reemplaza las máquinas en ejecución con la nueva versión atómicamente y preserva tus secretos y configuración.
OAuth en Fly.io
Sección titulada «OAuth en Fly.io»El fly.toml incluido se ejecuta en modo de autenticación legacy (PAT por petición). El modo OAuth también está soportado pero requiere una URL pública estable conocida al inicio para que los endpoints de descubrimiento OAuth (/.well-known/oauth-protected-resource) anuncien los metadatos correctos. Para habilitar OAuth, establece --auth-mode=oauth y --gitlab-url=<tu-default> en el array cmd, y redespliega. Consulta docs/oauth-app-setup.md para la configuración de la Aplicación OAuth de GitLab.
Verificación de salud
Sección titulada «Verificación de salud»Puedes verificar que el servidor está funcionando enviando una solicitud tools/list:
curl -s -X POST http://localhost:8080/mcp \ -H "Content-Type: application/json" \ -H "PRIVATE-TOKEN: glpat-tu-token" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' | head -c 200Una respuesta exitosa devuelve un resultado JSON-RPC con la lista de herramientas disponibles.