Ir al contenido

Despliegue HTTP

Por stdio, cada cliente MCP arranca su propio arcane-mcp y nada escucha en la red. Ejecútalo por HTTP cuando el cliente no pueda arrancar un proceso local (conectores remotos, clientes web), cuando varias personas deban compartir un servidor o cuando el servidor deba vivir junto a Arcane y no en cada portátil. Todos los ajustes que se nombran aquí se describen en Configuración; el modelo de amenazas está en Seguridad del despliegue, y los errores con los que te puedes encontrar, en Solución de problemas.

  • Autentica. Define ARCANE_MCP_HTTP_TOKEN o usa ARCANE_MCP_HTTP_AUTH=apikey. Sin ninguno de los dos, cualquiera que llegue al puerto usa el servidor.
  • Cifra. El token y las claves de Arcane viajan en las cabeceras. Termina TLS en un proxy inverso o dale al servidor un certificado con ARCANE_MCP_HTTP_TLS_CERT y ARCANE_MCP_HTTP_TLS_KEY (TLS en el propio servidor). HTTP sin cifrar es para loopback, un socket unix o una red que solo compartan el proxy y el servidor: en cualquier otra dirección TCP el servidor avisa al arrancar, ARCANE_MCP_HTTP_ALLOW_PLAINTEXT=true declara que ese tramo se cifra delante de él y ARCANE_MCP_HTTP_ALLOW_PLAINTEXT=false hace que se niegue a arrancar (consulta HTTP sin cifrar y el modo endurecido).
  • Nombra los hosts. Define ARCANE_MCP_HTTP_ALLOWED_HOSTS con los nombres que usan los clientes.
  • Háblale del proxy. Define ARCANE_MCP_HTTP_TRUSTED_PROXIES y ARCANE_MCP_HTTP_TRUSTED_PROXY_HEADER, o todos los clientes compartirán el cupo de autenticaciones fallidas del proxy.
  • Decide quién actúa en Arcane. En un servidor compartido, deja sin definir ARCANE_API_KEY, ARCANE_USERNAME y ARCANE_PASSWORD, para que cada usuario traiga su propia clave y actúe con sus propios permisos.
token (predeterminado)apikey
El cliente envíaAuthorization: Bearer <ARCANE_MCP_HTTP_TOKEN> y su clave de Arcane en X-Arcane-API-KeyAuthorization: Bearer <su clave de API de Arcane>
Va bien conClientes que pueden definir cabeceras propias (Claude Code, VS Code, Cursor y otros; consulta Configuración de clientes)Clientes que solo pueden definir Authorization: conectores remotos, mcp-remote
Credencial del servidor (ARCANE_API_KEY, inicio de sesión)Permitida: un cliente sin X-Arcane-API-Key, o con la propia clave del servidor en ella, actúa con esa clave y con el inicio de sesión. Un cliente con otra clave actúa solo con ella y nunca recibe el inicio de sesiónRechazada al arrancar
Lo que cuesta a Arcane cada peticiónNada másUn GET /api/auth/me por clave cada ARCANE_MCP_HTTP_AUTH_CACHE_TTL (5 minutos)

Los dos modos cuentan las autenticaciones fallidas por dirección de cliente y pueden limitar el ritmo de cada clave (ARCANE_MCP_HTTP_RATE_LIMIT_RPS). Consulta Autenticación HTTP.

Añade un servicio al proyecto de Compose que ejecuta Arcane: así el servidor llega a Arcane por el nombre de su servicio en la red del proyecto y no hace falta publicar el puerto de Arcane para él:

services:
arcane:
image: ghcr.io/getarcaneapp/manager:v2.17.2
# ... tu servicio de Arcane tal como está hoy
arcane-mcp:
image: ghcr.io/jmrplens/arcane-mcp:latest # fija una versión en producción
restart: unless-stopped
environment:
ARCANE_URL: http://arcane:3552
ARCANE_MCP_HTTP_ADDR: ":8080"
ARCANE_MCP_HTTP_ALLOW_PLAINTEXT: "true"
ARCANE_MCP_HTTP_TOKEN: ${ARCANE_MCP_HTTP_TOKEN:?set it in .env}
ARCANE_MCP_HTTP_ALLOWED_HOSTS: localhost,127.0.0.1
ports:
- "127.0.0.1:8080:8080"
depends_on:
- arcane

