サブフォルダインストール時の MCP バグ

@discourse/mcp がサブフォルダインストールで失敗する — リードスラッシュ付きパスがサイトのサブパスを除去する

要約

サブパス(例: https://example.com/forum)でマウントされた Discourse インスタンスでは、@discourse/mcp が接続できません。すべての内部 API 呼び出しでサブパスが削除され、誤ったホストのルートにアクセスしてしまうためです。これにより、サイト検証が失敗し、--site 検証だけでなく、すべての後続のツール呼び出し(searchread_topic など)が機能しなくなります。

環境

  • @discourse/mcp v0.2.7(執筆時点の最新バージョン)
  • npx -y @discourse/mcp@latest を通じた Node
  • ターゲット: nginx の背後でサブフォルダインストールされた Discourse (https://<host>/forum)

再現手順

  1. サブパスに Discourse フォーラムを配置します(例: https://example.com/forum)。https://example.com/forum/about.json200 を返すことを確認してください。
  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 にそのサブドメインを指定してください。MCP HTTP クライアントはリダイレクトに従うため、各呼び出しが正しいサブパス URL に解決され、認証も遷移を生き延びます。v0.2.7 において initializesearch などがエンドツーエンドで動作することを確認済みです。

そのようなサブドメインが存在しない場合、現在クライアント側の回避策はありません。このバグはパッケージ内で修正する必要があります。

「いいね!」 1