Legion MCP について
Legionは、複数モデルによる協議ワークフロー向けのMCPネイティブなモデル評議会です。設定したモデルを個別のツールとして公開し、討論、審査会などに使えるquorumとプリセット評議会を提供します。
主な機能
- 01設定モデルごとのMCPツール
- 02複数モデルへのquorum呼び出し
- 03構造化討議向けのプリセット評議会
- 04逐次・並列・非公開・独立モード
- 05モデルと評議会設定のホットリロード
活用シーン
- 01質問について複数モデルで討論
- 02ブラインドパネルの回答収集と投票
- 03コードレビューへのプリセット評議会の適用
- 04複数モデルのラウンドによる回答の改善
MCP 対応
設定した各モデル、quorum機能、各プリセット評議会を個別のMCPツールとして公開します。OpenAI Responses APIのワイヤ形式でモデルエンドポイントを呼び出し、直接接続または互換ゲートウェイ経由で利用します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
npx -y legion-mcpMCP_TRANSPORTRun the installed package over MCP stdio (the binary defaults to HTTP).DEFAULT_BASE_URLDefault OpenAI Responses-compatible API root for model files that omit baseUrl.DEFAULT_API_KEYシークレットDefault provider or gateway key for model files that omit apiKey.ALLOW_NO_MODELSBoot without any config/models/*.json. The package ships only key-free examples, which the scanner ignores, so this must stay true until a real model file exists beside the working directory.OPENAI_API_KEYシークレットOptional. A model file's apiKey may be "env:VAR" to read the key from an environment variable named VAR at startup; name those variables here as needed. The bundled gpt example reads this one.MAX_ROUNDSMaximum discussion rounds accepted by a council run.TOKEN_BUDGETシークレットOptional soft cumulative token budget for a council run.DYNAMIC_ROLESAllow callers to define ad-hoc council roles inline.LOG_LEVELLogging verbosity. Logs are written to stderr for stdio safety.ASYNC_TOOLSRun councils in the background: council tools return a job handle and poll/cancel tools are exposed. Jobs live in process memory only.TRUST_PROXY_AUTHシークレットBind async jobs to the caller named by X-MS-CLIENT-PRINCIPAL-* headers. Only safe behind an ingress that strips client-supplied copies.ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
17掲載時のツール一覧 · 3 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| models | array | はい | 2つ以上のセレクター:"model" または "model:role"。同じモデルを異なるロールで複数回指定できます(例:"gpt:judge" と "gpt:skeptic")。各セレクターは独立した発言者です。利用可能なモデル: |
| rounds | integer | いいえ | 議論のラウンド数(デフォルト 1、上限は MAX_ROUNDS で設定) |
| objectives | object | いいえ | チーム実行用の任意のチーム別目標:チームタグからチーム共通の目標へのマップです。model:role@team で発言者にタグを付けます。タグ付けされた各チームには、ここで目標を設定する必要があります。各チームメンバーは自チームの目標を参照でき、統合器はすべての目標を参照できます。 |
| tokenBudget | integer | いいえ | 実行全体に適用する任意のソフト累積 token 予算(TOKEN_BUDGET を上書き)。sequential モードではターン間に確認し、parallel モードではラウンド境界で確認するため、超過してから停止する場合があります。超過すると残りのターンは適切にスキップされますが、統合は実行されます。厳密な上限ではありません。structuredContent.budget を参照してください。 |
| prompt | string | はい | モデルに送信する質問またはタスク |
| context | string | いいえ | プロンプトに別ブロックとして追加する任意の補足テキスト(コード、ドキュメント、データ) |
| system | string | いいえ | 任意のシステムプロンプト/指示 |
| temperature | number | いいえ | 任意のサンプリング温度 |
| maxTokens | integer | いいえ | 任意の最大出力トークン数。可視の回答と隠れた推論の両方に予算を割り当てます。推論モデルはテキストを出力する前に思考にトークンを消費するため、上限が厳しすぎると可視の回答を出力できないことがあります。推論モデルには十分な余裕を持たせてください。複数ラウンドの quorum では、ラウンドごとにトランスクリプトが長くなるため、さらに上限を引き上げてください。 |
| roles | object | いいえ | この quorum 呼び出し用の臨時ロールです。ロール名と指示のマップです。models では "model:role" として参照します。 |
| mode | enum | いいえ | 各ラウンドの発言者が参照するトランスクリプトの範囲です。sequential(デフォルト。以前のすべての発言を参照)、parallel(完了済みの前のラウンドのみ参照し、同じラウンドの他の参加者は見えない)、private(自身の以前の発言のみ参照)、independent(統合までプロンプト以外は何も見ない)。sequential | parallel | private | independent |
| synthesize | string | いいえ | 統合ターンのセレクターです。統合役は通常のラウンドでは発言せず、統合枠でのみ発言します。 |
| synthesizeEvery | any | いいえ | 統合役を実行するタイミングです(synthesize が設定されている場合のみ有効)。数値 N は N ラウンドごとに統合し、最後にも必ず統合します。1 = 毎ラウンド、0 = 最後のみです。"end" は 0 の別名です(デフォルト)。 |
| frame | string | いいえ | 任意の中立的な枠組み設定役のセレクターです。議論の焦点を示し、問いの形を整えて第 1 ラウンドを始める司会役です。どちらの側にも立たず、チームタグも付けられません。締めくくる synthesize と対をなし、枠組み設定役は議論を開始します。 |
| reframeEvery | any | いいえ | 枠組み設定役が再び発言するタイミングです(frame が設定されている場合のみ有効)。数値 N は N ラウンドごとに枠組みを設定し直して方向を導いたり調整したりします。0 または "end"(デフォルト)は冒頭のみです。 |
| closingStatements | boolean | いいえ | true の場合、各ラウンドの発言者は統合の直前に、トランスクリプト全体について最後の並行発言を 1 つ行います。synthesize が必要です。 |
| vote | string | いいえ | 任意の匿名相互投票の指示です。設定すると、参加中の各ラウンド発言者が非公開の投票を行い、候補者メニューから数字を選びます(allowSelfVote が false でない限り、自分の席も含まれます)。または 0 を選んで棄権します。トランスクリプトに追加されるのは候補者ラベル別の匿名集計のみです(誰が誰に投票したかは表示されません)。投票内容はログから伏せられます。この仕組みは助言のみを行い、候補者を除外したり勝者を選んだりしません。投票結果を反映させたい場合は、プロンプトで統合役/審判に指示してください。 |
| voteEvery | any | いいえ | 匿名投票を行うタイミングです(vote が設定されている場合のみ有効)。数値 N は N ラウンドごとに投票し、最後のラウンドも必ず含みます。0 または "end"(デフォルト)は最後に 1 回だけ投票します。 |
| voteVisibility | enum | いいえ | 投票結果の表示範囲です。"aggregate"(デフォルト)は集計数のみを表示し、"ballots" は匿名化された投票内容も表示します(投票者の身元は表示されません)。aggregate | ballots |
| allowSelfVote | boolean | いいえ | 投票者自身の席を投票メニューに表示するかどうかです(vote が設定されている場合のみ有効)。デフォルトは true です(実際の選挙と同様に、自分を選べます)。自己投票がルールの悪用となる相互評価投票(例:"vote the weakest peer")では false に設定してください。 |
詳細
Legion
「私はレギオン。私たちは大勢いるのだから。」
MCPネイティブなモデル評議会です。Legion は LLM を個別のツールとして公開し、討論、陪審、ブラインドパネル、非公開の改良集中セッション、ワークショップ、カスタムの複数モデルによる審議へと編成します。
すべてのモデルには、OpenAI Responses API のワイヤーフォーマットを通じてアクセスします。OpenAI または Azure を直接利用するか、互換性のあるゲートウェイ(LiteLLM プロキシなど)を経由して他のプロバイダーにルーティングし、ホットリロード可能なファイルを通じて評議会全体を設定できます。
目次
仕組み
flowchart LR
AI[Calling AI] -->|claude / gpt / gemini …| Legion
Legion -->|Responses API| GPT[OpenAI / Azure — direct]
Legion -->|Responses API| GW[Gateway e.g. LiteLLM]
GW --> Claude & Gemini & Llama
- モデルごとに 1 つのツールを用意し、スラッグ化したモデル名を付けます(例:
Claude→claude)。各ツールはpromptと、任意のcontext、role、system、temperature、maxTokensを受け取ります。 quorumツールは、1 つのプロンプトを複数のモデルに振り分けます。役割、複数ラウンドのディスカッション、可視性モード、統合機能を備え、各回答を個別に返します。オーケストレーションの選択肢については、プリセットを参照してください。- プリセットは、あらかじめメンバーを設定した名前付きの評議会(討論、法廷、コードレビューなど)で、それぞれ独自のツールとして公開されます。
- ID 情報とテレメトリーは回答テキストではなく、
structuredContentに格納されます。ログは stderr に出力されます(stdio でも安全です)。
設計上の決定
- プロバイダーアダプターはありません。 プロバイダー固有のコードも、組み込みのモデル一覧もありません。Legion は 1 つのワイヤーフォーマットを使用し、これにネイティブ対応していないモデルはゲートウェイ経由で利用します。新しいモデルをサポートするために、ここを変更する必要はありません。
- モデルはコードではなく設定です。 モデルを追加するには JSON ファイルを追加します。HTTP 経由ではリクエストごとにディレクトリを読み直すため、再ビルドも再起動も不要です。stdio 経由では接続ごとに設定を 1 回読み込みます(ホットリロードを参照)。
- モデルごとに 1 つのツールです。 呼び出し元の AI には、モデルパラメーター付きの単一ツールではなく、各モデルがそれぞれ独自の説明を持つ個別のツールとして表示されます。臨機応変な複数モデルの利用には
quorumツールを使用でき、config/presets/の各プリセットは、メンバーが固定された事前設定済み評議会の専用ツールとして公開されます。 - ステートレスです。 各呼び出しは
store: falseを指定した単発処理です。何も永続化されないため、データベースも、管理が必要な会話状態もありません。 - 小規模です。 TypeScript は数千行ほどで、バンドル出力ファイルは 1 つ、依存関係は 5 つです。
要件
- Node.js 24+
- OpenAI Responses と互換性のあるエンドポイントを 1 つ以上(プロバイダー API への直接接続、またはブリッジが必要なモデル向けの LiteLLM などのゲートウェイ)
セットアップ
npm から利用する場合 — クローンもビルドも不要です。
npx legion-mcp
クローンからセットアップする場合:
npm install
copy .env.example .env # then edit .env
設定
すべての設定は config/ ディレクトリにあります。同梱のデフォルト設定は常にベースレイヤーとなり、現在の作業ディレクトリにある config/ フォルダーがファイル単位でその上に重ねられます。
- ディレクトリリソース(
models/、roles/、presets/、tools/):ローカルのファイルは同名の同梱ファイルを上書きします。ローカルにのみあるファイルは追加され、変更していない同梱ファイルはすべてそのまま残ります。そのため、config/presets/refine.jsonを1つ配置すると、そのプリセットだけが上書きされ、ほかの同梱プリセットは残ります。 - 単一ファイルのテキスト(
prompts.json、errors.json、schema.json):キー単位でマージされ、同梱の値よりローカルの値が優先されます。ローカルのファイルが部分的な場合は、指定したキーのみが上書きされます。 description.md:ローカルに存在する場合は全体が優先され、存在しない場合は同梱のものが使われます。
オーバーレイでは、同梱エントリを上書きまたは追加できますが、削除はできません。どの同梱プリセットをツールとして登録するか選ぶには、PRESETS を使用します(下記参照)。
npm からインストールする場合は、独自のモデルファイルを用意する必要があります。 同梱の設定にはキーを含まない
*.example.jsonモデルファイルのみが含まれており、スキャナーはこれらを意図的に無視するため、バンドルに含まれる実際のモデルはゼロです。実際のモデルファイルがない場合、サーバーは起動時にすぐに失敗します(No model files found in ...)。サーバーを実行する場所と同じ場所にconfig/models/<name>.jsonを配置してください(下記参照)。それ以外の設定は同梱のデフォルトにフォールバックします。
以下のディレクトリ構成は、どちらの場合も同じです。
ホットリロード
設定はサーバーインスタンスの構築時に毎回新しく読み込まれ、ビルド時に組み込まれることはありません。ただし、読み込みが行われるタイミングはトランスポートによって異なります。
| トランスポート | 設定の再読み込み | 設定ファイルを編集した場合の反映 |
|---|---|---|
http | リクエストごと | 次の呼び出しから即座に反映され、再起動は不要です。 |
stdio | 接続ごとに1回 | クライアントの再接続時に反映されます。 |
HTTP ではリクエストごとに新しいサーバーが構築されるため、追加したモデル、ロール、プリセット、またはテキストのオーバーライドは次の呼び出しから反映されます。Stdio では接続中、1つのサーバーが維持されるため、同じ編集内容はクライアントが Legion を再起動したときに反映されます。ほとんどのデスクトップ MCP クライアントでは、マシンを再起動するのではなく、サーバーを再読み込みします。
この README で「次の呼び出しから即座に反映」と書かれている場合は、HTTP での動作を指します。stdio では、次の接続時に反映されます。
モデル — config/models/*.json
モデルファイルが少なくとも1つ必要です。モデルファイルがない場合、サーバーはすぐに起動に失敗します。
各 JSON ファイルはツールになり、ファイル名をスラッグ化した名前が付けられます
(config/models/fable.json → ツール fable):
{
"model": "claude-fable-5",
"description": "Claude Fable — fast, creative, general purpose.",
"baseUrl": "https://api.example.com",
"apiKey": "sk-optional-per-model-key"
}
model(必須)— エンドポイントがルーティングする、デプロイ済みモデルの ID です。description— 呼び出し元の AI が適切なモデルを選ぶ際に役立ちます。system— このモデルへのすべての呼び出しに組み込む、任意の基本システム指示です。baseUrl/apiKey— 任意です。省略した値はDEFAULT_BASE_URL/DEFAULT_API_KEYにフォールバックします。apiKeyにはenv:プレフィックスを使って環境変数を指定できます。"apiKey": "env:GPT_KEY"は環境変数からGPT_KEYを読み込みます(未設定または空の場合、起動時に致命的なエラーになります)。これにより、キーをファイルに記載せずに済みます。omitParams— このモデルのリクエストから除外するパラメーターの任意リストです。例:["temperature"]。サーバーはプロバイダーに依存せず、どのモデルがどのパラメーターを拒否するかを決めつけません。各モデル固有の挙動はここで指定します。推論モデルや、temperatureを拒否する一部のデプロイで便利です。reasoning— 任意の"minimal" | "low" | "medium" | "high"で、reasoning.effortとして送信されます。推論モデルはmaxTokensをすべて思考に費やし、何も出力しないことがあります。"low"にすると、回答に使える余地を残せる場合があります。エンドポイントがこのパラメーターをサポートしている必要があります。また、コンテンツフィルタリングを回避するものではありません。maxTokens— このモデルの任意の出力上限です。呼び出し元やプリセットのロールが指定した値にかかわらず、すべてのリクエストでmin(requested, ceiling)が送信されます。より多くの余地が与えられるほど深く考え、結果を空で返すモデルに便利です。
ホットドロップ: リクエストごとにディレクトリが再スキャンされます。モデルファイルを追加または編集すると、再起動なしで次の呼び出しから反映されます。
シークレットと Git: モデルファイルには API キーが含まれる場合があるため、config/models/*.json は Git の追跡対象外です。*.example.json(追跡対象でキーを含まず、スキャナーから除外されます)をコピーして開始してください。
copy config\models\gpt.example.json config\models\gpt.json # then add your key
ロール — config/roles/*.md
任意のホットドロップ可能な指示ファイルです。各 .md ファイルが、ファイル名をスラッグ化した名前のロールになります。ファイルを置くと、次の呼び出しから反映されます。このリポジトリには、すぐに使えるスターターとして skeptic.md、builder.md、judge.md、short.md(「すぐに回答し、熟考しない」という簡潔なロール。出力が制約されたターンに便利です)が含まれています。自由に編集または削除してください(シークレットは含まれていません)。
ツールで使用できるセレクターは roleName になります。例:role: "skeptic" を渡すか、quorum.models で "model:skeptic" を使用します。
プリセット — config/presets/*.json
任意のホットドロップ可能な合議レシピです。プリセットごとに JSON ファイルを1つ用意し、モデルと同様にファイル名をスラッグ化した名前を付けます。各プリセットは独自のツールになります。config/presets/code_review.json を置くと、次のリクエストから code_review ツールが表示されます。各プリセットには description、roles リスト、および任意の権威的な mode / synthesizer のデフォルト値があります。各ロールはその動作をインラインで定義します。ロールの description がそのまま指示(動作契約)になります。description のないロールは、一致する config/roles/<role>.md ファイルにフォールバックします。
{
"description": [
"Free-for-all: pit several contestants against each other, then crown a winner.",
"",
"Staff `contestant` with as many models as you like; one `judge` decides."
],
"mode": "parallel",
"synthesizer": "judge",
"roles": [
{ "role": "contestant", "description": "Argue why your answer beats the others.", "min": 2, "max": null },
{ "role": "judge", "description": "Crown a single winner and justify it.", "min": 1, "max": 1 }
]
}
呼び出し元の AI はプリセットツール(例:code_review)を直接呼び出し、引き続き models セレクターを指定して、任意のモデルを任意のプリセットロールに割り当てます。プリセットは強制されます。すべてのセレクターでプリセットのロールを使い、各ロールを定められた人数分割り当てる必要があります。満たさない場合、修正すべき内容を示すエラーが返されます。
キー:
| キー | 型 | デフォルト | 説明 |
|---|---|---|---|
description | string | string[] | 必須 | プリセットツールの MCP 説明です。 |
roles | PresetRole[] | 必須 | プリセットで受け付けるロールです。 |
mode | "sequential" | "parallel" | "private" | "independent" | "sequential" | 各ラウンドの発言者が、どの過去のターンを参照できるかを制御します。 |
defaultRounds | 正の整数 | 1 | 呼び出しで rounds が省略された場合に使用するラウンド数です。 |
synthesizer | string | なし | 統合ターンを行うロールです。単一席のロールは中立で、ラウンドには参加しません。複数席のロール(max > 1 または null)は参加し、その最初の現役席が統合を行います。 |
synthesizeEvery | "end" | non-negative integer | "end" | 終了時、または N ラウンドごとに統合を行います。 |
eliminator | string | なし | 除外を行う中立ロールです。eliminateEvery と併用する場合は必須です。 |
framer | string | なし | 議論を開始し、方向を示す中立ロールです。 |
reframeEvery | "end" | non-negative integer | "end" | 開始時のみ、または開始後 N ラウンドごとに議論の方向を再設定します。 |
closingStatements | boolean | false | 最終統合の前に締めくくりのフェーズを実行します。 |
eliminateEvery | non-negative integer | "spread" | 0 | 除外役が N ラウンドごとに発言者を 1 人除外するか、除外を均等に配分します。プリセット専用です。 |
eliminationsOptional | boolean | false | 除外役が除外を見送れるようにします。プリセット専用です。 |
enterEvery | non-negative integer | 0 | 各チームから発言者を 1 人ずつ開始時に参加させ、その後 N ラウンドごとに待機中の発言者を 1 人ずつ追加します。プリセット専用です。 |
vote | string | なし | 投票の指示です。匿名投票を有効にします。 |
voteEvery | "end" | non-negative integer | "end" | 終了時、または N ラウンドごとに投票します。 |
voteVisibility | "aggregate" | "ballots" | "aggregate" | 文字起こしに集計結果のみ、または匿名化された投票内容も含めます。 |
allowSelfVote | boolean | true | 各投票者の候補一覧に、自分自身の席を含めます。 |
voteByTeam | boolean | false | @team ごとに 1 つの選択肢を提示し、チーム単位で投票を集計します。 |
ロールオブジェクトのキー:
| キー | 型 | デフォルト | 説明 |
|---|---|---|---|
role | string | 必須 | model:role セレクターで使用するロール名です。 |
description | string | string[] | 対応するロールファイル | インラインの指示です。配列の場合は改行で結合されます。それ以外の場合は config/roles/<role>.md が存在する必要があります。 |
min | non-negative integer | 1 | 発言者の最小数です。0 にするとロールは任意になります。 |
max | 正の整数または null | 1 | 発言者の最大数です。null は上限なしを意味します。 |
maxTokens | 正の整数 | 8192 | 呼び出し元が maxTokens を省略した場合の、このロールの出力上限です。呼び出し元が明示した値は、中立ロールを含むすべてのロールに適用されます。非表示の推論も含みます。 |
silent | boolean | false | 通常のラウンドで発言せずに、ロールが議論を観察して投票できるようにします。 |
voter | boolean | すべての投票資格を持つロール | いずれかのロールに指定されている場合、匿名投票を指定されたロールに限定します。 |
candidate | boolean | すべての投票資格を持つロール | いずれかのロールに指定されている場合、投票候補を指定されたロールに限定します。 |
closing | boolean | すべての投票資格を持つロール | 締めくくりを指定されたロールに限定します。チームごと、またはチームに属さないロールごとに、最初の指定発言者のみが締めくくります。 |
closingLast | boolean | false | 並行する締めくくりの発言をコンテキストに含め、この締めくくり役をその後に実行します。closing: true が必要です。 |
tagTeam | boolean | false | @team ごとに指定された発言者を 1 人ずつ、各通常ラウンドに交代で参加させます。enterEvery とは併用できません。 |
cameo | boolean | false | 毎ラウンドではなく、呼び出しの cameoRound で指定されたラウンド、またはそれがない場合は中間のラウンドに、ちょうど 1 回だけ発言します。レギュラーではなく、ゲスト出演です。 |
たとえば、法廷での呼び出しでは、弁護士を @team タグで陣営に割り当てます。各陣営で最初に記載された弁護士が、その陣営の締めくくりの陳述を行います。
{
"models": [
"gpt:lawyer@prosecution",
"grok:lawyer@prosecution",
"claude:lawyer@defense",
"kimi:juror",
"llama:juror",
"mistral:juror",
"opus:judge"
],
"objectives": {
"prosecution": "Prove liability.",
"defense": "Defeat liability."
}
}
作成時の注意
プリセットを書く際に気を付けたい点:
- 脱落指示には正確なラベルを使います。 審判は選択可能なメニューから
CUT <label>コマンドを1つコピーし、次の行に理由を記載します。任意の脱落ではKEEP ALLも指定できます。数字だけの指定や曖昧な選択は拒否されます。ローカルの脱落プロンプトをオーバーライドする場合も、このコマンド形式を使う必要があります。 - 必須の脱落処理は停止する場合があります。 回数を制限した後処理の再試行でも、最後に1人だけが残るとは限りません。未解決の実行では、要約と議論は保持されますが、
isError: trueと残りのラベルを含むstructuredContent.incompleteが返されます。脱落が任意のコンテストには、この要件は適用されません。 min/maxは、チームごとではなくその役割の全スピーカーを数えます。 その役割全体の人数を、すべてのチームを通して制限します。そのため、2対2から6対6までの両サイドをカバーする必要があるタッグチームのwrestler役はmin: 4, max: 12となります。3対3は、その範囲内で有効な編成の1つ(レスラー6人)にすぎず、それ自体のmax: 3が設定されるわけではありません。エンジンは「両サイドの人数を同じにする」や「各サイドに1人ずつ」といった条件を強制できないため、代わりにdescriptionに記載してください。- 中立の役割はチームに所属できません。
eliminator、framer、および1人用のsynthesizerは@teamタグを拒否するため、片方のチームに属する役割にこれらの職務を割り当てることはできません。 - キーによっては別のキーも必要です。 違反は読み込み時に検出されます。
synthesizeEveryにはsynthesizer、eliminateEveryにはeliminator、reframeEveryにはframer、closingLastにはclosing、投票オプションにはvoteが必要です。また、1人用のsynthesizerには、ほかに少なくとも1つの必須役割が必要です(通常のラウンドには参加しないためです)。enterEveryとtagTeamは、どちらも発言者を決めるため、併用できません。 - 形式が正しくないプリセットは致命的なエラーにならず、スキップされます。
❌ preset skipped — Invalid <file>: <reason>がログに記録され、ほかのすべてのツールは引き続き登録されます。プリセットのツールが表示されない場合は、サーバーログを確認してください。 - コストは
speakers × rounds回の直列モデル呼び出しです。 そのため、defaultRoundsや大きなmaxを設定すると、コストは急速に増加します。mode: "parallel"では、各ラウンドの処理時間が最も長いスピーカーに全体がそろう一方、ラウンド内でスピーカー同士が互いに見えなくなります。
このリポジトリには、以下のプリセットが同梱されています。自由に編集または削除してください。
battle_royale- 全員参加の勝ち抜き戦です。監督役が勝者を決定します。
brainstorm- 複数のモデルで多様なアイデアを生成します。
bullying- 1つのモデルが立場を擁護し、ほかのモデル全員が一斉に反論します。任意の教師役が、その主張を貫けたかどうかを判定します。
code_review- 複数モデルによる構造化されたコードレビューです。
courtroom- チームタグ付きの弁護士が対立する側に立って議論し、陪審員が陣営ごとに投票して、裁判官が判決を下します。
debate- 対立する側が問いについて議論し、最終的な統合へと導きます。
double_blind- 互いの内容が見えない、独立したブラインドパネルです。
election- 候補者が選挙活動を行い、その後、参加者が秘密投票で決定します。匿名投票が判定そのものであり、裁判官の判断ではありません。任意の
incumbentは実績を擁護し、任意の無言のelectorateは各ラウンドをすべて読み、選挙活動をせずに投票します。 final_girl- ラウンドごとに1人ずつ脱落し、最後の1人が残ります。
focus_group- モデレーターが進行し、参加者同士が互いの意見を発展させるパネルです。
gauntlet- 各ラウンドで非公開に自己改善を重ねる競争です。
quick_take- 2つの視点で素早く直感を確かめます。1つは直接的な回答、もう1つは一言の反論です。
refine- 既存の成果物をリレー形式で磨き上げます。
tag_team- タッグマッチです。各ラウンドでチームごとに
@teamタグ付きのレスラーが1人だけ出場し、ほかのメンバーはエプロンで待機します。ラウンドごとに交代するため、3人チームは3人全員が順番に出場します。任意のrun_inは1ラウンドだけリングに乱入します(cameoRoundで指定します)。任意のannouncerが試合を実況し、refが勝利チームを決定します。 tiebreak- 決着がつかない状況を、決定権を持つ第3の視点で解決します。
war_games- 選手が時間差で入場するチーム戦のケージマッチです。
@teamタグ付きの選手が1人ずつ入場し、中立のレフェリーが反則を判定して勝利チームを決定します。試合を組み立てる任意のbookerを追加できます。 workshop- 役割を分担した創造的なチームです。
どの組み込みプリセットをツールとして登録するかは
PRESETSで制御されます。未設定の場合はすべて登録されます。また、独自の
config/presets/に追加したローカル専用プリセット(組み込み版のないスラッグ)は、作成すること自体が明示的な選択となるため、設定にかかわらず常に登録されます。組み込みプリセットと同じスラッグを再利用するローカルファイルは、新しいプリセットではなく、そのプリセットのカスタマイズであるため、引き続きPRESETSに従います。組み込みプリセットもローカルプリセットもない場合、プリセットツールはありません。ただし、組み込みセットは基盤となるレイヤーなので、独自のconfig/presets/フォルダーを用意しなくても、組み込みプリセットはすべて利用できます。
役割の説明文は出力を促すもので、上限を設けるものではありません — ターンごとの厳密な上限には
maxTokensを使い、推論モデルや複数ラウンドの定足数には余裕を持たせてください。tokenBudgetは別の指標です。実行全体におけるすべての呼び出しの入力 と出力をカウントするため、turns × (context + maxTokens)を基準に見積もり、見積もりより大きな値を設定してください。会話履歴が長くなると入力が大半を占めます。
AI向けガイダンス — config/description.md
クライアントにMCPのinstructionsとして提供される任意のMarkdownです。使用するモデルと、AIがそれぞれを使うべき場面を記述します。テンプレートについては、このリポジトリ内のファイルを参照してください。リテラルの{longRuns}マーカーは、ASYNC_TOOLSに応じてconfig/sync/long-runs.mdまたは
config/async/long-runs.mdに置き換えられるため、ほかの内容を重複させずに、実行方法のガイダンス(ブロックして待機するか、開始・ポーリング・キャンセルするか)をモードに合わせられます。マーカーを含まないローカルのdescription.mdは、記載されたとおりに提供されます。モードに関するガイダンスがないことを示す起動時の警告が表示されます。
ツール、フィールド、メッセージのテキスト — config/*.json と config/tools/*.md
呼び出し元がLegionを操作する際に読むテキスト、つまりツールやフィールドの説明、プロンプトのひな形、実行時エラーは、コードではなくconfigにあります。(outputSchema内の結果形式の説明、生成されるスタッフ向けの行、起動時エラーはコードに残ります。)各ファイルはキーごとに同梱のJSONベース設定にマージされるため、変更したいものだけを上書きしてください。すべてのキーと{token}プレースホルダーは、同梱ファイルを開いて確認できます。
config/tools/quorum.md、poll.md、cancel.md—quorumツール、および(非同期モードのみ)poll/cancelツールの説明です。ファイルを削除すると、組み込み文字列にフォールバックします。モデルツールはモデルファイルのdescriptionから、プリセットツールはプリセット独自の説明から自身を説明します。config/sync/long-runs.md、config/async/long-runs.md—{longRuns}の位置でdescription.mdに挿入される、モードごとのブロックです。config/schema.json— 入力フィールドの説明です(promptは共通フィールド、quorumはquorum専用です。同名キーが競合する場合は、quorumキーが優先されます)。config/prompts.json— モデルが参照するプロンプトの構成テンプレートです。役割の契約、コンテキストブロック、トランスクリプトヘッダー、ラウンドバナーが含まれます。ここで役割の拘束力やラウンドの枠組みを調整できます。config/errors.json— 呼び出し元のAIに表示される実行時エラーメッセージです。
(起動時エラーや設定検証エラーはコードに残ります。壊れた設定ファイルを報告するメッセージを、その設定ファイルの中に置くことはできません。)
環境変数
| 変数 | 必須 | 説明 |
|---|---|---|
DEFAULT_BASE_URL | いいえ* | baseUrl がないモデルの API ルートです。SDK が末尾に /responses を追加します。例:https://api.openai.com/v1、https://<res>.openai.azure.com/openai/v1。LiteLLM プロキシはルート URL をそのまま指定して利用できます。 |
DEFAULT_API_KEY | いいえ* | apiKey がないモデルの API キーです。サーバー側に保持されます。 |
ALLOW_NO_MODELS | いいえ | true にすると、モデルファイルが存在しない場合でも起動します。モデルツールはゼロ件となり、quorum とプリセットツールは登録されますが、config/models/*.json が現れるまでは使用時に失敗します(リクエストごとにホットリロードされます)。ツールの一覧表示だけを行うデモやレジストリのサンドボックス向けです。既定値は false で、モデルがない場合は引き続き致命的なエラーになります。 |
MCP_TRANSPORT | いいえ | http(既定値)または stdio です。 |
HOST | いいえ | HTTP のバインドアドレスです(既定値は 127.0.0.1)。外部に公開するには 0.0.0.0 を設定し、その場合は ALLOWED_HOSTS も設定してください。 |
ALLOWED_HOSTS | いいえ | localhost 以外にバインドする場合の、DNS リバインディング対策用ホスト名をカンマ区切りで指定します。 |
PORT | いいえ | HTTP ポートです(既定値は 5000。stdio では無視されます)。 |
MAX_ROUNDS | いいえ | quorum ツールが受け付けるディスカッションの最大ラウンド数です(既定値は 5)。 |
MAX_TOKENS | いいえ | 呼び出し元が各ターンでリクエストできる、表示対象の maxTokens の最大値です。これを超える値は拒否されます(既定値は 3000)。これを超えるプリセットの役割別上限は、この値にクランプされます。モデルごとの推論割り当て分は別途加算されます。 |
MODEL_TIMEOUT | いいえ | モデル呼び出しごとのタイムアウト(ミリ秒)です(既定値は 90000)。これにより、応答が停止した 1 つの席が評議会全体を停止させることを防ぎます。1 回再試行されるため、失敗したターンと判定されるまでの席ごとの最悪所要時間は、およそ 2 倍になります。 |
TOKEN_BUDGET | いいえ | quorum の実行に対する既定の累積トークン予算(ソフト制限)です。未設定の場合は無制限です。呼び出しごとの tokenBudget で上書きできます。 |
DYNAMIC_ROLES | いいえ | 呼び出し元の AI が quorum の臨時の役割をインラインで定義できるようにします(既定値は true)。 |
PRESETS | いいえ | 登録する組み込みプリセットのスラッグをカンマ区切りの許可リストで指定します(例:code_review,debate)。未設定の場合はすべての組み込みプリセットが対象となり、アップグレードによってプリセットが予告なく削除されることはありません。設定した場合は指定したものだけが対象となり、新たに同梱されたプリセットが自動的に追加されることはありません。独自の config/presets/ に追加したプリセットは常に登録されます。作成すること自体がオプトインとなります。また、同梱プリセットと同じスラッグのローカルファイルを置くとそのプリセットがカスタマイズされ、引き続きこのリストに従います。不明な名前は無視されます。 |
LOG_LEVEL | いいえ | debug | info | warn | error(既定値は info)。 |
ASYNC_TOOLS | いいえ | true にすると、評議会をバックグラウンドで実行します。quorum とプリセットツールはジョブハンドルをすぐに返し、poll/cancel ツールが公開されます。評議会の完了前にツール呼び出しがタイムアウトするホスト向けです。ジョブはこのプロセスのメモリ内にのみ保持されます。既定値は false です。 |
TRUST_PROXY_AUTH | いいえ | true にすると、各ジョブを X-MS-CLIENT-PRINCIPAL-* ヘッダーで指定された呼び出し元に紐付けます(Azure Container Apps Easy Auth)。クライアントが送信した同名のヘッダーを削除するイングレスの背後でのみ安全に使用できます。既定値は false で、jobId を持つ人なら誰でもジョブをポーリングまたはキャンセルできます。 |
JOB_MAX_ACTIVE / JOB_MAX_RETAINED / JOB_RETAIN_MS / JOB_POLL_INTERVAL_MS / JOB_SHUTDOWN_GRACE_MS | いいえ | 非同期ジョブの上限:同時実行できる評議会数(3)、保持する完了済みジョブ数(20)、保持期間(1800000 ms)、推奨ポーリング間隔(10000 ms)、SIGTERM 時の猶予時間(20000 ms)。 |
* すべてのモデルで、ファイルまたは既定値から baseUrl と apiKey を解決できる必要があります。起動時に検証されます。
ALLOW_NO_MODELS=true の場合を除き、モデルディレクトリがない、または空の場合、モデルファイルが無効な場合、エンドポイントまたはキーを解決できない場合、あるいはツール名に変換すると同じスラッグになるファイル名が 2 つある場合、サーバーは起動時に即座に失敗します。
ルーティング
すべてのツール呼び出しは、ステートレスな単発の Responses API リクエストです。エンドポイントがネイティブに Responses に対応しているモデル(OpenAI、Azure OpenAI/Foundry)は、直接呼び出す baseUrl を設定します。それ以外のモデルは既定値を使用します。通常は、ネイティブ API への接続を仲介する LiteLLM などの OpenAI 互換ゲートウェイです。
ロギング
info(青):サーバーの起動時と、モデル呼び出しごとにメタデータを1行記録します。モデル、レイテンシ、トークン使用量、ロール、コンテキストの有無が対象です。プロンプトや応答の内容は記録しません。debug(グレー):これに加えて、プロンプトと応答の全文を記録します(コンテキストは有無のみを記録し、内容は表示しません)。warn(オレンジ)/error(赤):フォールバックとエラーを記録します。
stderr が TTY でない場合、色は自動的に無効になります。
実行
エントリーポイントは1つです。トランスポートは MCP_TRANSPORT で指定します(デフォルトは http、デスクトップ MCP クライアントでは stdio を設定してください)。
npm から実行する場合(legion-mcp バイナリ。config/ があるディレクトリから実行してください):
npx legion-mcp # Streamable HTTP transport on :$PORT/mcp
$env:MCP_TRANSPORT='stdio'; npx legion-mcp # stdio transport
グローバルまたは依存関係としてインストールした場合、同じバイナリを PATH から実行できます。
npm install -g legion-mcp
legion-mcp
開発時(ビルド手順なし、tsx 経由):
npm run dev # Streamable HTTP transport on :$PORT/mcp
npm run dev:stdio # stdio transport
本番環境(bin/server.js にコンパイル済み):
npm run build
npm start # http
npm run start:stdio # stdio
非同期モード — ASYNC_TOOLS=true
評議会の実行には数分かかる場合がありますが、ホスト型の ChatGPT と Codex はそれよりかなり早くツール呼び出しを中断します(実測で約124秒。Codex のデフォルトは60秒です)。ASYNC_TOOLS=true を設定すると、quorum とプリセットの各ツールはリクエストを検証し、評議会をバックグラウンドで開始して、ハンドルをすぐに返します。ハンドルには structuredContent.jobId、現在の state/phase、推奨される pollIntervalMs が含まれます。追加で2つのツールが利用できるようになります。
poll— 読み取り専用です。ジョブの状態、完了した回答と公開メモ、および(終了状態になった時点で)通常と同じ形式の評議会の完全な出力であるresultを返します。full: trueを指定すると、レンダリング済みのトランスクリプトとタイムラインが追加されます。cancel— 実行中のモデル呼び出しを中断し、完了済みの内容を返して、合成を行わずにジョブをcancelledとして終了します。繰り返し実行しても安全です。
個別のモデルツールは引き続き同期実行されます。サーバーの instructions は、呼び出し元のモデルが処理方法を把握できるよう、開始/ポーリング/キャンセルのワークフローに切り替わります。ジョブは JOB_* の上限に従ってプロセスメモリ内に保持されます。再起動すると失われ、別のレプリカにルーティングされたリクエストからは参照できません。そのため、このモードが有効な場合は、単一インスタンスで実行するか、スティッキールーティングを設定してください。Azure Container Apps Easy Auth の背後で各ジョブを認証済みの呼び出し元に紐付けるには、TRUST_PROXY_AUTH=true を設定します。設定しない場合、jobId を持っていることだけがアクセス制御になります。
試してみる
MCP Inspector でツールを一覧表示します。
npx @modelcontextprotocol/inspector -e MCP_TRANSPORT=stdio npx tsx ts/server.ts
VS Code で使用する
npm からの場合は、mcp.json に追加します。
{
"servers": {
"legion": {
"command": "npx",
"args": ["-y", "legion-mcp"],
"cwd": "path/to/your/config/parent",
"env": {
"MCP_TRANSPORT": "stdio",
"DEFAULT_BASE_URL": "https://your-gateway.example.com",
"DEFAULT_API_KEY": "sk-your-key"
}
}
}
}
または、クローンからの場合:
{
"servers": {
"legion": {
"command": "node",
"args": ["bin/server.js"],
"cwd": "path/to/legion",
"env": {
"MCP_TRANSPORT": "stdio",
"DEFAULT_BASE_URL": "https://your-gateway.example.com",
"DEFAULT_API_KEY": "sk-your-key"
}
}
}
}
HTTP トランスポートの場合、クライアントの接続先を http://<host>:<PORT>/mcp に設定します。
ヘルスチェック
GET /health— 軽量な稼働確認です。プロセスが起動しており、設定が読み込まれていることを確認します。{ status: "ok", name, version, models }(modelsは件数)を返します。外部への呼び出しは行いません。コンテナーのHEALTHCHECKと Kubernetes の稼働/準備プローブでは、ここを確認してください。GET /health?deep— オプションの接続確認です。すべてのモデルに短いプロンプトを送り、モデルごとの到達可能性を報告します(1つでも失敗すると503)。モデルごとに課金対象の実際の呼び出しを行うため、手動でのみ使用してください。自動プローブには接続しないでください。
デプロイ
すぐに使えるコンテナーのデプロイ例(Azure App Service、Azure Container Apps、Docker Compose、Kubernetes、HTTPS 用の Compose + Caddy)は examples/ にあります。各例は npm から Legion をインストールし、そのまま配置できる完全な config/ を含みます。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。