Pon el token en el .env del proyecto (ARCANE_MCP_HTTP_TOKEN= seguido de la salida de openssl rand -hex 32). Los clientes de la misma máquina se conectan a http://127.0.0.1:8080/mcp con Authorization: Bearer <token> y su propia clave de Arcane en X-Arcane-API-Key.

  • ARCANE_URL usa el nombre del servicio y el puerto de Arcane dentro de la red (3552 por defecto); no hace falta TLS en una red que solo comparten los contenedores del proyecto.
  • No hay ARCANE_API_KEY, así que un cliente que no envía clave se rechaza con 400. Añade una solo si todos los clientes de este servidor deben actuar como el mismo usuario de Arcane.
  • ARCANE_MCP_HTTP_ALLOW_PLAINTEXT: "true": dentro de su contenedor el servidor escucha en todas las interfaces (:8080), así que sin él avisa al arrancar de que sirve HTTP sin cifrar a la red. Aquí el puerto se publica solo en el loopback del anfitrión y el otro tramo es la red del propio proyecto, así que el valor lo declara. Los ejemplos detrás de un proxy, más abajo, lo definen por la misma razón: el proxy termina TLS.
  • El puerto se publica solo en loopback. Expón el servidor a otros mediante un proxy inverso (más abajo) o con TLS en el propio servidor, no publicando HTTP sin cifrar en 0.0.0.0:8080.
  • La imagen tiene HEALTHCHECK (arcane-mcp --probe), así que docker compose ps muestra el servicio como healthy en cuanto responde /healthz; no hace falta una entrada healthcheck:. Consulta Estado, disponibilidad y parada.
  • Hasta que se publique la primera versión, construye la imagen desde el repositorio (docker build -t arcane-mcp .) y usa ese nombre.

El proxy termina TLS y reenvía /mcp al servidor. Lo que todo proxy tiene que hacer bien:

RequisitoPor qué
Pasar el Host del cliente, e incluirlo en ARCANE_MCP_HTTP_ALLOWED_HOSTSCon la lista definida, /mcp solo responde a los nombres que contiene (403 en otro caso). Traefik y Caddy pasan el Host; nginx necesita proxy_set_header Host $host
Sin búfer ni compresión en /mcpLas respuestas y las notificaciones del servidor viajan como flujo de eventos (text/event-stream). Traefik y Caddy lo reenvían según llega; nginx necesita proxy_buffering off. La compresión retiene los eventos
Plazos de respuesta de al menos ARCANE_MCP_ACTION_TIMEOUT (30 minutos)Una llamada puede durar eso, y el servidor no envía pings de mantenimiento, así que una llamada callada o el flujo de eventos inactivo de una sesión pasan minutos sin enviar un byte. nginx lo corta a los 60 segundos por defecto
Cuerpos de hasta ARCANE_MCP_HTTP_MAX_BODY_BYTES (16 MiB)Un fragmento de subida ocupa eso codificado en base64; el límite por defecto de nginx es 1 MiB
Pasar Authorization, X-Arcane-API-Key, X-Arcane-URL, Mcp-Session-Id y MCP-Protocol-VersionLos tres proxies de abajo pasan las cabeceras de la petición sin tocarlas
Identificar al cliente realPon en ARCANE_MCP_HTTP_TRUSTED_PROXIES la dirección del proxy tal como la ve el servidor (unix para un proxy en un socket unix) y en ARCANE_MCP_HTTP_TRUSTED_PROXY_HEADER la cabecera que rellena. La cabecera solo se cree si viene de un proxy listado, y se lee desde la derecha omitiendo los proxies de confianza
No añadir cabeceras CORSEl servidor responde él mismo a las comprobaciones previas del navegador para los orígenes de ARCANE_MCP_HTTP_TRUSTED_ORIGINS; con dos cabeceras Access-Control-Allow-Origin el navegador rechaza la respuesta
Encaminar solo /mcp/healthz y /readyz no piden credencial, y /readyz nombra las instancias de Arcane; resérvalos para tus propias sondas

