Bug MCP lors de l'installation dans un sous-dossier

@discourse/mcp échoue lors des installations dans un sous-dossier — les chemins avec slash initial suppriment le sous-chemin du site

TL;DR

Sur les instances Discourse montées dans un sous-chemin (par exemple https://example.com/forum), @discourse/mcp ne peut pas se connecter car chaque appel API interne perd le sous-chemin, pointant vers la racine incorrecte de l’hôte. Cela brise la validation du site et tous les appels d’outils suivants (search, read_topic, etc.), pas seulement la validation --site.

Environnement

  • @discourse/mcp v0.2.7 (dernière version au moment de la rédaction)
  • Node via npx -y @discourse/mcp@latest
  • Cible : Discourse hébergé à https://<host>/forum (installation dans un sous-dossier derrière nginx)

Étapes pour reproduire

  1. Avoir un forum Discourse dans un sous-chemin, par exemple https://example.com/forum. Vérifier que https://example.com/forum/about.json renvoie 200.
  2. Exécuter :
    npx -y @discourse/mcp@latest --site https://example.com/forum --log_level debug
    
  3. Envoyer n’importe quelle requête MCP (ou simplement observer la validation au démarrage).

Attendu

Le serveur valide contre https://example.com/forum/about.json et les outils appellent https://example.com/forum/<endpoint>.

Réel

Le journal de débogage montre que la requête va vers la racine de l’hôte, et non le sous-chemin :

DEBUG HTTP GET https://example.com/about.json
DEBUG HTTP GET https://example.com/about.json -> 403 Forbidden
ERROR Failed to validate --site https://example.com/forum: HTTP 403 Forbidden

Le segment /forum est silencieusement supprimé.

Cause racine

Dans dist/http/client.js:42 (et le chemin d’écriture correspondant à :85) :

const url = new URL(path, this.base).toString();

Selon la spécification WHATWG URL, un argument path commençant par / est traité comme absolu et remplace le nom de chemin de l’URL de base. Dans tout le code, les chemins sont transmis avec un slash initial, par exemple :

  • dist/index.js:230client.get('/about.json')
  • dist/tools/builtin/select_site.js:15client.get('/about.json')
  • Tous les outils intégrés suivent le même motif '/...'.

Résultat : new URL('/about.json', 'https://example.com/forum')https://example.com/about.json. Le sous-dossier est perdu à chaque appel.

Correction suggérée

Soit (a) normaliser dans le client HTTP en supprimant le slash initial de path et en s’assurant que this.base a un slash final avant la résolution :

const base = this.base.toString().replace(/\/?$/, '/');
const rel  = path.replace(/^\//, '');
const url  = new URL(rel, base).toString();

Ou (b) modifier tous les sites d’appel pour utiliser des chemins relatifs (sans slash initial). L’option (a) est plus sûre — point unique de modification, aucune surprise comportementale ailleurs.

Contournement pour les utilisateurs affectés

Si votre installation Discourse possède également un sous-domaine qui effectue une redirection 301 vers le sous-chemin (par exemple forum.example.comexample.com/forum/...), passez le sous-domaine via --site. Le client HTTP MCP suit les redirections, donc chaque appel aboutit à l’URL correcte du sous-chemin et l’authentification survit au saut. Confirmé fonctionnel de bout en bout (initialize, search, etc.) sur v0.2.7.

Si un tel sous-domaine n’existe pas, il n’y a actuellement aucun contournement côté client — le bug doit être corrigé dans le package.

1 « J'aime »