Ir al contenido

Variables de entorno

Esta página recoge todas las variables que lee el servidor: los 45 ajustes GITLAB_MCP_*, GITLAB_URL, GITLAB_TOKEN, AUTOPILOT, las variables OTEL_* de la especificación de OpenTelemetry y las pocas que lee por su cuenta el runtime de Go. Configuración explica las opciones que fijan casi todos los despliegues y cómo ponerlas en un cliente; la referencia de la línea de comandos cubre todos los flags.

  • Predeterminado es lo que significa una variable sin definir o vacía. Un valor vacío cuenta como no definido en todas partes.
  • Transporte dice qué modo lee la variable. HTTP; stdio la valida significa que un servidor stdio la interpreta y se niega a arrancar ante un valor no válido, aunque nunca la use.
  • Flag es la grafía en la línea de comandos. Un flag solo se lee en modo HTTP salvo que la celda diga ambos: un servidor stdio toma todo lo demás del entorno, nombra al arrancar el flag de solo HTTP que recibió y lo ignora (cuatro de ellos pueden impedir el arranque; consulta la referencia de la línea de comandos).
  • Un valor no válido impide el arranque salvo que la fila diga otra cosa. Las filas que avisan y conservan un valor predeterminado lo hacen a propósito, y dicen por qué.