Dale al proxy una dirección fija cuando comparta una red de Docker con el servidor, para que ARCANE_MCP_HTTP_TRUSTED_PROXIES lo nombre a él y a nada más: con un rango, cualquier otro contenedor de esa red podría escribir la cabecera y elegir a qué dirección se cargan sus fallos.

Con Traefik en el mismo proyecto de Compose, en una red donde tenga una dirección fija:

services:
arcane:
image: ghcr.io/getarcaneapp/manager:v2.17.2
# ... tu servicio de Arcane tal como está hoy
traefik:
image: traefik:v3.6
command:
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.websecure.address=:443
- --certificatesresolvers.letsencrypt.acme.tlschallenge=true
- --certificatesresolvers.letsencrypt.acme.email=admin@example.com
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
ports:
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- letsencrypt:/letsencrypt
networks:
edge:
ipv4_address: 172.30.0.2
arcane-mcp:
image: ghcr.io/jmrplens/arcane-mcp:latest
restart: unless-stopped
environment:
ARCANE_URL: http://arcane:3552
ARCANE_MCP_HTTP_ADDR: ":8080"
ARCANE_MCP_HTTP_ALLOW_PLAINTEXT: "true"
ARCANE_MCP_HTTP_AUTH: apikey
ARCANE_MCP_HTTP_ALLOWED_HOSTS: mcp.example.com
ARCANE_MCP_HTTP_TRUSTED_PROXIES: 172.30.0.2
ARCANE_MCP_HTTP_TRUSTED_PROXY_HEADER: X-Forwarded-For
networks: [edge, default]
labels:
- traefik.enable=true
- traefik.docker.network=edge
- traefik.http.routers.arcane-mcp.rule=Host(`mcp.example.com`) && Path(`/mcp`)
- traefik.http.routers.arcane-mcp.entrypoints=websecure
- traefik.http.routers.arcane-mcp.tls.certresolver=letsencrypt
- traefik.http.services.arcane-mcp.loadbalancer.server.port=8080
networks:
edge:
name: edge
ipam:
config:
- subnet: 172.30.0.0/24
ip_range: 172.30.0.128/25 # las direcciones dinámicas no tocan la .2
volumes:
letsencrypt:

Este ejemplo usa el modo apikey: cada usuario se conecta a https://mcp.example.com/mcp con su propia clave de API de Arcane como token Bearer, y no hay ningún secreto compartido que repartir.

  • name: edge mantiene el nombre de la red tal como está escrito; sin él, Compose le antepone el nombre del proyecto y traefik.docker.network=edge no coincide con nada (Traefik responde entonces 504).
  • ip_range aparta de la dirección de Traefik las que Docker reparte a otros contenedores; si no, un contenedor que arrancara antes podría quedársela.
  • Traefik sustituye el X-Forwarded-For que envíe el cliente por la dirección que ha visto, así que el servidor carga las autenticaciones fallidas al cliente real.
  • Traefik 3.5 (comprobado con la 3.5.6) no puede leer Docker Engine 29 (client version 1.24 is too old) y responde 404 a todas las rutas; la 3.6 sí puede.

Con Caddy en el mismo proyecto de Compose, también con una dirección fija:

services:
arcane:
image: ghcr.io/getarcaneapp/manager:v2.17.2
# ... tu servicio de Arcane tal como está hoy
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
networks:
default:
ipv4_address: 172.31.0.2
arcane-mcp:
image: ghcr.io/jmrplens/arcane-mcp:latest
restart: unless-stopped
environment:
ARCANE_URL: http://arcane:3552
ARCANE_MCP_HTTP_ADDR: ":8080"
ARCANE_MCP_HTTP_ALLOW_PLAINTEXT: "true"
ARCANE_MCP_HTTP_TOKEN: ${ARCANE_MCP_HTTP_TOKEN:?set it in .env}
ARCANE_MCP_HTTP_ALLOWED_HOSTS: mcp.example.com
ARCANE_MCP_HTTP_TRUSTED_PROXIES: 172.31.0.2
ARCANE_MCP_HTTP_TRUSTED_PROXY_HEADER: X-Forwarded-For
networks:
default:
ipam:
config:
- subnet: 172.31.0.0/24
ip_range: 172.31.0.128/25 # las direcciones dinámicas no tocan la .2
volumes:
caddy_data:

y el Caddyfile a su lado:

mcp.example.com {
handle /mcp {
reverse_proxy arcane-mcp:8080
}
handle {
respond 404
}
}

Caddy obtiene el certificado por su cuenta, reenvía los flujos de eventos según llegan y no tiene plazo de respuesta propio. No añadas encode a este sitio. Este ejemplo mantiene el modo token: los clientes envían el token y su propia clave de Arcane.

Cuando nginx se ejecuta en el host, el servidor puede escuchar en un socket unix en lugar de un puerto: en el host solo llegan a él los procesos que dejen pasar los permisos del socket, y no queda ningún puerto abierto. Ejecuta el binario como servicio, con un usuario de sistema propio:

Ventana de terminal
sudo useradd --system --no-create-home --shell /usr/sbin/nologin arcane-mcp

Después, con systemd:

/etc/systemd/system/arcane-mcp.service
[Unit]
Description=arcane-mcp (MCP server for Arcane)
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/arcane-mcp
EnvironmentFile=/etc/arcane-mcp/arcane-mcp.env
User=arcane-mcp
Group=www-data
RuntimeDirectory=arcane-mcp
RuntimeDirectoryMode=0750
Restart=on-failure
NoNewPrivileges=yes
[Install]
WantedBy=multi-user.target
Ventana de terminal
# /etc/arcane-mcp/arcane-mcp.env (modo 0600: puede contener un token)
ARCANE_URL=https://arcane.example.com
ARCANE_MCP_HTTP_ADDR=/run/arcane-mcp/mcp.sock
ARCANE_MCP_HTTP_AUTH=apikey
ARCANE_MCP_HTTP_ALLOWED_HOSTS=mcp.example.com
ARCANE_MCP_HTTP_TRUSTED_PROXIES=unix
ARCANE_MCP_HTTP_TRUSTED_PROXY_HEADER=X-Real-IP

Group= es el grupo con el que se ejecuta nginx (www-data en Debian y Ubuntu). El socket se crea con ARCANE_MCP_HTTP_SOCKET_MODE (0660) y pertenece al usuario del servicio y a ese grupo, así que nginx puede conectarse y los demás usuarios no; se borra cuando el servicio se detiene. Después, el sitio:

upstream mcp_backend {
server unix:/run/arcane-mcp/mcp.sock;
}
server {
listen 443 ssl;
http2 on;
server_name mcp.example.com;
ssl_certificate /etc/letsencrypt/live/mcp.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mcp.example.com/privkey.pem;
location = /mcp {
proxy_pass http://mcp_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Connection "";
# Las respuestas son flujos de eventos: reenvíalas según llegan.
proxy_buffering off;
gzip off;
# Una llamada puede pasar ARCANE_MCP_ACTION_TIMEOUT (30m) sin enviar un byte.
proxy_read_timeout 35m;
proxy_send_timeout 35m;
# El servidor acepta cuerpos de hasta ARCANE_MCP_HTTP_MAX_BODY_BYTES (16 MiB).
client_max_body_size 16m;
}
location / {
return 404;
}
}

Una conexión por socket no tiene dirección de cliente. ARCANE_MCP_HTTP_TRUSTED_PROXIES=unix le dice al servidor que se crea el X-Real-IP que nginx rellena con la dirección que ha visto; sin él, todos los clientes comparten un único cupo de fallos de autenticación con el nombre unix.

La escucha y los proxies de confianza deben casar, o todos los clientes compartirían en silencio un único cupo; el servidor se niega a arrancar con las dos combinaciones que lo provocarían:

ARCANE_MCP_HTTP_ADDRARCANE_MCP_HTTP_TRUSTED_PROXIESResultado
socket unixunix (con o sin direcciones)Arranca; la cabecera del proxy local nombra a cada cliente
socket unixsin definirArranca; todos los clientes comparten el cupo unix
socket unixdirecciones, sin unixRechazado al arrancar: quien llega por el socket no tiene dirección, así que la cabecera nunca se creería
dirección TCPdireccionesArranca; la cabecera se cree si viene de esas direcciones
dirección TCPunix entre las entradasRechazado al arrancar: unix no se fía de nadie en TCP

Con Caddy en el host funciona igual (reverse_proxy unix//run/arcane-mcp/mcp.sock y ARCANE_MCP_HTTP_TRUSTED_PROXY_HEADER=X-Forwarded-For). En contenedores, el socket va en un volumen que montan los dos; la imagen se ejecuta con el usuario y el grupo 65532, así que dale al servidor un grupo que también tenga el proxy (user: "65532:<id del grupo del proxy>") o un ARCANE_MCP_HTTP_SOCKET_MODE más amplio.

Sin proxy, el servidor puede hablar HTTPS él mismo:

services:
arcane:
image: ghcr.io/getarcaneapp/manager:v2.17.2
# ... tu servicio de Arcane tal como está hoy
arcane-mcp:
image: ghcr.io/jmrplens/arcane-mcp:latest
restart: unless-stopped
environment:
ARCANE_URL: http://arcane:3552
ARCANE_MCP_HTTP_ADDR: ":8443"
ARCANE_MCP_HTTP_AUTH: apikey
ARCANE_MCP_HTTP_TLS_CERT: /certs/fullchain.pem
ARCANE_MCP_HTTP_TLS_KEY: /certs/privkey.pem
ARCANE_MCP_HTTP_ALLOWED_HOSTS: mcp.example.com
volumes:
- /etc/arcane-mcp/certs:/certs:ro # un directorio, para que se vean los ficheros renovados
ports:
- "8443:8443"

Los clientes se conectan a https://mcp.example.com:8443/mcp.

  • TLS 1.2 o posterior, con el certificado PEM (la cadena completa) y la clave que nombran los dos ajustes. Un par que falta, que no se puede leer o que no casa detiene el servidor al arrancar.
  • Renovaciones sin reiniciar. Los ficheros se vuelven a mirar como mucho una vez por segundo, según llegan conexiones; un par renovado se sirve desde el siguiente handshake y queda en el log (reloaded the TLS certificate). Un par que no se puede cargar (a medio escribir, clave y certificado de renovaciones distintas) mantiene el certificado anterior y se registra una vez.
  • Monta un directorio, no los dos ficheros. La mayoría de las herramientas de renovación sustituyen un fichero renombrando otro nuevo encima, y un fichero montado con bind sigue mostrando el antiguo.
  • La imagen se ejecuta con el usuario 65532, así que la clave tiene que poder leerla ese usuario. certbot escribe claves que solo lee root: copia el par al directorio montado desde un hook de despliegue (--deploy-hook) y dáselo a ese usuario.
  • Sin proxy, sin proxies de confianza. A cada cliente se le cargan sus propios fallos. Los puertos publicados por Docker conservan la dirección del cliente en las conexiones que llegan desde otras máquinas.
  • Los handshakes fallidos se limitan en el log: los escáneres de puertos, el HTTP sin cifrar enviado al puerto HTTPS y los clientes que rechazan el certificado dejan un aviso por minuto con el número de los omitidos, y cada uno en el nivel debug.

TLS no cambia nada de la autenticación: un servidor sin token sigue avisando de que cualquiera que llegue a él puede usarlo.

Al arrancar, el servidor mira ARCANE_MCP_HTTP_ADDR. Una dirección TCP a la que llegan otras máquinas (un comodín como :8080, 0.0.0.0:8080 o [::]:8080, una dirección enrutable o un nombre que resuelve a algo que no es loopback) servida sin TLS en el propio servidor lleva en claro cada token, cada clave de Arcane y cada respuesta, sea cual sea el modo de autenticación. Lo que ocurre entonces lo decide ARCANE_MCP_HTTP_ALLOW_PLAINTEXT (o --http-allow-plaintext, que gana a la variable):

ValorAl arrancar
sin definirSe sirve, con un aviso que nombra las salidas: the HTTP listener serves plain HTTP on an address other machines can reach, …
trueSe sirve, con una línea en INFO: declaras que algo delante cifra ese tramo (un proxy que termina TLS y llega al servidor por una red privada o un puente de contenedores)
falseSe rechaza antes de abrir el puerto, con estado de salida 1: serve HTTP: ARCANE_MCP_HTTP_ALLOW_PLAINTEXT=false (--http-allow-plaintext=false) refuses a listener that serves plain HTTP …

TLS en el propio servidor, una dirección de loopback (o un nombre que solo resuelve a loopback) y un socket unix no registran nada y arrancan con cualquier valor, así que el modo endurecido sirve para un servidor que nunca debe servir HTTP sin cifrar a la red por error: dale un certificado, escucha en 127.0.0.1 para un proxy de la misma máquina o usa un socket. Un contenedor no puede usar loopback para un proxy de otro contenedor (dentro de su propio espacio de red, 127.0.0.1 es el propio contenedor), así que en el modo endurecido un servidor en contenedor necesita TLS en el propio servidor o un socket en un volumen compartido.

Un servidor puede atender a varios gestores de Arcane:

environment:
ARCANE_URL: home=http://arcane:3552,lab=https://arcane.lab.example.com
ARCANE_MCP_HTTP_AUTH: apikey

Cada petición nombra su instancia en X-Arcane-URL (home o lab); una petición sin ella se rechaza con 400, y un nombre no listado, con 403. Las claves pertenecen a un único Arcane, así que en modo token ARCANE_API_KEY, si se define, es una lista nombre=clave, y un inicio de sesión (ARCANE_USERNAME, ARCANE_PASSWORD) detiene el servidor, porque solo serviría a una instancia. Quien trabaje con las dos configura dos entradas de cliente con cabeceras X-Arcane-URL distintas. /readyz comprueba todas las instancias y responde degraded mientras alguna está caída. Consulta Varias instancias.

Quédate con el transporte con estado, el predeterminado, salvo que tengas un motivo para cambiarlo:

  • Con estado (predeterminado): sesiones con Mcp-Session-Id, ligadas a la clave que las abrió; las llamadas destructivas pueden preguntar al usuario mediante elicitación en todas las revisiones del protocolo. A los clientes que hablan la revisión 2026-07-28 se les indica que bajen a la 2025-11-25, y siguen funcionando.
  • Sin estado (ARCANE_MCP_HTTP_STATELESS=on): sin sesiones, cada POST va por su cuenta, así que cualquier réplica detrás de un balanceador puede responder cualquier petición. Los clientes con revisiones anteriores a la 2026-07-28 pierden la elicitación y reciben en su lugar el rechazo de confirm: true.

Con el transporte con estado y más de una réplica, el balanceador tiene que enviar todas las peticiones de una sesión a la réplica que la abrió; una réplica que no conoce la sesión responde 404 y el cliente abre una nueva. Consulta HTTP sin estado.

RutaPara qué sirveResponde
/healthzVida: reinicia el contenedor cuando falla200 ok mientras el proceso atiende, sea cual sea el estado de Arcane. Con ?format=json: estado, draining, versión, commit, fecha de compilación y configDigest
/readyzDisponibilidad: saca el servidor de un balanceador cuando falla200 ready cuando Arcane responde a GET /api/health; 503 not ready: … cuando no responde, durante el drenaje y mientras el servidor se detiene. Con varias instancias, 200 degraded mientras respondan algunas, seguido de una línea nombre: ok o nombre: <lo que falló> por instancia. Con ?format=json: el mismo código de estado, con si la versión de Arcane coincide con la del catálogo (abajo)

Ninguna de las dos pide el token ni toca /mcp, y la comprobación de disponibilidad se guarda 5 segundos, así que las sondas no pueden saturar Arcane. /readyz nombra las instancias a cualquiera que llegue a ella (nunca sus URL); mantenla fuera de la ruta pública, como hacen los ejemplos de arriba. Dos réplicas con el mismo configDigest se arrancaron con los mismos ajustes.

/readyz?format=json (o un Accept de solo application/json, como en /healthz) responde con el código de estado de la forma en texto y estos campos:

  • status: ready, degraded (varias instancias, alguna caída) o not ready; reason, solo cuando no está disponible, dice lo que la forma en texto dice tras el prefijo not ready:.
  • catalogVersion: la versión de Arcane a partir de la que se generó el catálogo.
  • versionMatch: si el major.minor de la versión de la que informó la instancia es el del catálogo; null mientras la versión es desconocida o no es una versión publicada (una compilación de desarrollo como next).
  • Con varias instancias, versionMatch está en instances, una entrada por instancia con su name y su status (ok o lo que falló).
{"status":"ready","versionMatch":false,"catalogVersion":"v2.17.2"}

La versión exacta de Arcane no está en la respuesta: /readyz no pide credencial, y la versión permitiría a cualquiera que llegue al servidor identificar el Arcane que hay detrás. Está en el log del servidor, en las líneas de aviso e información descritas en La versión de Arcane y la del catálogo difieren. Una versión que difiere de la del catálogo se registra como aviso y aparece aquí como versionMatch: false, pero nunca hace fallar /readyz. La forma en texto nunca pregunta a Arcane su versión; la forma JSON la vuelve a leer cuando la que tiene es de hace más de 10 minutos.

  • arcane-mcp --probe pide /healthz al servidor local (--ready para /readyz) y termina con 0 ante un 200 y con 1 en otro caso, en 3 segundos como mucho (--timeout). Lee la dirección y el certificado igual que el servidor, así que encuentra un puerto TCP, un servidor con TLS o un socket unix sin argumentos. El HEALTHCHECK de la imagen lo ejecuta cada 30 segundos; un contenedor stdio se da por sano, porque no tiene servidor que sondear. Un servidor en el puerto 0 no se puede encontrar así: pasa con --http el puerto que haya registrado.
  • Parada. Ante SIGTERM el servidor deja de aceptar conexiones, cierra los flujos de eventos abiertos y da hasta 10 segundos a las peticiones en curso para terminar.
  • Drenaje. Con ARCANE_MCP_HTTP_DRAIN_DELAY (como mucho 5m), SIGTERM pone primero /readyz en 503 mientras el servidor sigue atendiendo, para que el balanceador deje de enviarle peticiones nuevas; la parada de arriba llega tras el plazo. Docker espera 10 segundos antes de matar un contenedor, así que sube stop_grace_period en Compose al plazo de drenaje más esos 10 segundos.

Todo va a la salida de error estándar: docker logs o docker compose logs arcane-mcp para un contenedor, journalctl -u arcane-mcp para el servicio de arriba. Cada llamada a una herramienta deja un registro de auditoría con la huella de la clave y, con varias instancias, el nombre de la instancia; los rechazos de la capa HTTP se registran en warn y las autenticaciones fallidas en info, con la dirección del cliente. Envía la salida de error adonde guardes los logs si necesitas un rastro. Consulta Logs y registro de auditoría.

  • ARCANE_MCP_HTTP_TOKEN o ARCANE_MCP_HTTP_AUTH=apikey
  • TLS en el proxy o en el propio servidor; /mcp encaminado sin búfer, sin compresión y sin plazos cortos
  • ARCANE_MCP_HTTP_ALLOW_PLAINTEXT=true cuando un proxy cifra el tramo hasta un servidor en HTTP sin cifrar, o false para rechazar HTTP sin cifrar en la red
  • ARCANE_MCP_HTTP_ALLOWED_HOSTS con el nombre público
  • ARCANE_MCP_HTTP_TRUSTED_PROXIES (la dirección fija del proxy, o unix) y ARCANE_MCP_HTTP_TRUSTED_PROXY_HEADER
  • Ni ARCANE_API_KEY ni inicio de sesión en un servidor compartido, o una clave con un rol reducido
  • Modo de solo lectura, modo seguro o exclusiones si hay que limitar a todos los usuarios (se aplican a todo el servidor)
  • La salida de error recogida, por el registro de auditoría
  • /readyz vigilado y fuera de la ruta pública