このガイドでは、外部の**Model Context Protocol (MCP)**サーバーを Discourse AI エージェントに接続する方法について説明します。これにより、MCP 互換のツールプロバイダーを AI ボット内で直接利用できるようになります。
必要なユーザーレベル:管理者
「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 |
| 有効 | サーバーを削除せずに一時的に無効にするための切り替え |
URL は HTTPS を使用する必要があります。
localhostおよび RFC-1918 私有アドレスはブロックされます(SSRF 保護はサーバー側で強制されます)。
認証オプション
認証なし
サーバーはパブリックにアクセス可能です。認証情報は送信されません。
ヘッダー認証
秘密の値が各リクエストの HTTP ヘッダーに挿入されます。
- まず、管理 → AI → 認証情報の下で認証情報を作成します
- MCP サーバーフォームでそれを認証情報として選択します
- 認証ヘッダー名を設定します(デフォルト:
Authorization) - オプションの認証スキームプレフィックスを設定します(デフォルト:
Bearer)
MCP サーバーに送信されるリクエストヘッダーは以下のようになります:
Authorization: Bearer <your-secret-value>
ヘッダー名とスキームの両方を変更して、サーバーが要求する任意の認証スタイルに一致させることができます(例:スキームを空白にして X-Api-Key: <value> とする)。
OAuth
Discourse は、MCP クライアントとして完全な OAuth 2.0 + PKCE フローを実装しています。これにより、OAuth の背後でツールを保護している MCP サーバーがサポートされます。
セットアップ手順:
- 認証を
OAuthに設定 - クライアント登録を選択:
- クライアントメタデータドキュメント(デフォルト)— Discourse は
https://your-site.com/discourse-ai/mcp/oauth/client-metadataで独自の OAuth クライアントメタデータを公開します。MCP サーバーが RFC 7591 Dynamic Client Registration をサポートしている場合、Discourse は自動的に登録します - 手動クライアント認証情報 — 事前に登録済みのOAuth クライアント IDを入力し、OAuth クライアントシークレット認証情報を選択
- クライアントメタデータドキュメント(デフォルト)— Discourse は
- オプションでOAuth スコープを設定(スペース区切り)
- サーバーを保存
- 接続をクリック — Discourse がプロバイダーの承認ページ経由でリダイレクトします
- 承認後、管理者画面に戻り、ステータスが接続済みになります
高度な 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 エージェントに割り当てる
サーバーが登録されたら、エージェントに割り当てます:
- 管理 → プラグイン → Discourse AI → エージェントに移動し、エージェントを編集または作成
- MCP サーバーセクション(通常のツールセクションの下)までスクロール
- リストには、有効な MCP サーバーすべてと、そのツールの数、および推定トークンコストが表示されます
- サーバーをオンに切り替えると、そのエージェントで利用可能になります
ヒント:デフォルトでは、サーバーからのすべてのツールがエージェントに利用可能になります。ロケール文字列はこれをよく表しています:「選択された MCP サーバーは、デフォルトですべてのツールを公開します。トークン使用量を削減し、ツール選択を焦点化するために、エージェントごとに絞り込みます。」
エージェントごとの特定ツールの選択
多数のツールを利用可能にすると、各メッセージのトークンコストが増加します(各ツールの定義がシステムプロンプトでモデルに送信されるため)。無駄を省くために:
- エージェントエディターで、割り当てられた MCP サーバーの隣にあるツールを選択をクリック
- モーダルに、サーバーが現在公開しているすべてのツール、その説明、およびパラメータリストが表示されます
- このエージェントに必要なツールのみをチェック
- 保存をクリック — エージェントは選択されたサブセットのみを表示するようになります
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 ツールを使用すると判断した場合:
- セッションの再利用:Discourse は、現在のボットコンテキスト(
context.mcp_state)でこのサーバーのキャッシュされた MCP セッション ID を検索します。セッションはボットの返信チェーンごとに作成され、同じサーバーへのツール呼び出し間で再利用されます。 - 必要な場合の初期化:セッションが存在しない場合、新しい
initialize+notifications/initializedハンドシェークが実行されます。 - 呼び出し:
POST /に{ method: "tools/call", params: { name: tool_name, arguments: params } }を送信 - セッションの有効期限切れ:サーバーが
404(有効期限切れのセッション)を返した場合、Discourse は自動的に再初期化し、1 回再試行します。 - 応答の正規化:
textタイプの MCP コンテンツアイテムは連結されます。非テキストアイテムは JSON シリアライズされます。structuredContentは整形された JSON として出力されます。 - エラー結果:サーバーが
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ではないバリアントが使用される
関連ソースファイル
plugins/discourse-ai/lib/mcp/client.rb— MCP HTTP クライアント(セッション、呼び出し、OAuth 再試行)plugins/discourse-ai/lib/mcp/tool_registry.rb— ツールキャッシュ、競合解決plugins/discourse-ai/lib/agents/tools/mcp.rb— エージェントランタイム向けの MCP 呼び出しをラップするツールクラスplugins/discourse-ai/app/models/ai_mcp_server.rb— サーバーモデル、OAuth トークン管理plugins/discourse-ai/app/models/ai_agent_mcp_server.rb— エージェントごとのツール選択plugins/discourse-ai/lib/mcp/oauth_flow.rb— OAuth 2.0 + PKCE フロー
関連トピック
- AI ボット – カスタムツール(スクリプトベース)
- Discourse AI ペルソナ/エージェントガイド
- Discourse MCP が登場しました!(Discourse を MCP サーバーとして)
Discourse-as-MCP-server 機能(discourse/discourse-mcp)は、この機能の補完です。これにより、外部の AI クライアント(Claude Code、Cursor など)が Discourse サイトを読み書きできます。このガイドはその逆で、Discourse AI エージェントが外部 MCP サーバーを呼び出すことを可能にします。