Bug do MCP ao instalar em subpasta

@discourse/mcp falha em instalações em subpastas — caminhos com barra inicial removem o subcaminho do site

TL;DR

Em instâncias do Discourse montadas em um subcaminho (por exemplo, https://example.com/forum), o @discourse/mcp não consegue se conectar porque toda chamada interna à API remove o subcaminho, acessando a raiz errada do host. Isso quebra a validação do site e todas as chamadas de ferramenta subsequentes (search, read_topic, etc.), não apenas a validação de --site.

Ambiente

  • @discourse/mcp v0.2.7 (mais recente no momento da escrita)
  • Node via npx -y @discourse/mcp@latest
  • Alvo: Discourse hospedado em https://<host>/forum (instalação em subpasta atrás do nginx)

Passos para reproduzir

  1. Tenha um fórum do Discourse em um subcaminho, por exemplo, https://example.com/forum. Confirme que https://example.com/forum/about.json retorna 200.
  2. Execute:
    npx -y @discourse/mcp@latest --site https://example.com/forum --log_level debug
    
  3. Envie qualquer solicitação MCP (ou apenas observe a validação na inicialização).

Esperado

O servidor valida contra https://example.com/forum/about.json e as ferramentas chamam https://example.com/forum/<endpoint>.

Realidade

O log de depuração mostra que a solicitação vai para a raiz do host, não para o subcaminho:

DEBUG HTTP GET https://example.com/about.json
DEBUG HTTP GET https://example.com/about.json -> 403 Forbidden
ERROR Falha ao validar --site https://example.com/forum: HTTP 403 Forbidden

O segmento /forum é silenciosamente removido.

Causa raiz

Em dist/http/client.js:42 (e no caminho de escrita correspondente em :85):

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

Conforme a especificação WHATWG URL, um argumento path que começa com / é tratado como absoluto e substitui o pathname da URL base. Em todo o código, os caminhos são passados com uma barra inicial, por exemplo:

  • dist/index.js:230client.get('/about.json')
  • dist/tools/builtin/select_site.js:15client.get('/about.json')
  • Todas as ferramentas integradas seguem o mesmo padrão '/...'.

Resultado: new URL('/about.json', 'https://example.com/forum')https://example.com/about.json. A subpasta é perdida em cada chamada.

Correção sugerida

Ou (a) normalizar no cliente HTTP removendo a barra inicial de path e garantindo que this.base tenha uma barra final antes da resolução:

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

…ou (b) alterar todos os locais de chamada para usar caminhos relativos (sem barra inicial). A opção (a) é mais segura — ponto único de alteração, sem surpresas de comportamento em outros lugares.

Solução alternativa para usuários afetados

Se sua instalação do Discourse também tiver um subdomínio que redireciona 301 para o subcaminho (por exemplo, forum.example.comexample.com/forum/...), passe o subdomínio como --site. O cliente HTTP do MCP segue redirecionamentos, então cada chamada resolve para a URL correta do subcaminho e a autenticação sobrevive à transferência. Confirmado funcionando de ponta a ponta (initialize, search, etc.) na v0.2.7.

Se não houver tal subdomínio, atualmente não há solução alternativa do lado do cliente — o bug precisa ser corrigido no pacote.

1 curtida