AI Bot – ご自身のMCPサーバーをBring Your Own

:bookmark: このガイドでは、外部の**Model Context Protocol (MCP)**サーバーを Discourse AI エージェントに接続する方法について説明します。これにより、MCP 互換のツールプロバイダーを AI ボット内で直接利用できるようになります。

:person_raising_hand: 必要なユーザーレベル:管理者


「Bring Your Own MCP」とは?

Model Context Protocol は、Anthropic によって最初に提案されたオープンスタンダードであり、AI エージェントが標準的な HTTP/JSON-RPC インターフェースを介して外部ツールサーバーと通信できるようにします。MCP サーバーは、LLM が呼び出して処理を実行できる「ツール」(型付き入力を持つ関数)のメニューを公開します。

Discourse AI は現在、MCP クライアントとして機能します。管理パネルで任意の HTTPS MCP サーバーを登録すると、Discourse がそのサーバーの利用可能なツールを検出し、それらのツールは選択した AI エージェント内で第一級の存在となります。JavaScript の記述は不要です。ツールはリモートサーバーによって定義されます。

これは、Discourse 内で実行される JavaScript の記述が必要となるカスタムスクリプトツールとは異なります。MCP を使用すると、既に実行されている外部サーバーを持ち込むことができます。


概要

  • MCP サーバーの登録(URL とオプションの認証)
  • Discourse が自動的にサーバーのツールを検出し、キャッシュ
  • 1 つ以上の AI エージェントにサーバーを割り当て
  • 各エージェントが使用できるツールをオプションで制限
  • ツールはランタイム時に LLM によって呼び出され、Discourse を介して外部サーバーへルーティングされます

MCP サーバーの登録

以下の場所に移動します:

管理 → プラグイン → Discourse AI → ツールMCP サーバータブ → 新しい MCP サーバー

以下の項目を入力します:

項目 説明
名前 人間が読みやすいラベル(エージェントエディターとログに表示)
説明 このサーバーの用途(管理者向け参照)
URL MCP サーバーの HTTPS エンドポイント。パブリックな HTTPS URL である必要があります(プライベート IP は不可)
認証 以下のいずれか:認証なしヘッダー認証、または OAuth
タイムアウト(秒) 1 回のリクエストに対する Discourse の待機時間。デフォルト 30、最大 300
有効 サーバーを削除せずに一時的に無効にするための切り替え

:warning: URL は HTTPS を使用する必要があります。localhost および RFC-1918 私有アドレスはブロックされます(SSRF 保護はサーバー側で強制されます)。


認証オプション

認証なし

サーバーはパブリックにアクセス可能です。認証情報は送信されません。

ヘッダー認証

