@discourse/mcp не работает при установке в подпапке — пути с ведущим слэшем удаляют подпуть сайта
Кратко
На экземплярах Discourse, размещённых в подпапке (например, https://example.com/forum), @discourse/mcp не может подключиться, поскольку каждый внутренний вызов API теряет подпуть и обращается к корню неправильного хоста. Это нарушает валидацию сайта и каждый последующий вызов инструмента (search, read_topic и т. д.), а не только валидацию через --site.
Окружение
@discourse/mcpv0.2.7 (актуальная версия на момент написания)- Node через
npx -y @discourse/mcp@latest - Целевой сервер: Discourse размещён по адресу
https://<хост>/forum(установка в подпапке за nginx)
Шаги для воспроизведения
- Имейте форум Discourse в подпапке, например
https://example.com/forum. Убедитесь, что запрос кhttps://example.com/forum/about.jsonвозвращает200. - Выполните:
npx -y @discourse/mcp@latest --site https://example.com/forum --log_level debug - Отправьте любой 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:230—client.get('/about.json')dist/tools/builtin/select_site.js:15—client.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.com → example.com/forum/...), укажите этот поддомен как параметр --site. HTTP-клиент MCP следует перенаправлениям, поэтому каждый запрос корректно разрешается в URL с нужным подпутём, а аутентификация сохраняется после перенаправления. Проверено и работает от начала до конца (initialize, search и т. д.) в версии v0.2.7.
Если такого поддомена нет, на стороне клиента обходного решения в настоящее время нет — баг необходимо исправить в пакете.