Ir al contenido

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.

EscenarioModo Recomendado
Desarrollador individual, cliente de IA localstdio
Equipo compartiendo una instancia de servidorHTTP
Despliegue en servidor remoto/sin pantallaHTTP
Integración CI/CD con MCPHTTP
Pruebas con curl o clientes HTTPHTTP
Ventana de terminal
# 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=:8080

El servidor comienza a escuchar en el puerto 8080 por defecto. El endpoint MCP está disponible en /mcp.

FlagPor DefectoDescripción
--http(desactivado)Habilitar modo de transporte HTTP
--http-addr:8080Direcció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-verifyfalseOmitir verificación de certificados TLS para certificados autofirmados
--meta-toolstrueHabilitar 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-surfacefullSelector de recursos y prompts; consulta Opciones de superficie de herramientas y capacidades
--meta-param-schemaopaqueModo de esquema de entrada de meta-herramientas: opaque, compact o full
--enterprisefalseForzar herramientas Enterprise/Premium; omítelo para autodetectar CE/EE por entrada token+URL
--read-onlyfalseModo solo lectura: desactivar todas las herramientas de escritura
--safe-modefalseIntercepta herramientas modificantes y devuelve una vista previa JSON en lugar de ejecutarlas
--embedded-resourcestrueIncrustar URIs canónicas de recursos MCP en resultados de herramientas get_*
--max-http-clients100Máximo de entradas únicas token+URL en el pool del servidor
--session-timeout30mTimeout de sesión MCP inactiva
--auto-updatetrueModo de actualización automática: true, check o false
--auto-update-repojmrplens/gitlab-mcp-serverRepositorio de GitHub para assets del release
--auto-update-interval1hIntervalo de verificación periódica de actualizaciones
--auth-modelegacyModo de autenticación: legacy u oauth (RFC 9728)
--oauth-cache-ttl15mTTL de caché de identidad de token OAuth (rango: 1m–2h)
--revalidate-interval15mIntervalo de revalidación de token; 0 para desactivar (límite: 24h)
--rate-limit-rps0Límite de tasa por servidor para tools/call en req/s (0 = desactivado)
--rate-limit-burst40Tamaño máximo del token bucket cuando --rate-limit-rps > 0
--trusted-proxy-headerCabecera 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_tools y gitlab_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 con gitlab_find_action y gitlab_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.

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.

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

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

PRIVATE-TOKEN: glpat-xxxxxxxxxxxxxxxxxxxx
Authorization: Bearer glpat-xxxxxxxxxxxxxxxxxxxx

Si ambas cabeceras están presentes, PRIVATE-TOKEN tiene precedencia. Las solicitudes sin un token válido son rechazadas.

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:

Ventana de terminal
gitlab-mcp-server --http --gitlab-url=https://gitlab.com --auth-mode=oauth

Cómo funciona:

  1. El servidor expone /.well-known/oauth-protected-resource con metadatos que apuntan a tu instancia de GitLab como servidor de autorización
  2. Los clientes MCP (VS Code, Claude Code) descubren este endpoint e inician el flujo OAuth 2.1 PKCE
  3. Los usuarios autorizan en el navegador — no se requiere copiar tokens
  4. 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 (ver docs/oauth-app-setup.md)
  • scopes: Debe incluir api para funcionalidad completa de herramientas

VS Code maneja el descubrimiento OAuth y la autorización automáticamente.

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
  1. Primera solicitud: El token y la URL de GitLab se extraen, se combinan y hashean, y se crea un nuevo servidor MCP + cliente GitLab
  2. Solicitudes posteriores: La entrada existente se encuentra y se promueve en la lista LRU
  3. Timeout de inactividad: Después de --session-timeout de inactividad, la sesión MCP se cierra (pero la entrada del pool permanece)
  4. Desalojo del pool: Cuando se alcanza la capacidad, la entrada más antigua se elimina completamente

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.

FlagPor defectoSignificado
--rate-limit-rps0Tasa sostenida de relleno, en solicitudes por segundo. 0 desactiva el limitador
--rate-limit-burst40Capacidad 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.

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.

  • 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

Añadir a .vscode/mcp.json:

{
"servers": {
"gitlab": {
"type": "http",
"url": "http://tu-servidor:8080/mcp",
"headers": {
"PRIVATE-TOKEN": "glpat-tu-token"
}
}
}
}

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.

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
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-stopped

Iniciar el servicio:

Ventana de terminal
docker compose up -d

La imagen sigue las guías OWASP Docker Top 10:

PropiedadValor
Imagen basealpine:3.23 (mínima, parcheada regularmente)
Usuarioappuser (UID 10001, no-root)
Sistema de archivosSolo lectura con tmpfs escribible para /tmp
CapabilitiesTodas eliminadas (--cap-drop=ALL)
Escalada de privilegiosDeshabilitada (no-new-privileges:true)
Flags de compilación-trimpath -buildmode=pie (binario PIE, sin rutas de fuente en stack traces)
Etiquetas OCIorg.opencontainers.image.* con versión, commit, URL de origen

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.

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.

Ventana de terminal
# 1. Iniciar sesión
flyctl 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. Desplegar
flyctl deploy

El 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"
]
Ventana de terminal
flyctl status # Estado de máquinas y despliegues recientes
flyctl logs # Seguimiento en vivo de logs estructurados
flyctl 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)
  • El proxy de Fly sondea GET /health cada 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" y min_machines_running = 0 permiten que los despliegues inactivos escalen a cero entre peticiones

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:

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

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.

Puedes verificar que el servidor está funcionando enviando una solicitud tools/list:

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

Una respuesta exitosa devuelve un resultado JSON-RPC con la lista de herramientas disponibles.