Ошибка MCP при установке в подпапку

@discourse/mcp не работает при установке в подпапке — пути с ведущим слэшем удаляют подпуть сайта

Кратко

На экземплярах Discourse, размещённых в подпапке (например, https://example.com/forum), @discourse/mcp не может подключиться, поскольку каждый внутренний вызов API теряет подпуть и обращается к корню неправильного хоста. Это нарушает валидацию сайта и каждый последующий вызов инструмента (search, read_topic и т. д.), а не только валидацию через --site.

Окружение

  • @discourse/mcp v0.2.7 (актуальная версия на момент написания)
  • Node через npx -y @discourse/mcp@latest
  • Целевой сервер: Discourse размещён по адресу https://<хост>/forum (установка в подпапке за nginx)

Шаги для воспроизведения

  1. Имейте форум Discourse в подпапке, например https://example.com/forum. Убедитесь, что запрос к https://example.com/forum/about.json возвращает 200.
  2. Выполните:
    npx -y @discourse/mcp@latest --site https://example.com/forum --log_level debug
    
  3. Отправьте любой MCP-запрос (или просто наблюдайте за валидацией при запуске).

Ожидаемое поведение

Сервер должен выполнить валидацию по адресу https://example.com/forum/about.json, а инструменты должны обращаться к https://example.com/forum/<endpoint>.

Фактическое поведение

В логах отладки видно, что запрос уходит в корень хоста, а не в подпуть:

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

Сегмент /forum незаметно удаляется.

Причина проблемы

В файле dist/http/client.js:42 (и аналогично в пути записи на строке :85):

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

Согласно спецификации WHATWG URL, аргумент path, начинающийся с /, трактуется как абсолютный и заменяет путь в базовом URL. Во всей кодовой базе пути передаются с ведущим слэшем, например:

  • dist/index.js:230client.get('/about.json')
  • dist/tools/builtin/select_site.js:15client.get('/about.json')
  • Все встроенные инструменты следуют тому же шаблону '/...'.

Результат: new URL('/about.json', 'https://example.com/forum')https://example.com/about.json. Подпапка теряется при каждом вызове.

Предлагаемое исправление

Либо (a) нормализовать путь в HTTP-клиенте, удаляя ведущий слэш из path и обеспечивая наличие завершающего слэша у this.base перед разрешением:

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

Или (b) изменить все места вызовов на использование относительных путей (без ведущего слэша). Вариант (a) безопаснее — это единственная точка изменения, без неожиданных побочных эффектов в других местах.

Обходное решение для затронутых пользователей

Если ваша установка Discourse также имеет поддомен, который перенаправляет (301) на подпуть (например, forum.example.comexample.com/forum/...), укажите этот поддомен как параметр --site. HTTP-клиент MCP следует перенаправлениям, поэтому каждый запрос корректно разрешается в URL с нужным подпутём, а аутентификация сохраняется после перенаправления. Проверено и работает от начала до конца (initialize, search и т. д.) в версии v0.2.7.

Если такого поддомена нет, на стороне клиента обходного решения в настоящее время нет — баг необходимо исправить в пакете.

1 лайк