秘密の値が各リクエストの HTTP ヘッダーに挿入されます。

  1. まず、管理 → AI → 認証情報の下で認証情報を作成します
  2. MCP サーバーフォームでそれを認証情報として選択します
  3. 認証ヘッダー名を設定します(デフォルト:Authorization
  4. オプションの認証スキームプレフィックスを設定します(デフォルト:Bearer

MCP サーバーに送信されるリクエストヘッダーは以下のようになります:

Authorization: Bearer <your-secret-value>

ヘッダー名とスキームの両方を変更して、サーバーが要求する任意の認証スタイルに一致させることができます(例:スキームを空白にして X-Api-Key: <value> とする)。

OAuth

Discourse は、MCP クライアントとして完全な OAuth 2.0 + PKCE フローを実装しています。これにより、OAuth の背後でツールを保護している MCP サーバーがサポートされます。

セットアップ手順

  1. 認証OAuth に設定
  2. クライアント登録を選択:
    • クライアントメタデータドキュメント(デフォルト)— Discourse は https://your-site.com/discourse-ai/mcp/oauth/client-metadata で独自の OAuth クライアントメタデータを公開します。MCP サーバーが RFC 7591 Dynamic Client Registration をサポートしている場合、Discourse は自動的に登録します
    • 手動クライアント認証情報 — 事前に登録済みのOAuth クライアント IDを入力し、OAuth クライアントシークレット認証情報を選択
  3. オプションでOAuth スコープを設定(スペース区切り)
  4. サーバーを保存
  5. 接続をクリック — Discourse がプロバイダーの承認ページ経由でリダイレクトします
  6. 承認後、管理者画面に戻り、ステータスが接続済みになります

高度な OAuth オプション(「詳細オプションを表示」をオンにする):

オプション 目的
OAuth 承認パラメータ 承認リクエストにマージされる JSON オブジェクト(例:{"access_type":"offline"}
OAuth トークンパラメータ トークン交換リクエストにマージされる JSON オブジェクト
リフレッシュトークンを必須 プロバイダーがリフレッシュトークンを返さない場合、接続を失敗させる

Discourse は、有効期限切れになる前にアクセストークンを自動的に更新し、リフレッシュトークンが利用可能な場合は 401 で再試行します。


接続のテスト

サーバーをエージェントに割り当てる前に、エディターフォームの接続テストボタンを使用します。これにより、MCP セッションが即座に初期化され、tools/list が呼び出され、以下の結果が返されます:

  • 交渉された MCP プロトコルバージョン
  • 検出されたツールの数
  • すべてのツールの名前

テストが失敗した場合、サーバーからのエラーメッセージ(またはタイムアウトインジケーター)がインラインで表示されます。


Discourse がツールを検出する方法

Discourse は MCP 仕様 2025-03-26 に従います。接続シーケンスは以下の通りです:

Discourse → POST /  { method: "initialize", params: { protocolVersion, capabilities, clientInfo } }
Server    → { result: { protocolVersion, capabilities } } + Mcp-Session-Id ヘッダー
Discourse → POST /  { method: "notifications/initialized" }   (セッションハンドシェーク完了)
Discourse → POST /  { method: "tools/list", session_id: … }
Server    → { result: { tools: [ { name, description, inputSchema } … ] } }

ツールの定義はサーバーごとに1 時間キャッシュされます。キャッシュの有効期限が切れた後、バックグラウンドジョブが自動的にそれを更新します。キャッシュキーはサイトごと/サーバーごとであるため、マルチサイトインストールは分離されます。

接続テストをクリックすることで、手動で更新をトリガーすることもできます。これにより、常にライブデータが取得されます。

サーバーのヘルスステータス(healthy / error)は、キャッシュの更新ごとに更新されます。


MCP サーバーを AI エージェントに割り当てる

サーバーが登録されたら、エージェントに割り当てます:

  1. 管理 → プラグイン → Discourse AI → エージェントに移動し、エージェントを編集または作成
  2. MCP サーバーセクション(通常のツールセクションの下)までスクロール
  3. リストには、有効な MCP サーバーすべてと、そのツールの数、および推定トークンコストが表示されます
  4. サーバーをオンに切り替えると、そのエージェントで利用可能になります

ヒント:デフォルトでは、サーバーからのすべてのツールがエージェントに利用可能になります。ロケール文字列はこれをよく表しています:「選択された MCP サーバーは、デフォルトですべてのツールを公開します。トークン使用量を削減し、ツール選択を焦点化するために、エージェントごとに絞り込みます。」


エージェントごとの特定ツールの選択

多数のツールを利用可能にすると、各メッセージのトークンコストが増加します(各ツールの定義がシステムプロンプトでモデルに送信されるため)。無駄を省くために:

  1. エージェントエディターで、割り当てられた MCP サーバーの隣にあるツールを選択をクリック
  2. モーダルに、サーバーが現在公開しているすべてのツール、その説明、およびパラメータリストが表示されます
  3. このエージェントに必要なツールのみをチェック
  4. 保存をクリック — エージェントは選択されたサブセットのみを表示するようになります

ai_agent_mcp_servers 結合テーブルは、selected_tool_names を JSONB 配列として格納します。空の配列は「すべてのツールが有効」を意味します。


ツール名と競合解決

MCP ツール名は、単一のエージェントのツールリスト内(エージェントの組み込みツールとカスタムスクリプトツールを含む)で一意である必要があります。Discourse は競合を自動的に処理します:

  • 2 つの異なる MCP サーバーが同じ名前のツールを公開する場合、Discourse は名前空間化します:servername__toolname
  • 組み込みの Discourse ツールと MCP ツールが同じ名前を共有する場合、MCP ツールも名前空間化されます
  • 名前空間化後も衝突が残る場合、数値サフィックスが追加されます(_2_3、…)

LLM 呼び出しで使用される function_name は、MCP サーバー上の生 tool_name と異なる可能性があります。これは自動的に処理されます。MCP ツールクラスは常に元の tool_name_value を個別に保存し、サーバーを呼び出す際に使用します。


ランタイムでのツール呼び出しの仕組み

LLM が MCP ツールを使用すると判断した場合:

  1. セッションの再利用:Discourse は、現在のボットコンテキスト(context.mcp_state)でこのサーバーのキャッシュされた MCP セッション ID を検索します。セッションはボットの返信チェーンごとに作成され、同じサーバーへのツール呼び出し間で再利用されます。
  2. 必要な場合の初期化:セッションが存在しない場合、新しい initialize + notifications/initialized ハンドシェークが実行されます。
  3. 呼び出しPOST /{ method: "tools/call", params: { name: tool_name, arguments: params } } を送信
  4. セッションの有効期限切れ:サーバーが 404(有効期限切れのセッション)を返した場合、Discourse は自動的に再初期化し、1 回再試行します。
  5. 応答の正規化text タイプの MCP コンテンツアイテムは連結されます。非テキストアイテムは JSON シリアライズされます。structuredContent は整形された JSON として出力されます。
  6. エラー結果:サーバーが isError: true を返した場合、ボットは結果ではなくエラーメッセージを受け取ります。

サーバー応答はプレーン JSON または SSE ストリームであり得ます。Discourse は両方を処理します。


トークンコストの表示

エージェントエディターでは、割り当てられた各 MCP サーバーに推定トークン数が表示されます。これは、各ツールの完全な JSON シグネチャ(名前 + 説明 + 入力スキーマ)に OpenAI の cl100k_base トークナイザーを適用して計算されます。これは近似値です。実際のコストは LLM のトークナイザーに依存します。

トークンコストの内訳は、どのサーバーとツールを特定のエージェントに割り当てるかについて、情報に基づいた判断を下すのに役立ちます。


トラブルシューティング

症状 確認すべき点
接続テストがタイムアウトで失敗 **タイムアウト(秒)**を増やしてください。デフォルトは 30 です。サーバーの初期化が遅い場合は、60–120 を試してください。
接続テストは成功するが、エージェントにツールが表示されない サーバーが有効になっていること、およびエージェントの MCP サーバーセクションでオンになっていることを確認してください。
OAuth ステータスが「注意が必要」と表示される エディターフォームに最後の OAuth エラーが表示されます。一般的な原因:リフレッシュトークンの有効期限切れ(再接続をクリック)、サーバーが予期しないスコープを返した場合、またはクライアントメタデータ URL がサーバーからアクセスできない場合。
ツール名が myserver__sometool のように見える 正常です。別のツール(組み込みまたは他のサーバーから)が同じ名前を持っていたためです。LLM はこの名前空間化された名前を自動的に見て使用します。
一定期間後にヘルスが「エラー」と表示される バックグラウンド更新ジョブがサーバーに到達できませんでした。サイトの /logs を確認し、Discourse のホストから MCP サーバーにアクセスできることを確認してください。
会話中にツールが動作しなくなった セッションの有効期限切れ。Discourse はツール呼び出しごとに 1 回自動的に再試行しますが、サーバーが一貫して再起動している場合は、セッション TTL を短くするか、サーバー側のログを調査してください。

より深いデバッグのためには、ai_bot_debugging_allowed_groups を介して AI トランスクリプトへのアクセスを有効にし、完全な会話ログを検証してください。


技術リファレンス

MCP プロトコルの詳細

プロパティ
プロトコルバージョン 2025-03-26
転送 HTTP POST(JSON-RPC 2.0)
SSE サポート あり(tools/call 応答のストリーミング用)
セッション管理 Mcp-Session-Id HTTP ヘッダー
最大応答ボディ 5 MB
クライアント User-Agent Discourse AI MCP Client / <version>

JSON スキーマサポート

Discourse は、LLM に渡す前にツールの inputSchema 定義で以下の JSON スキーマ構文を解決します:

  • $ref — ルートスキーマの $defs / definitions に対して解決
  • allOf — マージ(properties と required 配列はユニオンマージ)
  • anyOf / oneOf — 最初の null ではないバリアントが使用される

関連ソースファイル


関連トピック

:bulb: Discourse-as-MCP-server 機能(discourse/discourse-mcp)は、この機能の補完です。これにより、外部の AI クライアント(Claude Code、Cursor など)が Discourse サイトを読み書きできます。このガイドはその逆で、Discourse AI エージェントが外部 MCP サーバーを呼び出すことを可能にします。

「いいね!」 3