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
--tool-surfacedynamicSelector canónico del catálogo; consulta Opciones de superficie de herramientas y capacidades
--meta-tools(sin definir)Flag de compatibilidad deprecado. Usa --tool-surface=individual en lugar de --meta-tools=false
--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; solo afecta schemas de meta-herramientas
--tier(detectado)Forzar el nivel de licencia (free, ce, premium, ultimate); omítelo para detectarlo por entrada token+URL desde la licencia de la instancia (por defecto free)
--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
--http-idle-timeout0 (desactivado)Timeout de conexión inactiva del servidor HTTP. 0 (por defecto) desactiva el cierre por inactividad, de modo que --session-timeout es la vida efectiva; usa una duración positiva para reciclar conexiones inactivas antes
--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)
--statelesstrueHTTP streamable sin sesiones (SEP-2567 / protocolo 2026-07-28): sin seguimiento de Mcp-Session-Id, cada POST es autónomo, GET/DELETE devuelven 405. Usa --stateless=false para sesiones con estado heredadas
--json-responsefalseDevuelve cuerpos application/json en lugar de text/event-stream (SSE)
--max-request-body-bytes0Tamaño máximo del cuerpo de las peticiones HTTP streamable en bytes; 0 usa el valor por defecto del SDK (4 MiB); los valores negativos se rechazan al arrancar. Los cuerpos que lo superan se rechazan con 413

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 dos herramientas: gitlab_find_action y gitlab_execute_action.

--capability-surface controla recursos y prompts de forma independiente a las herramientas: full registra todos los recursos, guías de flujo, prompts y el manifiesto gitlab://tools, mientras que minimal conserva el manifiesto gitlab://tools, y omite prompts, guías y recursos opcionales de GitLab. El descubrimiento de schemas dinámicos sigue funcionando con minimal porque find devuelve schemas inline.

