@discourse/mcp falla en instalaciones en subcarpetas: las rutas con barra inicial eliminan la subruta del sitio
Resumen rápido
En las instancias de Discourse montadas en una subruta (p. ej. https://ejemplo.com/foro), @discourse/mcp no puede conectarse porque cada llamada interna a la API elimina la subruta, accediendo incorrectamente a la raíz del host. Esto rompe la validación del sitio y todas las llamadas subsiguientes a herramientas (search, read_topic, etc.), no solo la validación de --site.
Entorno
@discourse/mcpv0.2.7 (la última al momento de escribir esto)- Node mediante
npx -y @discourse/mcp@latest - Objetivo: Discourse alojado en
https://<host>/foro(instalación en subcarpeta detrás de nginx)
Pasos para reproducir
- Ten un foro de Discourse en una subruta, por ejemplo
https://ejemplo.com/foro. Confirma quehttps://ejemplo.com/foro/about.jsondevuelva200. - Ejecuta:
npx -y @discourse/mcp@latest --site https://ejemplo.com/foro --log_level debug - Envía cualquier solicitud MCP (o simplemente observa la validación al iniciar).
Comportamiento esperado
El servidor debe validarse contra https://ejemplo.com/foro/about.json y las herramientas deben llamar a https://ejemplo.com/foro/<endpoint>.
Comportamiento real
El registro de depuración muestra que la solicitud va a la raíz del host, no a la subruta:
DEBUG HTTP GET https://ejemplo.com/about.json
DEBUG HTTP GET https://ejemplo.com/about.json -> 403 Forbidden
ERROR Error al validar --site https://ejemplo.com/foro: HTTP 403 Forbidden
El segmento /foro se elimina silenciosamente.
Causa raíz
En dist/http/client.js:42 (y en la ruta de escritura correspondiente en :85):
const url = new URL(path, this.base).toString();
Según la especificación WHATWG de URL, un argumento path que comienza con / se trata como absoluto y reemplaza la ruta de la URL base. En todo el código, las rutas se pasan con una barra inicial, por ejemplo:
dist/index.js:230—client.get('/about.json')dist/tools/builtin/select_site.js:15—client.get('/about.json')- Todas las herramientas integradas siguen el mismo patrón
'/...'.
Resultado: new URL('/about.json', 'https://ejemplo.com/foro') → https://ejemplo.com/about.json. La subcarpeta se pierde en cada llamada.
Solución sugerida
O bien (a) normalizar en el cliente HTTP eliminando la barra inicial de path y asegurando que this.base tenga una barra final antes de la resolución:
const base = this.base.toString().replace(/\/?$/, '/');
const rel = path.replace(/^\//, '');
const url = new URL(rel, base).toString();
…o (b) cambiar todos los puntos de llamada para usar rutas relativas (sin barra inicial). La opción (a) es más segura: un único punto de cambio y sin comportamientos inesperados en otras partes.
Solución temporal para usuarios afectados
Si tu instalación de Discourse también tiene un subdominio que redirige con 301 a la subruta (p. ej. foro.ejemplo.com → ejemplo.com/foro/...), pasa el subdominio como --site. El cliente HTTP de MCP sigue las redirecciones, por lo que cada llamada se resuelve a la URL correcta de la subruta y la autenticación sobrevive al salto. Funciona de extremo a extremo (initialize, search, etc.) confirmado en v0.2.7.
Si no existe tal subdominio, actualmente no hay solución temporal del lado del cliente: el error debe corregirse en el paquete.