TipoQué se acepta
BooleanoLas grafías booleanas de Go: true, false, 1, 0, t, f, en minúsculas, mayúsculas o con inicial mayúscula. Tres excepciones: GITLAB_MCP_YOLO_MODE y AUTOPILOT leen 1, true y yes (sin distinguir mayúsculas) como verdadero y cualquier otra cosa como falso; GITLAB_MCP_TELEMETRY y OTEL_SDK_DISABLED solo leen true y false (sin distinguir mayúsculas), y avisan de cualquier otra cosa y la tratan como falso; GITLAB_MCP_ALLOW_PRIVATE_INSTANCES trata como falso, sin decir nada, todo lo que no se puede interpretar, porque desactiva una protección
DuraciónSintaxis de duración de Go: 90s, 15m, 1h30m. 0 solo se acepta donde la fila dice que desactiva algo, y allí solo escrito como 0 a secas: 0s impide el arranque, aunque el flag del mismo nombre lo acepta (#1171). GITLAB_MCP_TELEMETRY_IDENTITY_ROTATION acepta las dos formas. Los plazos OTEL_*, en cambio, son milisegundos enteros (una trampa que conviene conocer)
TamañoUn número de bytes, o un número con sufijo KB, MB o GB en mayúsculas o minúsculas. Los sufijos son potencias de 1024
ListaSeparada por comas, sin los espacios que rodean cada entrada. Una lista de directorios usa en cambio el separador de rutas del sistema operativo: : en Linux y macOS, ; en Windows
VariablePredeterminadoAceptaTransporteFlagQué hace
GITLAB_URLhttps://gitlab.com en stdio; ninguno en modo HTTPUna URL http:// o https:// con host. En modo HTTP, una lista separada por comasAmbos--gitlab-urlEn stdio, la instancia a la que se envía el token. En modo HTTP, la instancia o instancias que publica el despliegue: obligatoria salvo que se pase --allow-any-gitlab-url, y con varias la cabecera de petición GITLAB-URL es obligatoria y debe nombrar una de ellas. Con GITLAB_MCP_AUTH_MODE=oauth toda instancia debe ser https, y http solo se acepta para un host de loopback. Un servidor stdio arrancado a mano en una terminal con esta variable o GITLAB_TOKEN sin definir tras leer los ficheros dotenv muestra una pantalla de primer arranque y espera a Intro en lugar de servir
GITLAB_TOKENNinguno: es obligatoria en stdioUn token de acceso personal de GitLab (glpat-...); consulta Qué tokenstdioNinguno, a propósitoLa credencial con la que se hace cada llamada. No tiene flag porque un token en la línea de comandos queda a la vista de todos los usuarios de la máquina con ps, lo recoge la contabilidad de procesos y acaba en el historial de la shell. El modo HTTP nunca la lee: cada petición trae su propio token
GITLAB_MCP_SKIP_TLS_VERIFYfalseBooleanoAmbos--skip-tls-verifyOmite la verificación del certificado de la instancia GitLab. El modo HTTP la rechaza con GITLAB_MCP_AUTH_MODE=oauth para cualquier instancia que no sea de loopback, porque los tokens bearer irían a cualquier host que respondiera. Una CA privada en el almacén de confianza del sistema, o SSL_CERT_FILE (consulta Leídas por el runtime de Go), no necesita flag
GITLAB_MCP_ALLOW_PRIVATE_INSTANCESfalseBooleano; lo que no se puede interpretar es falsoAmbos--allow-private-instances (ambos)Permite que un destino que el operador no eligió resuelva a una dirección de loopback, privada, CGNAT 100.64.0.0/10, de enlace local, local única o no especificada: una instancia que quien llama nombró en GITLAB-URL con --allow-any-gitlab-url, o un salto de redirección que salió del host de la instancia configurada. Una dirección que nombren GITLAB_URL o --gitlab-url nunca se comprueba, y las direcciones de metadatos de la nube siguen rechazadas diga lo que diga (Conexiones salientes)
TokenQué le sirve el servidor
Clásico, scope apiTodas las acciones que permite el tier
Clásico, scope read_apiSolo las acciones de lectura: el servidor lee los scopes del token al arrancar y le construye una superficie de solo lectura
De grano fino (su lista de scopes dice granular)Lo que alcanza su concesión, decidido acción por acción frente a los permisos que declara GitLab, cuando el token concede Personal Access Token: Read y Metadata: Read y la instancia ejecuta la versión de la que se registró la tabla de permisos; si no, todo salvo las acciones que ningún token de grano fino alcanza (Tokens de grano fino)
Ni read_api ni apiNada. Un servidor stdio sigue respondiendo al saludo de MCP y rechaza todos los métodos del catálogo (tools/list, tools/call, los métodos de recursos y prompts, los autocompletados y subscriptions/listen) con -40300 y un mensaje que pide crear un token con read_api, o con api para escribir también, y reiniciar con él. El modo HTTP rechaza un token así con 403

Un token cuyos scopes no se pueden leer se sirve como si pudiera escribir, y el propio 403 de GitLab responde a la llamada que no puede hacer. GITLAB_MCP_IGNORE_SCOPES omite la restricción a solo lectura y el filtro por scopes, nunca el mínimo de read_api.

VariablePredeterminadoAceptaTransporteFlagQué hace
GITLAB_MCP_TOOL_SURFACEdynamicdynamic, meta, individualAmbos--tool-surfaceQué catálogo de herramientas se registra: dos herramientas de búsqueda y ejecución (dynamic), un despachador por dominio (meta) o una herramienta por acción
GITLAB_MCP_CAPABILITY_SURFACEfullfull, minimalAmbos--capability-surfaceminimal conserva el manifiesto gitlab://tools y quita los demás recursos, los prompts, las guías de flujo y las suscripciones a recursos
GITLAB_MCP_META_PARAM_SCHEMAopaqueopaque, compact, full, sin distinguir mayúsculasAmbos--meta-param-schemaCómo describen las meta-herramientas sus params en tools/list: un sobre opaco, o un esquema por acción solo con los nombres de las propiedades (compact) o completo. Según lo medido, ocupan unas 8,7 y 18,3 veces el esquema opaco. Solo cambia el listado de la superficie meta: ningún handler, ningún resultado de búsqueda y ninguna entrada de gitlab://tools
GITLAB_MCP_TIERDetectadofree (o ce), premium, ultimate, sin distinguir mayúsculasAmbos--tierDefinido, el tier se usa tal cual sin comprobar la licencia. Sin definir, se detecta con GET /license (que solo puede leer un administrador en instancias autogestionadas, y nadie en GitLab.com) y después con los planes de los namespaces que administra el token (GET /namespaces, el plan real en GitLab.com y siempre default en autogestionadas), leídos de 100 en 100 durante 10 páginas como mucho y deteniéndose en el primer ultimate. Si ninguno responde, el tier es free, y una instancia enterprise lo dice en WARN nombrando esta variable. El modo HTTP lo detecta por credencial salvo que esté fijado
GITLAB_MCP_READ_ONLYfalseBooleanoAmbos--read-onlyQuita todas las acciones que modifican, acción por acción y no herramienta por herramienta, así que las lecturas siguen funcionando en todas las superficies: una meta-herramienta conserva sus acciones de lectura, y gitlab_execute_action de la superficie dinámica se queda, anotada como de solo lectura, para las lecturas que puede encaminar (Modo de solo lectura)
GITLAB_MCP_SAFE_MODEfalseBooleanoAmbos--safe-modeResponde a una acción que modifica con una tarjeta de vista previa que nombra la acción y repite sus argumentos en lugar de ejecutarla; las lecturas se siguen ejecutando. Si ambos están activos, gana el modo de solo lectura (Modo seguro)
GITLAB_MCP_EMBEDDED_RESOURCEStrueBooleanoAmbos--embedded-resourcesAñade el recurso canónico gitlab:// como bloque de recurso incrustado a los resultados de las acciones get que tienen uno (Formato de salida). Pon false para un cliente que no tolere el bloque de contenido duplicado
GITLAB_MCP_EXCLUDE_TOOLSVacíoLista de nombres de herramienta, nombres de grupo o IDs canónicos de acción, como gitlab_admin,gitlab_runner,project.deleteAmbos--exclude-toolsQuita lo que nombra en todas las superficies, y de los recursos, suscripciones, prompts y autocompletados que devuelven los mismos objetos. Las utilidades independientes responden a las mismas tres grafías: gitlab_interactive quita los cuatro flujos guiados, interactive.issue_create (o su herramienta en las superficies meta e individual, gitlab_interactive_issue_create) uno de ellos, y discover_project.resolve (o gitlab_discover_project) el descubrimiento de proyectos. Una entrada que no nombra nada se registra en WARN en lugar de rechazarse, porque una misma configuración se suele reutilizar entre tiers
GITLAB_MCP_IGNORE_SCOPESfalseBooleanoAmbos--ignore-scopesRegistra todas las herramientas que permite el tier, sean cuales sean los scopes del token. Los scopes se siguen leyendo, así que un token por debajo de read_api se sigue rechazando, y la concesión de un token de grano fino sigue decidiendo lo que se le muestra
GITLAB_MCP_CLIENT_COMPATautooff (sin distinguir mayúsculas) lo desactiva; cualquier otro valor significa autoAmbos--client-compat (ambos)En auto, una sesión que se identifica como OpenAI Codex recibe la priority fraccionaria de sus anotaciones redondeada a 0 o 1, porque las compilaciones incluidas en ChatGPT.app rechazan una fracción (Perfiles de compatibilidad por cliente). Es una desviación deliberada de la especificación
GITLAB_MCP_DESCRIPTION_SUBSTITUTIONSVacíoPares old=new separados por comas y aplicados en orden; una barra invertida escapa \, \= \\. Como mucho 32 pares, 256 bytes por mitadAmbos--description-substitutions (ambos)Reescribe las descripciones y títulos listados de herramientas, prompts, recursos y plantillas de recursos para validadores estrictos de pasarelas MCP, nunca nombres, URIs, valores de enum ni resultados de herramientas. Un old vacío o un escape desconocido impiden el arranque. Una reescritura que haría crecer una cadena por encima del doble de su longitud, o de 512 bytes más cuando eso es mayor, deja esa cadena como estaba. Una lista activa se anuncia una vez en WARN
GITLAB_MCP_YOLO_MODEfalse1, true, yes (sin distinguir mayúsculas) son verdadero; cualquier otra cosa es falsoAmbos--yolo-mode (ambos)En todas las superficies, deja que una acción destructiva, como un borrado, se ejecute sin confirmación: sin pregunta a un cliente que admite elicitación, sin rechazo para uno que no puede preguntar, y sin necesidad de confirm: true en la superficie dinámica por defecto (Acciones destructivas). Si está definida, decide ella, así que --yolo-mode=false anula un AUTOPILOT=true heredado
AUTOPILOTSin definirComo GITLAB_MCP_YOLO_MODEAmbosNingunoUn alias que fijan otras herramientas de agentes, que solo se consulta cuando GITLAB_MCP_YOLO_MODE está vacía. Sigue sin prefijo a propósito y nunca genera aviso
GITLAB_MCP_UPLOAD_MAX_FILE_SIZE2GBTamaño, positivo, como mucho 1 TBAmbos--upload-max-file-size (ambos)El mayor fichero que acepta una herramienta de subida o de lectura de ficheros. Un servidor stdio rechaza al arrancar un valor no válido o demasiado grande; el modo HTTP avisa y usa el valor predeterminado, o el máximo de 1 TB
GITLAB_MCP_ACTION_TIMEOUT65mDuración; 0 lo desactiva; como mucho 24hAmbos--action-timeoutCancela una acción que sigue en marcha pasado este tiempo. El valor predeterminado está por encima de la espera más larga que ofrece cualquier acción (la espera de un pipeline se limita a una hora), y también termina una subida o descarga de fichero que siga en marcha al llegar al límite, así que súbelo para ficheros demasiado grandes para moverse en ese tiempo

Estas tres amplían dónde puede tocar una herramienta la máquina en la que corre el servidor. El directorio de trabajo, salvo que sea la raíz de un sistema de ficheros o exactamente tu directorio personal, y el directorio temporal del sistema operativo están siempre permitidos. Una ruta se resuelve a través de todos sus enlaces simbólicos antes de comprobarla, y un directorio listado que no existe se omite con un WARN. Solo se aplican a un servidor stdio: el modo HTTP rechaza toda ruta local.

VariablePredeterminadoAceptaTransporteFlagQué hace
GITLAB_MCP_ALLOWED_UPLOAD_DIRSVacíoLista de directoriosstdioNingunoMás directorios desde los que una herramienta puede leer un fichero local: toda entrada file_path y directory_path
GITLAB_MCP_ALLOWED_DOWNLOAD_DIRSVacíoLista de directoriosstdioNingunoMás directorios en los que una herramienta puede escribir una descarga (output_path). El destino se vuelve a comprobar cuando ya existen sus directorios padre, y el fichero se escribe a su lado con un nombre temporal y solo se renombra sobre él cuando está completo, así que una descarga fallida o cancelada deja output_path como estaba
GITLAB_MCP_ALLOWED_IMPORT_DIRSVacíoLista de directoriosstdioNingunoMás directorios desde los que se puede leer un archivo de importación de proyecto o de grupo. El archivo debe ser un fichero .tar.gz regular y, fuera de Windows, sin permiso de escritura para el grupo ni para otros
VariablePredeterminadoAceptaTransporteFlagQué hace
GITLAB_MCP_STDIO_MAX_LINE_BYTES4194304 (4 MiB)Un número positivo de bytes, sin máximostdioNingunoEl mensaje stdio más largo que se ensambla. Una línea más larga se rechaza y se responde en lugar de acumularse, así que un cliente no puede hacer crecer el proceso enviando una. El valor predeterminado coincide con el límite de cuerpo HTTP del propio SDK, así que ambos transportes rechazan los mismos mensajes; súbelo solo para un cliente que incrusta cargas base64 grandes. Un valor no interpretable o no positivo avisa y conserva el predeterminado, porque un número mal escrito no debería tumbar al cliente junto con el servidor
GITLAB_MCP_MAX_LISTEN_STREAMS64Un entero no negativo; 0 quita el techoAmbosNingunoCuántos streams subscriptions/listen puede mantener abiertos una credencial. Un listen es una petición que el cliente deja abierta, medida en torno a un descriptor de fichero y entre 55 y 100 KB de memoria por stream, y un cliente real abre unos pocos. 0 quita ese techo y nada más: una credencial con un stream abierto sigue contando como ocupada y se mantiene en el pool. Un segundo techo de 512 por proceso no es configurable, porque el primero se multiplica por tantos tokens como tenga quien llama. Un valor no válido avisa y conserva 64
GITLAB_MCP_LOG_LEVELinfodebug, info, warn (o warning), error, sin distinguir mayúsculas; cualquier otra cosa significa infoAmbos--log-level (ambos)Nivel de detalle del log JSON que el servidor escribe en stderr
GITLAB_MCP_PPROF_ADDRVacíohost:puerto cuyo host es localhost o una dirección de loopback (127.0.0.1:6060, [::1]:6060)Ambos--pprof-addr (ambos)Sirve los handlers de profiling de Go bajo /debug/pprof/ en un listener propio, que arranca antes que el transporte y se detiene con el proceso. Cualquier otro host, o ninguno, impide el arranque: un perfil del heap es una copia de la memoria del proceso y los handlers no piden credencial. Vacío no sirve nada
GITLAB_MCP_ENV_FILEVacíoUna ruta a un fichero dotenv, preferiblemente absolutaAmbos--env-file (ambos)Un fichero dotenv que cargar además del fichero personal. Consulta Ficheros dotenv
VariablePredeterminadoAceptaTransporteFlagQué hace
GITLAB_MCP_MAX_HTTP_CLIENTS100Un entero positivo, como mucho 10000HTTP; stdio la valida--max-http-clientsCuántas entradas (token, URL de GitLab) mantiene el pool. Acota entradas, no las llamadas ni las sesiones que contienen: esas las acota el proceso por su límite de descriptores (192 llamadas retenidas y 96 sesiones con estado con un límite duro de 1024), y nada lo configura (Dimensionado)
GITLAB_MCP_SESSION_TIMEOUT30mUna duración positiva, como mucho 24h. La variable rechaza 0, que el flag sí aceptaHTTP; stdio la valida--session-timeoutTiempo de inactividad de una sesión MCP con estado, así que solo con --stateless=false: con el transporte sin estado predeterminado, la sesión de cada POST termina con su respuesta. Una sesión que ningún cliente borra ocupa uno de los huecos de sesión del proceso hasta que caduca
GITLAB_MCP_POOL_IDLE_TIMEOUT1hDuración; 0 lo desactiva; como mucho 24hHTTP; stdio la valida--pool-idle-timeoutRecupera la entrada del pool de una credencial tras este tiempo sin uso. Una entrada con una suscripción viva nunca está inactiva según esta medida
GITLAB_MCP_SESSION_REVALIDATE_INTERVAL15mDuración; 0 detiene la comprobación periódica; como mucho 24hHTTP; stdio la valida--revalidate-intervalCada cuánto se vuelve a comprobar cada credencial del pool. Con 0, una entrada cuya credencial tiene más de una hora se reconstruye igualmente, lo que la vuelve a comprobar. Fíjate en el nombre más corto del flag
GITLAB_MCP_DRAIN_DELAY0Duración, como mucho 5mHTTP; stdio la valida--drain-delayTras SIGTERM, mantiene abierto el listener y responde a /health con 503 draining durante este tiempo antes de cerrarlo, para que un balanceador que consulta /health saque antes la instancia. Ponlo al menos en un intervalo de sondeo; 0 cierra de inmediato
VariablePredeterminadoAceptaTransporteFlagQué hace
GITLAB_MCP_AUTH_MODElegacylegacy, oauth, en minúsculasHTTP; stdio la valida--auth-modelegacy acepta un token por petición en PRIVATE-TOKEN o Authorization: Bearer. oauth solo acepta un token bearer, lo verifica contra GitLab y publica metadatos de recurso protegido RFC 9728; exige GITLAB_MCP_PUBLIC_URL y una instancia https (Servidor HTTP)
GITLAB_MCP_PUBLIC_URLVacíoUna URL absoluta https://host[:puerto][/ruta] sin barra final ni fragmento; http solo para localhost, 127.0.0.1 o ::1HTTP; stdio la valida en oauth--public-urlLa dirección accesible desde fuera del despliegue. Obligatoria con oauth, donde es el identificador de recurso RFC 9728; en modo legacy es opcional, y su origen es de confianza para peticiones cross-origin del navegador
GITLAB_MCP_TRUSTED_ORIGINSVacíoLista de orígenes absolutos (esquema://host[:puerto]), o *HTTP--trusted-originsOrígenes a los que se permite hacer peticiones cross-origin desde el navegador. Vacía, rechaza todo POST cross-origin del navegador salvo el del origen de GITLAB_MCP_PUBLIC_URL, que es de confianza en cualquier caso; * acepta cualquier origen y desactiva la protección (Protección cross-origin)
GITLAB_MCP_OAUTH_CACHE_TTL15mDuración de 1m a 2hHTTP; stdio la valida--oauth-cache-ttlCuánto tiempo se reutiliza una identidad OAuth verificada. La caché guarda como mucho 10000 identidades sea cual sea la duración y, para hacer sitio, descarta una caducada o, si no hay ninguna, la que lleva más tiempo sin usarse; a la vez se ejecutan como mucho 16 verificaciones, y ninguna de las dos cifras es configurable (La caché de identidades del servidor)
GITLAB_MCP_OAUTH_CLIENT_UIDVacíoLista de uids de aplicaciones OAuth de GitLabHTTP--oauth-client-uidSolo admite tokens emitidos para estas aplicaciones. Vacía, admite cualquier credencial que acepte la instancia; definida, rechaza los tokens de acceso personal, que no pertenecen a ninguna aplicación. GitLab no publica vinculación de audiencia, así que esta es la comprobación de destinatario disponible (ADR-0019, Admitir solo tu propia aplicación)

Límites de frecuencia y presupuestos de autenticación

Sección titulada «Límites de frecuencia y presupuestos de autenticación»
VariablePredeterminadoAceptaTransporteFlagQué hace
GITLAB_MCP_RATE_LIMIT_RPS0 en stdio, 10 en modo HTTPUn número no negativo, como mucho 1000; 0 lo desactivaAmbos--rate-limit-rpsLímite por credencial, en peticiones por segundo, de toda llamada que llega a GitLab (tools/call, resources/read, resources/subscribe, subscriptions/listen, prompts/get), más completion/complete en un bucket propio con diez veces la tasa y el burst, y tools/list en un bucket propio que se rellena diez veces más despacio. Un listado se cobra además, en las herramientas que lleva, a un bucket que comparte todo el proceso (3000 por segundo, 48000 disponibles, no configurable). 0 los apaga todos. En stdio esta variable es el único interruptor (Limitar la frecuencia de invocación de herramientas)
GITLAB_MCP_RATE_LIMIT_BURST40Un entero de 0 a 10000Ambos--rate-limit-burstEl tamaño del bucket mientras el límite está activo. Con el limitador activo, una ráfaga menor que 1 impide el arranque en los dos transportes
GITLAB_MCP_AUTH_FAILURE_LIMIT10Un entero de 0 a 100000; 0 lo desactivaHTTP; stdio la valida--auth-failure-limitAutenticaciones fallidas que puede producir una dirección dentro de la ventana de fallos antes de quedar bloqueada. 0 apaga este presupuesto en lugar de bloquear al primer fallo (Presupuestos de autenticación)
GITLAB_MCP_AUTH_FAILURE_WINDOW1mDuración; 0 lo desactiva; como mucho 24hHTTP; stdio la valida--auth-failure-windowLa ventana en la que cuenta el presupuesto de fallos, y el paso con el que se construye la escalada de credenciales distintas: una ventana, después diez, después sesenta. 0 apaga también el presupuesto de credenciales distintas
GITLAB_MCP_AUTH_DISTINCT_TOKEN_LIMIT50Un entero de 0 a 100000; 0 lo desactivaHTTP; stdio la valida--auth-distinct-token-limitCredenciales distintas que una dirección puede ver rechazadas dentro de la ventana de credenciales distintas antes de quedar bloqueada, cada vez durante más tiempo. Una persona tiene un token y una flota tras un NAT tiene uno por máquina, así que este recuento solo lo produce un ataque
GITLAB_MCP_AUTH_DISTINCT_TOKEN_WINDOW10mDuración; 0 lo desactiva; como mucho 24hHTTP; stdio la valida--auth-distinct-token-windowLa ventana en la que cuenta el presupuesto de credenciales distintas

La telemetría está desactivada por defecto y solo va a un colector que configures tú; la página de OpenTelemetry explica qué registra y cómo enviarla.

VariablePredeterminadoAceptaTransporteFlagQué hace
GITLAB_MCP_TELEMETRYfalsetrue o false, sin distinguir mayúsculas; cualquier otra cosa avisa y cuenta como falsoAmbos--telemetry (ambos)Exporta trazas, métricas y registros por OTLP. OTEL_SDK_DISABLED=true lo veta
GITLAB_MCP_TELEMETRY_IDENTITYnonenone, pseudonymous, full, sin distinguir mayúsculasAmbos--telemetry-identity (ambos)Qué registra la telemetría sobre quién hizo una llamada: nadie, un resumen con clave que correlaciona las llamadas de quien llama sin nombrarlo, o el id y el nombre de usuario de GitLab. La identidad nunca llega a una métrica. Un valor no reconocido se registra en ERROR, y no se registra nada sobre quién llama (Registrar quién hizo la llamada)
GITLAB_MCP_TELEMETRY_IDENTITY_KEYVacíoCualquier secretoAmbosNinguno, a propósitoEl secreto del que la política pseudonymous deriva sus claves (HKDF-SHA256). Vacío genera uno por proceso, así que un resumen solo significa algo dentro de un proceso; defínelo cuando varias réplicas deban coincidir o un recuento tenga que sobrevivir a un reinicio, y mantenlo lejos de donde acabe la telemetría. No tiene flag porque los argumentos de un proceso se pueden leer a través de /proc
GITLAB_MCP_TELEMETRY_IDENTITY_ROTATIONVacíoDuración; vacío o 0 conserva la clave toda la vida del proceso; como mucho 30 días (720h)Ambos--telemetry-identity-rotation (ambos)Cuánto vive una clave generada. Se ignora, con un WARN, cuando está definida GITLAB_MCP_TELEMETRY_IDENTITY_KEY. Un valor no interpretable o fuera de rango se registra en ERROR, y no se registra nada sobre quién llama
GITLAB_MCP_TELEMETRY_TOOL_NAMEautoauto, on, off, sin distinguir mayúsculas; cualquier otra cosa se registra en ERROR y se lee como autoAmbos--telemetry-tool-name (ambos)Si gen_ai.tool.name es una dimensión de las métricas. auto la mantiene en las superficies dinámica y meta y la quita en individual, donde un millar de herramientas agotaría el límite de cardinalidad del SDK y plegaría la cola larga en una única serie de desbordamiento

Las variables estándar conservan sus nombres, y casi todas las leen los propios exportadores y el SDK de OpenTelemetry, nunca el código de este servidor. Unas pocas las lee también este servidor, por el motivo de la última columna.

VariableLa leeQué hace este servidor con ella
OTEL_SDK_DISABLEDSolo este servidortrue (sin distinguir mayúsculas) veta la telemetría aunque la pidan GITLAB_MCP_TELEMETRY o --telemetry. Nada en el SDK de Go implementa la variable, así que lo hace el servidor
OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_TRACES_PROTOCOL, ..._METRICS_PROTOCOL, ..._LOGS_PROTOCOLEste servidorElige el exportador de cada señal, primero la variable propia de la señal: http/protobuf (el predeterminado, también escrito http) o grpc. http/json y cualquier otra cosa detienen la telemetría al arrancar con una línea ERROR, y el servidor sigue sirviendo sin ella
OTEL_EXPORTER_OTLP_ENDPOINT y sus formas por señalLos exportadores; también este servidorSe nombra en la línea de arranque y en la server card, sin el usuario ni la contraseña que lleve, y se contrasta con las cabeceras para el aviso de texto plano
OTEL_EXPORTER_OTLP_HEADERS y sus formas por señalLos exportadores; también este servidorUna credencial del colector: el servidor avisa una vez cuando una cruzaría la red en claro hacia otro host, y la elimina de sus propias líneas de log (Autenticarse ante tu colector)
OTEL_EXPORTER_OTLP_INSECURE y sus formas por señalLos exportadores; también este servidorSolo se lee para decidir qué señales nombra ese aviso, porque los exportadores de trazas y métricas de Go le dejan anular un endpoint https
OTEL_EXPORTER_OTLP_CERTIFICATE, ..._CLIENT_CERTIFICATE, ..._CLIENT_KEY y sus formas por señalLos exportadores; este servidor las comprueba antesUn fichero de CA que no se puede leer o que no contiene ningún certificado, o un certificado de cliente sin su clave bajo el mismo prefijo, detiene la telemetría al arrancar con un ERROR que nombra la variable, en lugar de dejar que los exportadores recurran a otra cosa en silencio
OTEL_SERVICE_NAME, OTEL_RESOURCE_ATTRIBUTESEl SDK; este servidor las compruebaCuando ninguna nombra el servicio, el servidor se llama a sí mismo gitlab-mcp-server; cuando alguna lo hace, se mantiene ese nombre. Cualquier otro atributo de recurso pasa sin tocar
OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMITEl SDK; este servidor comprueba si está definidaSin definir, el servidor limita cada valor de atributo de span a 4096 caracteres en lugar de dejarlo sin límite
OTEL_TRACES_SAMPLEREl SDK; este servidor comprueba si está definidaSin definir, el span HTTP ignora la petición de quien llama de no ser muestreado, así que quien llama de forma anónima no puede apagar el registro de su propio rechazo. Definida, decide el muestreador que elegiste
Cualquier otra variable OTEL_* (plazos, compresión, lotes, intervalos de exportación)Solo los exportadores y el SDKNada. Sus duraciones son milisegundos enteros

Otros dos grupos de variables los lee la biblioteca estándar de Go, no código escrito por este proyecto:

  • Las variables de proxy HTTPS_PROXY, HTTP_PROXY y NO_PROXY (y sus grafías en minúsculas), leídas una vez por proceso para las conexiones con GitLab. Tras un proxy la conexión es con el proxy, y el destino que hay detrás se juzga como describe Conexiones salientes; los hosts que deban alcanzarse directamente van en NO_PROXY.
  • SSL_CERT_FILE en Linux y en los demás sistemas Unix salvo macOS, que indica a Go un paquete de certificados raíz. Sustituye las raíces predeterminadas para todo el proceso, así que dale un paquete y no un único certificado. Es la respuesta en contenedores a una CA privada, y no necesita GITLAB_MCP_SKIP_TLS_VERIFY.

Los ajustes que define este proyecto ganaron el prefijo GITLAB_MCP_ en la 2.8.0, porque un servidor stdio se ejecuta en la shell desde la que arrancó su cliente, junto a todas las demás herramientas de esa shell, y un nombre tan genérico como LOG_LEVEL o AUTH_MODE puede pertenecer ya a una de ellas. Las grafías antiguas respondieron junto a las nuevas hasta la 3.1.0, que las eliminó. Se retrasaron una versión a propósito: la 2.7.5 incluye un autoactualizador y la 3.0.0 no, así que un despliegue 2.7.5 se actualizó solo a la 3.0.0 sin que nadie leyera una nota de versión, y la 3.1.0 es la primera versión a la que nadie llega arrastrado.

Ya nada lee una grafía antigua. El servidor conoce la grafía antigua de 32 ajustes, y al arrancar, después de cargar los ficheros dotenv, busca cada una: el sufijo sin prefijo (LOG_LEVEL para GITLAB_MCP_LOG_LEVEL) o, para cinco de ellos, el nombre con prefijo GITLAB_ que tenían (GITLAB_TIER, GITLAB_READ_ONLY, GITLAB_SAFE_MODE, GITLAB_IGNORE_SCOPES, GITLAB_SKIP_TLS_VERIFY). YOLO_MODE es la grafía antigua de GITLAB_MCP_YOLO_MODE. Los otros 26 nombres sin prefijo son ACTION_TIMEOUT, AUTH_DISTINCT_TOKEN_LIMIT, AUTH_DISTINCT_TOKEN_WINDOW, AUTH_FAILURE_LIMIT, AUTH_FAILURE_WINDOW, AUTH_MODE, CAPABILITY_SURFACE, CLIENT_COMPAT, DRAIN_DELAY, EMBEDDED_RESOURCES, EXCLUDE_TOOLS, LOG_LEVEL, MAX_HTTP_CLIENTS, META_PARAM_SCHEMA, OAUTH_CACHE_TTL, OAUTH_CLIENT_UID, POOL_IDLE_TIMEOUT, PPROF_ADDR, PUBLIC_URL, RATE_LIMIT_BURST, RATE_LIMIT_RPS, SESSION_REVALIDATE_INTERVAL, SESSION_TIMEOUT, TOOL_SURFACE, TRUSTED_ORIGINS y UPLOAD_MAX_FILE_SIZE. Cada una que encuentra se informa en ambos transportes:

GITLAB_TIER is no longer read (removed in 3.1.0): rename it to GITLAB_MCP_TIER
Nombre antiguoQué pasa ahora
GITLAB_READ_ONLYImpide el arranque: la línea de arriba en ERROR, seguida de “and this deployment will not be started under a capability it did not ask for”, y estado de salida 1
GITLAB_SAFE_MODEImpide el arranque, del mismo modo
EXCLUDE_TOOLSImpide el arranque, del mismo modo. Es el único nombre sin prefijo de los tres y puede pertenecer a otra herramienta de la misma shell; el servidor no puede saberlo, así que renómbralo a GITLAB_MCP_EXCLUDE_TOOLS, o quítalo del entorno de este servidor
Los otros 29Una línea WARN, y el servidor arranca con el ajuste en su valor predeterminado

Los tres que impiden el arranque son la forma en que un operador retira parte de lo que sirve un despliegue, así que una versión que ignorase uno en silencio serviría escrituras, o las acciones que el operador quitó, en un despliegue que no pidió ninguna de las dos cosas. La comprobación mira el nombre y nunca su valor, así que GITLAB_READ_ONLY=false también lo impide, y un nombre definido en un fichero dotenv que carga el servidor cuenta igual que uno exportado en la shell. Como solo se leen nombres, un LOG_LEVEL sin prefijo que pertenezca a otra herramienta de la misma shell también se informa; solo genera un aviso.

Dos nombres se eliminaron antes, en la 3.0.0, y se ignoran sin decir nada: META_TOOLS (con su grafía GITLAB_MCP_META_TOOLS y el flag --meta-tools, que ahora es un flag desconocido), sustituido por GITLAB_MCP_TOOL_SURFACE; y GITLAB_ENTERPRISE, sustituido por GITLAB_MCP_TIER. A un despliegue que aún define GITLAB_ENTERPRISE se le detecta el tier, como a uno que no define nada.

Algunos nombres siguen sin prefijo a propósito: GITLAB_URL y GITLAB_TOKEN, la convención de GitLab, que define toda configuración existente; AUTOPILOT, una convención de otras herramientas de agentes; y OTEL_*, que pertenecen a la especificación de OpenTelemetry y que leen los propios exportadores, así que nunca verían una grafía con prefijo. Las variables MODELEVAL_*, GITLAB_MCP_TEST_INVENTORY_DIR y GITLAB_MCP_TEST_SNAPSHOT_PARITY configuran los arneses de pruebas y de evaluación de este repositorio; el servidor nunca las lee.

Además de su entorno, el servidor lee dos ficheros dotenv, en ambos transportes, antes de que nada lea la configuración:

  1. ~/.gitlab-mcp-server.env en tu directorio personal, si existe.
  2. El único fichero que nombre GITLAB_MCP_ENV_FILE, o --env-file, que fija lo mismo y gana a la variable.

Precedencia, de mayor a menor:

  1. Un flag pasado de forma explícita. En ambos transportes son --env-file, los siete flags que escriben su variable (--log-level, --client-compat, --upload-max-file-size, --yolo-mode, --description-substitutions, --allow-private-instances, --pprof-addr) y los cuatro flags de telemetría; en modo HTTP, todos los flags.
  2. El entorno del proceso, que es lo que pasó el cliente MCP o exportó la shell.
  3. El fichero que nombra GITLAB_MCP_ENV_FILE.
  4. El fichero personal.

Un fichero nunca sobrescribe una variable que ya está definida. Eso incluye una variable exportada vacía: oculta el valor del fichero, y después el servidor la lee como no definida.

GITLAB_MCP_ENV_FILE se resuelve una sola vez, desde el entorno del proceso, antes de cargar ningún fichero, así que un fichero que carga el servidor no puede nombrar a otro. Dale una ruta absoluta. Una relativa se resuelve contra el directorio de trabajo, que el cliente cambia con cada espacio de trabajo que abre, así que una línea relativa en una configuración de cliente a nivel de usuario nombra un fichero distinto en cada repositorio; el servidor avisa cuando ve una. La carga del fichero nombrado se anuncia en WARN con su ruta, y un fichero que no se puede leer también es un WARN, no un rechazo.

~/.gitlab-mcp-server.env
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
GITLAB_URL=https://gitlab.example.com
GITLAB_MCP_TOOL_SURFACE=dynamic
GITLAB_MCP_UPLOAD_MAX_FILE_SIZE=500MB
GITLAB_MCP_LOG_LEVEL=info

No subas nunca a un repositorio un fichero que contenga un token, y restríngelo a su propietario (chmod 600 en Linux y macOS).

El directorio de trabajo no es una fuente de configuración

Sección titulada «El directorio de trabajo no es una fuente de configuración»

Un .env en el directorio de trabajo no se carga. Un servidor stdio hereda su directorio de trabajo del cliente, y todo cliente que abre un espacio de trabajo lo fija en ese espacio, así que el fichero llega con un repositorio clonado o un archivo descomprimido, escrito por quien los escribió. Cuando ese fichero se cargaba el primero, dos líneas en un repositorio podían enviar tu token a otro host, desactivar la verificación de certificados para que nada se quejara, activar la telemetría hacia un colector de su elección y reescribir las descripciones de herramientas que lee el modelo, todo antes de cualquier llamada a una herramienta: la comprobación de arranque entregaba el token. Las variables que lo hacen posible son justo las que ningún cliente define, así que siempre estaban libres para el primer fichero encontrado.

Ahora un fichero dotenv configura el servidor solo cuando alguien lo puso donde el servidor mira o lo nombró. Estar en el directorio de trabajo no es una decisión que haya tomado nadie, que es la misma conclusión a la que llegaron safe.directory de Git, direnv allow de direnv y la confianza en el espacio de trabajo de VS Code.

El fichero se sigue buscando. Uno que existe y no está vacío se nombra en WARN con su ruta absoluta, el número de claves que quería definir y hasta diez de sus nombres, nunca sus valores, para que un fichero que dejó de surtir efecto aparezca en el log y no en una tarde de depuración. Para seguir usándolo, nómbralo por ruta absoluta en GITLAB_MCP_ENV_FILE: el fichero que nombra se carga a propósito, aunque sea ese mismo .env.

En modo HTTP, la configuración se resuelve en tres capas, de mayor a menor:

  1. Un flag pasado de forma explícita en la línea de comandos. Pasar un flag cuyo valor coincide con el predeterminado también cuenta como elegirlo: --rate-limit-rps=10 gana a GITLAB_MCP_RATE_LIMIT_RPS=2.
  2. La variable con el mismo significado, cuando no se pasó su flag.
  3. El valor predeterminado.

Una variable solo se tiene en cuenta cuando está definida y no está vacía, y pasa por el mismo intérprete y los mismos límites que en stdio, así que un valor no válido detiene el arranque con loading environment configuration: ... en lugar de recurrir en silencio a otro valor. Las filas de arriba que avisan en lugar de eso lo dicen.

Un servidor stdio lee las variables y, de los flags, solo --http, --transport, --env-file, los siete que escriben una variable y los cuatro de telemetría. Nada de esta tabla se puede alcanzar desde una petición: un cliente solo controla su propio token y, donde el despliegue lo permite, la cabecera GITLAB-URL, y una cabecera de petición con el nombre de cualquier otro ajuste se ignora y se registra (Servidor HTTP).

VariableFlagNotas
GITLAB_MCP_ENV_FILE--env-fileAmbos transportes; gana el flag
Ninguna--http, --transportEl transporte solo se elige en la línea de comandos
GITLAB_URL--gitlab-urlUn valor separado por comas equivale a la lista de un flag repetido
Ninguna--allow-any-gitlab-urlSin variable a propósito: deja que quien llama elija el host al que se envía su token, así que pertenece a la línea de comandos que arrancó el proceso
GITLAB_TOKENNingunoSolo stdio. En modo HTTP cada petición trae su propio token
GITLAB_MCP_SKIP_TLS_VERIFY--skip-tls-verify
GITLAB_MCP_ALLOW_PRIVATE_INSTANCES--allow-private-instancesAmbos transportes; el flag escribe la variable
GITLAB_MCP_TOOL_SURFACE--tool-surface
GITLAB_MCP_CAPABILITY_SURFACE--capability-surface
GITLAB_MCP_META_PARAM_SCHEMA--meta-param-schema
GITLAB_MCP_TIER--tierSin ninguno de los dos, el tier se detecta por credencial
GITLAB_MCP_READ_ONLY--read-only
GITLAB_MCP_SAFE_MODE--safe-mode
GITLAB_MCP_EMBEDDED_RESOURCES--embedded-resources
GITLAB_MCP_EXCLUDE_TOOLS--exclude-tools
GITLAB_MCP_IGNORE_SCOPES--ignore-scopes
GITLAB_MCP_CLIENT_COMPAT--client-compatAmbos transportes; el flag escribe la variable
GITLAB_MCP_DESCRIPTION_SUBSTITUTIONS--description-substitutionsAmbos transportes; el flag escribe la variable
GITLAB_MCP_YOLO_MODE--yolo-modeAmbos transportes; el flag escribe la variable
AUTOPILOTNingunoAmbos transportes; pierde frente a una GITLAB_MCP_YOLO_MODE no vacía
GITLAB_MCP_UPLOAD_MAX_FILE_SIZE--upload-max-file-sizeAmbos transportes; el flag escribe la variable
GITLAB_MCP_ACTION_TIMEOUT--action-timeoutAmbos transportes; stdio solo lee la variable
GITLAB_MCP_ALLOWED_UPLOAD_DIRS, GITLAB_MCP_ALLOWED_DOWNLOAD_DIRS, GITLAB_MCP_ALLOWED_IMPORT_DIRSNingunoSolo stdio: el modo HTTP rechaza toda ruta local digan lo que digan
GITLAB_MCP_STDIO_MAX_LINE_BYTESNingunoSolo stdio. Su equivalente HTTP es --max-request-body-bytes, que no tiene variable
GITLAB_MCP_MAX_LISTEN_STREAMSNingunoAmbos transportes; solo en el entorno
GITLAB_MCP_LOG_LEVEL--log-levelAmbos transportes; el flag escribe la variable
GITLAB_MCP_PPROF_ADDR--pprof-addrAmbos transportes; el flag escribe la variable
GITLAB_MCP_MAX_HTTP_CLIENTS--max-http-clients
GITLAB_MCP_SESSION_TIMEOUT--session-timeoutSolo el flag acepta 0
GITLAB_MCP_POOL_IDLE_TIMEOUT--pool-idle-timeout
GITLAB_MCP_SESSION_REVALIDATE_INTERVAL--revalidate-intervalLa única pareja cuyos nombres difieren
GITLAB_MCP_DRAIN_DELAY--drain-delay
GITLAB_MCP_AUTH_MODE--auth-mode
GITLAB_MCP_PUBLIC_URL--public-url
GITLAB_MCP_TRUSTED_ORIGINS--trusted-origins
GITLAB_MCP_OAUTH_CACHE_TTL--oauth-cache-ttl
GITLAB_MCP_OAUTH_CLIENT_UID--oauth-client-uid
Ninguna--resource-documentation, --resource-policy-uri, --resource-tos-uriLos enlaces de los metadatos RFC 9728; solo flags
GITLAB_MCP_RATE_LIMIT_RPS--rate-limit-rpsLos valores predeterminados difieren: 10 en modo HTTP, 0 en stdio, que ignora el flag
GITLAB_MCP_RATE_LIMIT_BURST--rate-limit-burst
GITLAB_MCP_AUTH_FAILURE_LIMIT--auth-failure-limit
GITLAB_MCP_AUTH_FAILURE_WINDOW--auth-failure-window
GITLAB_MCP_AUTH_DISTINCT_TOKEN_LIMIT--auth-distinct-token-limit
GITLAB_MCP_AUTH_DISTINCT_TOKEN_WINDOW--auth-distinct-token-window
Ninguna--trusted-proxies, --trusted-proxy-headerSolo flags, y cada uno exige el otro
Ninguna--http-addr, --http-socket-mode, --tls-cert, --tls-keyEl listener; solo flags
Ninguna--stateless, --json-response, --max-request-body-bytes, --http-idle-timeoutEl transporte HTTP streamable; solo flags
GITLAB_MCP_TELEMETRY--telemetryAmbos transportes
GITLAB_MCP_TELEMETRY_IDENTITY--telemetry-identityAmbos transportes
GITLAB_MCP_TELEMETRY_IDENTITY_KEYNingunoSolo en el entorno, a propósito: los argumentos de un proceso se pueden leer a través de /proc
GITLAB_MCP_TELEMETRY_IDENTITY_ROTATION--telemetry-identity-rotationAmbos transportes
GITLAB_MCP_TELEMETRY_TOOL_NAME--telemetry-tool-nameAmbos transportes

Los flags que se ejecutan una vez y terminan (--tool-search, --probe, --shutdown, --version, -h y --help) no tienen variable; --tool-search lee GITLAB_MCP_TOOL_SURFACE, GITLAB_MCP_TIER y los ficheros dotenv, así que un despliegue stdio busca en lo que sirve. La referencia de la línea de comandos cubre cada flag.

Un servidor al que se llega por HTTP rechaza toda ruta local que nombre quien llama: un file_path o un directory_path que leer, un output_path en el que escribir y un archivo de importación local. El llamante no tiene ficheros en la máquina en la que corre el servidor, así que cualquier ruta que pueda nombrar pertenece a otra persona. El rechazo no depende de las tres variables GITLAB_MCP_ALLOWED_*_DIRS, que no tienen efecto en modo HTTP, y sigue al transporte que el proceso sirve de verdad, --transport=auto incluido.

El error lo dice y, para file_path, nombra la entrada que lleva los bytes en la propia petición:

file_path is disabled when the server is reached over HTTP: the file would be read from the server's own disk, not yours; send the bytes with content_base64 instead

content_base64 es la forma remota de una subida, y uno de los motivos por los que el límite del cuerpo de petición HTTP se queda por defecto en los 4 MiB del SDK.