--meta-param-schema solo afecta los schemas visibles de meta-herramientas de dominio. Mantén opaque salvo que un cliente necesite compact o full en tools/list; las formas de llamada exactas siguen disponibles en gitlab://tools/{id}.

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, META-TOOLS, 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. Las cabeceras deprecadas META-TOOLS también se identifican en deprecated_options.

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/guides/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 modo sin estado es el predeterminado y sigue el diseño sin sesiones introducido por SEP-2567 (protocolo MCP 2026-07-28):

  • El servidor no lee ni establece la cabecera Mcp-Session-Id. Cada POST es un intercambio JSON-RPC autónomo — no se necesita la ronda initialize.
  • GET y DELETE sobre el endpoint MCP devuelven 405 Method Not Allowed (Allow: POST). Los endpoints /health y /.well-known/* no se ven afectados.
  • Las peticiones síncronas iniciadas por el servidor no están disponibles. Los clientes con protocolo 2026-07-28 conservan la elicitación completa mediante peticiones multi-ronda (MRTR), que viajan dentro del resultado de la herramienta; solo los clientes con protocolo heredado recurren a las alternativas no interactivas (p. ej. el parámetro confirm para acciones destructivas).
  • --session-timeout no tiene efecto: ninguna sesión sobrevive a su petición.
  • El pool de servidores por token sigue aplicando, así que las peticiones repetidas reutilizan una instancia de servidor cacheada.

El modo sin estado encaja en despliegues con balanceo de carga donde las peticiones de un cliente pueden aterrizar en réplicas distintas. Combínalo con --json-response para clientes o gateways que prefieren cuerpos JSON planos en lugar de SSE:

Ventana de terminal
gitlab-mcp-server --http --gitlab-url=https://gitlab.example.com \
--json-response

--stateless=false restaura el transporte basado en sesiones: se emite Mcp-Session-Id en initialize, GET abre el flujo SSE independiente, DELETE termina la sesión y --session-timeout gobierna el tiempo de vida en reposo. Es un modo de compatibilidad para clientes que aún no negocian el protocolo 2026-07-28 (negocian 2025-11-25 o anterior y usan elicitación síncrona), el servidor registra un aviso al arrancar cuando está activo, y la intención es retirarlo cuando los ecosistemas de clientes hayan migrado.

Todos los resultados cacheables llevan sugerencias SEP-2549 con cacheScope: private, porque los catálogos y el contenido de los recursos se filtran según los ámbitos del token y el nivel de licencia de quien llama, y nunca deben servirse desde una caché compartida:

ResultadottlMs
tools/list, prompts/list, resources/list, resources/templates/list, server/discover300000 (5 minutos)
resources/read de contenido estático (guías, esquemas, manifiestos gitlab://tools)3600000 (1 hora)
resources/read de datos en vivo de GitLab0 (siempre fresco)

Las cancelaciones del cliente siempre se propagan a los contextos de los manejadores, de modo que un POST abandonado cancela sus llamadas en curso a la API de GitLab. El SDK lo aplica solo a las peticiones con protocolo 2026-07-28.

En la superficie dinámica de herramientas, la propiedad action de gitlab_execute_action lleva la anotación x-mcp-header de SEP-2243 con el valor Mcp-Param-Action, de modo que los gateways compatibles con MCP pueden enrutar, limitar y observar las llamadas por ID canónico de acción sin analizar el cuerpo JSON-RPC.

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.

Arquitectura del Modo HTTP

Cliente A
Token: glpat-aaa
URL: gitlab.com

StreamableHTTPHandler

Cliente B
Token: glpat-bbb
URL: gitlab.com

Cliente C
Token: glpat-aaa
URL: self-hosted.ejemplo.com

Pool de Servidores

hash(glpat-aaa + gitlab.com)
Servidor MCP + Cliente GitLab

hash(glpat-bbb + gitlab.com)
Servidor MCP + Cliente GitLab

hash(glpat-aaa + self-hosted)
Servidor MCP + Cliente GitLab

API de GitLab
como usuario A @ gitlab.com

API de GitLab
como usuario B @ gitlab.com

API de GitLab
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

Modelo de timeouts: capa HTTP vs sesión MCP

Sección titulada «Modelo de timeouts: capa HTTP vs sesión MCP»

Dos capas independientes gobiernan la vida de la conexión y de la sesión:

  • Sesión MCP (--session-timeout, por defecto 30m): vida útil de inactividad de la sesión MCP a nivel del transporte del SDK.
  • Conexión HTTP inactiva (--http-idle-timeout, por defecto 0 = desactivado): el tiempo máximo que el http.Server espera la siguiente petición en una conexión keep-alive antes de cerrarla.
  • Escritura de respuesta HTTP (fijo 60s, desactivado para SSE): acota cuánto puede tardar en escribirse una respuesta.

El servidor habla el transporte moderno Streamable HTTP, que usa Server-Sent Events (text/event-stream) para las respuestas en streaming y el stream independiente que transporta las notificaciones iniciadas por el servidor y los pings de keep-alive. Una respuesta SSE activa está acotada por WriteTimeout (no por IdleTimeout, que solo limita la espera entre peticiones en una conexión inactiva), y el escritor SSE del go-sdk nunca reinicia el deadline de escritura.

Para no cortar esos streams sin debilitar la protección del resto, el WriteTimeout global se mantiene en unos seguros 60s (protegiendo endpoints estándar como /health de ataques de escritura lenta) y cualquier petición que negocie SSE (Accept: text/event-stream) — tanto el stream GET independiente como las respuestas POST en streaming — desactiva dinámicamente su propio deadline de escritura. Como --http-idle-timeout vale 0 (desactivado) por defecto, la capa HTTP tampoco cierra las conexiones inactivas de fábrica, así que --session-timeout es la vida efectiva de inactividad. Pon un --http-idle-timeout bajo solo si quieres reciclar antes las conexiones inactivas.

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.24 (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",
"--tool-surface=meta",
"--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 2048 # Redimensionar memoria (el fly.toml de este repo declara 10 GB)
  • 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/guides/oauth-app-setup.md para la configuración de la Aplicación OAuth de GitLab.

Dimensiona el host por el conjunto residente del servidor HTTP, no por el tamaño del binario. Medido sobre la build v2.6.1 (darwin/arm64, AUTO_UPDATE=false, en reposo justo tras arrancar):

ModoConjunto residenteNotas
stdio, cualquier superficie~29–30 MBPrácticamente idéntico en dynamic, meta e individual
HTTP, en reposo, sin sesiones~181 MBAntes de que se conecte ningún cliente
Binario en disco~70 MBBinario estático único, sin dependencias de runtime

De aquí se derivan dos cosas.

El modo HTTP necesita al menos 512 MB. Una instancia de 256 MB no basta: el servidor reposa en torno a 181 MB antes de que se conecte nadie, y cada sesión del pool añade su propio catálogo y cliente encima. No es un límite teórico: una VM de Fly.io con 256 MB ejecutando la v2.4.0 fue terminada por OOM durante el arranque. El margen por encima de ese suelo lo marca la concurrencia: el pool mantiene hasta --max-http-clients entradas, cada una con su propia instancia del servidor MCP, así que el pico de memoria sigue a los pares token+URL distintos y no al volumen de peticiones. El despliegue de referencia de este repositorio declara memory = "10gb" sobre shared-cpu-8x, generoso por ese motivo; dimensiona el tuyo según tu concurrencia esperada.

La superficie de herramientas casi no afecta a la memoria, solo al contexto. Las tres superficies construyen el mismo catálogo canónico de acciones, así que elegir dynamic en vez de individual ahorra ventana de contexto del modelo, no RAM del servidor. Elige la superficie por coste de tokens y el tamaño de instancia por concurrencia.

La concurrencia la acotan --max-http-clients (100 por defecto) y --session-timeout (30m por defecto), que juntos fijan cuántas entradas puede haber en el pool a la vez. Baja ambos si vas justo de memoria y súbelos solo junto con más RAM. Las cifras absolutas varían según plataforma y versión del runtime de Go: tómalas como punto de partida y mide tu propio despliegue.

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.

Preguntas frecuentes

¿Cuándo debería usar el modo HTTP en lugar de stdio?

Usa el modo stdio para un único desarrollador con un cliente de IA local, donde cada cliente inicia su propio proceso de servidor. Usa el modo HTTP cuando un equipo comparte una instancia de servidor, para despliegues remotos o sin pantalla, para integración CI/CD con MCP y para pruebas con curl o clientes HTTP. En modo HTTP un único proceso de servidor atiende a varios clientes por la red, cada uno autenticándose con su propio token de GitLab.

¿Cómo se autentican los clientes en el modo HTTP?

Los clientes envían su Token de Acceso Personal de GitLab en cada petición usando la cabecera PRIVATE-TOKEN (recomendada) o una cabecera Authorization: Bearer; si ambas están presentes, PRIVATE-TOKEN tiene precedencia. Cuando el servidor arranca sin --gitlab-url, los clientes también envían una cabecera GITLAB-URL para elegir la instancia destino. Para producción, --auth-mode=oauth habilita OAuth 2.1 con PKCE compatible con RFC 9728, de modo que los clientes descubren el servidor de autorización y autorizan en el navegador en lugar de copiar tokens.

¿Los clientes del modo HTTP comparten estado o contexto?

No. El modo HTTP usa 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. Los clientes con el mismo token y la misma URL comparten una instancia, mientras que tokens distintos o URLs distintas obtienen instancias completamente aisladas. Los tokens sin procesar nunca se almacenan —solo los hashes SHA-256— y cuando el pool alcanza --max-http-clients se desaloja la entrada menos usada recientemente.

¿Por qué se caen mis sesiones MCP o se cortan los streams?

Dos capas independientes gobiernan la vida útil: el timeout de inactividad de la sesión MCP (--session-timeout, por defecto 30m) y el timeout de conexión HTTP inactiva (--http-idle-timeout, por defecto 0 = desactivado). Como --http-idle-timeout vale 0 por defecto, la capa HTTP no cierra conexiones inactivas, así que --session-timeout es la vida efectiva de inactividad. Si las sesiones caen pronto, un --http-idle-timeout bajo o un timeout de lectura/inactividad del proxy inverso suele cerrar los streams SSE de larga duración; aumenta el timeout del proxy para streams MCP largos.