
はじめに
生成AIの進化により、エンジニアに求められるスキルも変わりつつあります。プロンプトの設計・AIエージェントの設計・AIと連携するシステムの構築は、職種を問わず重要性を増している領域です。
生成AIを組み込んだシステムでは、LLMを呼び出すだけで完結しません。状況をどう構造化して渡すか、どの処理をLLMに任せるか、失敗時にどう振る舞うか。こうした設計上の判断が、システムの品質に影響します。
当社では、こうした生成AI時代のスキルを「学ぶ」だけでなく「作って競う」ことで自分のものにする場として、2025年度の社内プログラミングコンテストを開催しました。テーマは、「生成AIを利用した人狼知能の思考ルーチン対決」 です。参加者はMCP(Model Context Protocol)サーバーとして人狼ゲームのプレイヤーを開発し、運営が提供するゲームマスターと接続して対戦します。
16部署から27サーバーが参加し、予選432試合・決勝52試合の計484試合を行いました。この記事では、「コンテストを学習の場として設計する際の考え方」・「上位サーバーに見られた実装パターン」・「参加者アンケートから得た知見」を紹介します。
なぜ「MCP × 人狼ゲーム」なのか
MCPを選んだ理由
MCPは、AIアプリケーションが外部の機能や情報を利用するためのプロトコルです。サーバー側が入力・出力のスキーマを定義し、クライアントがその機能を呼び出します。今回のコンテストでは、この「構造化された情報を受け取り、目的に沿う結果を返す」仕組みを人狼ゲームの各行動に対応させました。
ゲームマスターは、参加サーバーごとの実装言語・内部設計を意識せず、同じtoolの呼び出しでプレイヤーに判断を依頼できます。参加者側は、共通スキーマを満たしながら、プロンプト・前処理・状態管理を自由に設計できます。標準化された接続方式・実装の自由度を両立できる点が、MCPを採用した理由です。
人狼ゲームを題材にした理由
人狼ゲームは、AI研究の分野でも「人狼知能」として長年注目されてきたテーマです。その理由は、人狼ゲームが持つ以下の特徴にあります。
- すべての情報が開示されず、推論で補う必要がある
- 村人陣営と人狼陣営が異なる目的で行動する
- 議論を通じた推理と説得が勝敗を分ける
従来、人狼知能の実現には推論アルゴリズム・自然言語処理の高度な実装が必要でした。現在は、LLMのコンテキスト理解・応答生成能力を活用することで、プロンプト設計を中心に試作できる選択肢が広がっています。
つまり、MCPという技術に触れる場として、人狼ゲームは「技術的に探究しがいがあり、親しみやすい」題材でした。
このコンテストにおける人狼ゲーム
プレイヤーは村人陣営と人狼陣営に分かれます。村人陣営は人狼を全員追放できれば勝利し、人狼陣営は生存している人狼の人数とそれ以外の人数を同数にできれば勝利です。
プレイヤーの役職は、村人陣営の村人・占い師・霊媒師・狩人と、人狼陣営の人狼・狂人の6役職です。
昼フェーズでは全員が議論し、投票で1人を追放します。占い師や霊媒師が得た情報をいつ、どのように共有するか、人狼がどのように紛れ込むかが対戦の要点です。

役職別に得られる情報は次のとおりです。
| 役職 | 役職別に得られる情報 |
|---|---|
| 村人 | なし |
| 占い師 | 占い対象が人狼か人間か |
| 霊媒師 | 前日に追放されたプレイヤーが人狼か人間か |
| 狩人 | なし |
| 人狼 | ほかのプレイヤーが人狼か人間か |
| 狂人 | なし |
各プレイヤーが得られる情報は役職によって異なる一方で、他者の役職は原則としてわかりません。狩人の護衛が成功したかどうかは、翌日の襲撃結果から全プレイヤーが確認できます。各プレイヤーは、会話・投票・襲撃の結果から状況を読み取り、役職ごとの目的に応じて行動します。
ゲームの勝敗という明確なフィードバックがあるため、プロンプト・状態管理・ルールベースの前処理といった設計の違いを、実際の対戦で比較できます。
挑戦を後押しし工夫を評価するコンテスト設計
未経験者でも挑戦できる参加環境
生成AI・MCPの経験の有無にかかわらず参加できるよう、以下の工夫で参加ハードルを下げました。
- Node.js・Python・Javaのサンプルコードを提供
- 「プログラムを書かないプログラム開発」と題した、サンプルのカスタマイズガイドを用意
- 必要なランタイム・ツールをインストール済みのLinuxサーバーを提供
自由に試行できる仕組みの提供
ゲームマスターとなるMCPクライアントの実行環境を社内向けにWeb上で公開することにより、参加者が開発したMCPサーバーを自由に動作検証できる仕組みを提供しました。 参加者はプロンプト改善・状態分析・キャッシュ活用・戦略ロジック追加などを段階的に試行できます。対戦結果をすぐに確認できるようにすることで、仮説の構築と検証を短いサイクルで回せるようにしました。
部署対抗による組織的な知見共有
コンテストは部署対抗形式で開催し、各部署から最大3つのMCPサーバーをエントリーできるものとしました。複数のアイデアを並行して試せるだけでなく、部署内での技術共有・レビューを促進することにつながると考えました。
多様な工夫を評価する採点方式
評価では勝敗だけでなく、役職ごとの行動もスコアに反映しました。たとえば、村人陣営が人狼に投票した場合や、狩人が襲撃を防いだ場合に加点されます。予選・決勝の2段階方式により、単発の結果に左右されにくい評価を目指しました。 予選では27サーバーを3ブロックに分け、1ブロック9サーバーで4ラウンド対戦(1ラウンドあたり36試合)し、累計スコア上位13サーバーが決勝へ進みます。決勝は13サーバーで52試合を行い、その成績のみで順位を決定しました。
【補足】スコア計算ルール(クリックして開く/閉じる)
同じ組み合わせで数十回ゲームを実施した際に、合計スコアが高い順に順位をつけます。
ゲーム内で得られるスコアには、勝利陣営だった場合に得られる「勝利スコア」と、行動によって得られる「行動スコア」があります。
勝利スコア
勝利スコアは、役職の重要度などによって違いがあります。
| 役職 | 獲得スコア |
|---|---|
| 村人 狂人 | 9 |
| 占い師 霊媒師 狩人 人狼 | 10 |
勝利した際にスコアを獲得することができます。
(追放されていたとしても、勝利陣営に所属していると獲得できます)
負けた場合は獲得できません。
行動スコア
行動スコアは、条件に合った行動を実施した際にポイントが加算されます。
| 役職 | 行動 | 獲得スコア | 備考 |
|---|---|---|---|
| 村人 占い師 霊媒師 狩人 | 人狼へ投票した | +1 | 何度でも |
| 占い師 | 人狼を占った | +1 | 一度占った人狼は二度目以降は対象外 |
| 狩人 | 人狼の襲撃を防いだ | +1 | 何度でも |
| 人狼 | 投票で追放されなかった | +1 | 1ゲームで最大5ポイントまで |
| 狂人 | 人狼以外へ投票した | +1 | 何度でも |
スコアの計算例
- 人狼として5日目の投票・襲撃で勝利が確定し最後まで追放されなかった
- 勝利スコア:10ポイント
- 1日目から5日目まで投票で追放されなかったので+5ポイント
- 合計:15ポイント
- 人狼として8日目の投票・襲撃で勝利が確定し最後まで追放されなかった
- 勝利スコア:10ポイント
- 1日目から5日目まで投票で追放されなかったので最大値の+5ポイント
- 合計:15ポイント
- 人狼として2日目の投票で追放されたが人狼陣営が勝利した
- 勝利スコア:10ポイント
- 1日目の投票で追放されなかったので+1ポイント
- 合計:11ポイント
- 人狼として6日目まで残ったが村人陣営が勝利した
- 勝利スコアは0ポイント
- 1日目から5日目まで投票で追放されなかったので最大値の+5ポイント
- 合計:5ポイント
- 占い師として0日目と2日目に人狼を占い、初日に占った人狼に投票し続けて3日目に襲撃されて、村人陣営も敗退した
- 勝利スコアは0ポイント
- 占いで人狼を2回見つけたので+2ポイント
- 1日目から3日目まで人狼に投票し続けたので+3ポイント
- 合計:5ポイント
スコア獲得に向けた戦略
- 勝利陣営となった場合の獲得スコアが一番大きいので、何よりも勝利するための行動をするのがよい
- 占い師は、占いで人狼を見分ける能力があることから、占いと人狼への投票による行動スコアを得られやすいが、人狼にも狙われやすい
- 狩人は、護衛さえ決まれば何度も行動スコアを獲得できるが、護衛自体が難しい
- 霊媒師、村人は人狼への投票が唯一の行動スコアだが、残り続ける限りスコア獲得の機会はある
- 人狼は、もともと人数が少ない陣営であるが、投票をかわすだけで行動スコアを獲得できる優位性がある
- 狂人は、人狼以外に投票するだけで行動スコアを獲得できるので、特別な能力がなくても行動スコアを獲得しやすい
評価に含めた実装品質
各tool呼び出しには最大120秒という応答時間の上限を設け、発言は500文字までとしました。出力エラー・タイムアウト・クラッシュが発生した参加サーバーがあっても、試合全体は継続する運用です。
そのため、本コンテストの順位には、推論や戦略だけでなく、MCPサーバーとして所定のインターフェースに準拠し、リクエストへ安定して応答できたかどうかも反映されています。
アーキテクチャ解説
全体構成
本コンテストのシステムは、MCPのクライアント・サーバーモデルをそのまま人狼ゲームに適用した構成になっています。

- ゲームマスター(MCPクライアント):運営側が提供。ゲームの進行管理・各プレイヤーへの行動リクエスト・勝敗判定を担う
- プレイヤー(MCPサーバー):参加者が開発。ゲームマスターからのリクエストに対して、生成AIを活用した判断結果を返す
参加者が実装する8つのtool
各MCPサーバーは、人狼ゲームの各行動に対応する以下のtoolを実装します。
| tool | 役割 | 対象 |
|---|---|---|
speak | 議論で発言する | 全プレイヤー |
whisper | 人狼同士の作戦会議で発言する | 人狼のみ |
vote | 追放対象に投票する | 全プレイヤー |
divine | 占い対象を選択する | 占い師のみ |
guard | 護衛対象を選択する | 狩人のみ |
attack | 襲撃対象を選択する | 人狼のみ |
last_words | 追放時に遺言を残す | 追放されたプレイヤー |
result | ゲーム終了後の結果を受け取る | 全プレイヤー |
各toolには、ゲームの行動履歴(誰が何を発言したか、誰に投票したか、占い結果など)がパラメーターとして渡されます。ゲームマスターはゲームの進行に応じて、誰にどのtoolを呼び出すかを決定します。MCPサーバーは、呼び出されたtoolに対して、発言内容・投票先・占い先など、プレイヤーとしての応答を返します。この役割分担により、参加者はゲーム進行を実装せず、各場面でどのような応答を返すかという判断ロジックの改善に集中して取り組むことができます。
【補足】1日のターンの処理シーケンス(クリックして開く/閉じる)
sequenceDiagram
autonumber
participant GM as ゲームマスター(MCPクライアント)
participant PS as プレイヤー(MCPサーバー)
rect rgb(245,245,245)
Note over GM,PS: 昼フェーズ:議論
GM->>GM: 状況を整理(発言ログ / 投票履歴 / 襲撃結果 など)
GM->>PS: tool: speak(...)
PS->>PS: 判断(状態更新 → 生成AI → 出力整形)
PS-->>GM: 発言を返す(〜500文字)
end
rect rgb(245,245,245)
Note over GM,PS: 昼フェーズ:投票
GM->>PS: tool: vote(...)
PS-->>GM: 投票先を返す
GM->>GM: 集計 → 追放者決定
opt 追放時
GM->>PS: tool: last_words(...)
PS-->>GM: 遺言を返す
end
end
rect rgb(245,245,245)
Note over GM,PS: 夜フェーズ:役職行動(分岐)
alt 人狼の場合
GM->>PS: tool: whisper(...)
PS-->>GM: 密談を返す
end
alt 占い師の場合
GM->>PS: tool: divine(...)
PS-->>GM: 占い先を返す
end
alt 狩人の場合
GM->>PS: tool: guard(...)
PS-->>GM: 護衛先を返す
end
alt 人狼の場合
GM->>PS: tool: attack(...)
PS-->>GM: 襲撃先を返す
end
GM->>GM: 襲撃結果判定
GM->>GM: 結果を整理
end
rect rgb(245,245,245)
Note over GM,PS: 1日のターン終了
GM->>GM: ゲーム終了判定
alt ゲーム終了の場合
GM->>PS: tool: result(...)(全員)
PS-->>GM: 戻り値(空)を返す
end
end
MCPサーバーのサンプル実装を公開
本コンテストで使用したMCPサーバーのサンプル実装をGitHubで公開しています。
mcp-sample ⧉
Node.js・Python・Javaの実装例を通じて、MCPのtool設計・LLMへの指示・ゲーム状態の扱いを確認できます。
サンプル実装の概要
各言語のサンプルでは、人狼ゲームの8つのtoolを定義してMCPサーバーで公開しています。ゲームマスターであるMCPクライアントからtoolが呼び出されると、サンプルは行動履歴や役職固有の情報を含むゲーム状態・選択可能な対象を受け取り、LLMへの指示を組み立てます。その応答を、発言内容や投票先などtoolの戻り値として返します。
以下はNode.js版で、占い師が占い先を選ぶdivine toolのハンドラーです。ほかのtoolも同様に、入力を受け取り、役職・行動に応じた指示をLLMへ渡して結果を返す構造です。
// 占い対象の指定async function handleDivine(input: DivineInputType): Promise<{ content: { type: "text"; text: string; }[] }> { logger.info("Divine Target", { availableTargets: input.availableTargets }); const res = await requestOpenAI([ { role: "system", content: `あなたは人狼ゲームの占い師です
## 現在の状況のスキーマ ${JSON.stringify(zodToJsonSchema(DivineInputSchemaObject))}
## 現在の状況 ${JSON.stringify(input)}` }, { role: "user", content: "availableTargetsから占う相手を1名選んでください\nプレイヤー名のみを出力してください" } ]); logger.debug("divine tool called", { res, today: input.commonState.todayStatus }); return { content: [{ type: "text", text: res.content || "Content Error" }] };}独自の戦略を試す際は、各toolのハンドラー・LLMへ渡すプロンプト・入力されたゲーム状態の整理方法が主なカスタマイズ箇所です。詳細な実装については、リポジトリーを参照してください。
ゲームマスターは公開していないため、公開サンプル単体で人狼AIの対戦を実行することはできません。公開サンプル単体の各tool応答を確認する場合は、MCP Inspectorなどをご利用ください。
対戦イメージ(動画)
対戦の雰囲気を伝えるため、運営側が提供するゲームマスターがMCPサーバー(サンプル)に接続して対戦する様子を動画にしました。
動画では、プレイヤー人数を9人に設定し、3つのMCPサーバー(サンプルのNode.js版・Python版・Java版)を使って対戦します。
便宜上、村人陣営(村人・占い師・霊媒師・狩人)のプレイヤーにはNode.js版/Python版のどちらかを割り当て、人狼陣営(人狼・狂人)のプレイヤーにはJava版を割り当てています。
実際のコンテストでは、1つのMCPサーバーに1人のプレイヤーを割り当て、役職が偏らないように組み合わせを事前に定義して繰り返し対戦を行いました。
上位チームの戦略
ここでは、決勝で上位に入ったチームのアプローチを紹介します。
1位:会話分析とLLM判断のハイブリッド設計
| 項目 | 内容 |
|---|---|
| 使用言語 | Node.js (TypeScript) |
| 利用AIモデル(参考) | Claude Opus 4.5 |
| 予選順位 | 8位/27サーバー中 |
| 決勝順位 | 1位/13サーバー中(累計スコア:396、勝率:59.6%) |
| アプローチ | コードで会話・投票履歴からゲーム状況を整理し、その結果をLLMに渡して判断させる設計 |
予選8位から決勝で逆転優勝を果たしたサーバーの特徴は、LLMに会話ログをそのまま渡すのではなく、コードで必要な情報を取り出してから判断させた点にあります。予選(9プレイヤー対戦)から決勝(13プレイヤー対戦)にかけてプレイヤー数が増えたことで、会話から追跡すべき関係がより複雑になります。このサーバーは、役職宣言や誰が誰を支持しているか、誰を疑っているかを会話から整理し、現在のゲーム状況と役職ごとの方針をLLMに渡していました。会話の整理はコードで担い、状況に応じた発言や投票の判断はLLMに任せる役割分担です。この設計は、参加者間の関係がより複雑になる決勝の状況において、非常に効果のある工夫だったと考えられます。
2位:シンプルな実装とプロンプト設計
| 項目 | 内容 |
|---|---|
| 使用言語 | Python |
| 利用AIモデル(参考) | GPT-5 |
| 予選順位 | 2位/27サーバー中 |
| 決勝順位 | 2位/13サーバー中(累計スコア:384、勝率:55.8%) |
| アプローチ | サンプル実装と同一のファイル構成で、戦略はすべてプロンプト内の指示として実装。コード上の独自機能追加なし |
このサーバーは、提供サンプルと同程度にシンプルな構成で、戦略の多くをプロンプトに記述していました。それでも予選2位・決勝2位というコンテスト上位の成績を収めています。独自のコードを多く追加したり、複雑なシステム設計を行ったりしなくても、プロンプト設計の工夫によって高い成績を狙えることを示す事例です。
3位:役職別設計と安定稼働への配慮
| 項目 | 内容 |
|---|---|
| 使用言語 | Node.js (TypeScript) |
| 利用AIモデル(参考) | Gemini 3 Pro |
| 予選順位 | 7位/27サーバー中 |
| 決勝順位 | 3位/13サーバー中(累計スコア:370、勝率:55.8%) |
| アプローチ | BasePlayer抽象クラス・6つの役職サブクラスによるOOP構造。分析→発言生成の2段階パイプラインとリトライ機構を実装 |
このサーバーは、役職ごとにクラスを分割し、分析と発言生成を2段階に分けていました。また、LLM呼び出しの失敗時にはリトライし、ゲームの進行に伴って古くなる情報には有効期限を設けてメモリー管理をしていました。対戦中に応答できずに得点機会を逃すサーバーが多数ある中、ゲームの進行に必要な情報を適切に保持しつつ、LLM呼び出しの安定性を確保する工夫が上位の成績につながりました。
三者三様のアプローチ比較
上位3チームは、それぞれまったく異なるアプローチで好成績を収めました。
| 観点 | 1位チーム | 2位チーム | 3位チーム |
|---|---|---|---|
| 戦略の軸 | 会話分析とLLM判断のハイブリッド設計 | シンプルな実装とプロンプト設計 | 役職別設計と安定稼働への配慮 |
| 使用言語 | Node.js (TypeScript) | Python | Node.js (TypeScript) |
| 利用AIモデル(参考) | Claude Opus 4.5 | GPT-5 | Gemini 3 Pro |
| アプローチ | コードで会話・投票履歴からゲーム状況を整理し、その結果をLLMに渡して判断させる設計 | サンプル実装と同一のファイル構成で、戦略はすべてプロンプト内の指示として実装。コード上の独自機能追加なし | BasePlayer抽象クラス・6つの役職サブクラスによるOOP構造。分析→発言生成の2段階パイプラインとリトライ機構を実装 |
上位チームの比較は、このコンテストのルール・参加サーバー・評価環境における観測結果です。特定のモデル・実装手法の一般的な優劣を示すものではありません。
今回の上位チームには、会話の前処理・プロンプト設計・安定稼働を支える実装など、異なる方向の工夫が見られました。
- 1位チームは、LLMに渡す前に情報を整理・構造化する「前処理の質」で差をつけた
- 2位チームは、コードをほとんど書かずにプロンプトの的確さとモデル性能で勝負し、「シンプルさの強さ」を証明した
- 3位チームは、エラー耐性・キャッシュ管理といった「ソフトウェアとしての品質」で安定した成績を実現した
モデル選定も含め、利用するモデルの特性とシステム設計をどう組み合わせるかを検討する重要性が見えてきます。
参加者アンケートから得られた知見
コンテスト後のアンケートには75人が回答しました。回答者のうち63人(84.0%)が、コンテストを通じて「生成AI活用スキルを得た」と回答しています。プログラミング経験について「ほぼ未経験」/「学習・趣味レベル」と答えた参加者も20人おり、経験の幅があるなかで取り組める形式になりました。

サンプルコードの有用性については、75人中74人の有効回答を集計したところ、67人(90.6%)が5段階評価で「4」/「5」と回答し、平均は4.55でした。動作する土台を用意したことは、参加者がMCPの接続そのものよりも、プロンプト・状態管理・戦略の検討に取り組む後押しになったと考えられます。

AI対戦形式の満足度は平均4.37/5、部署対抗形式の満足度は4.08/5でした。完成物を実際に競わせ、結果をもとに改善する形式は、参加者の意欲向上につながったと考えられます。

次回に向けた改善点
一方で、参加者からは「開発環境の性能・接続安定性」・「動作検証データの出力」・「事前ルールの明確化」に関する改善要望も寄せられました。生成AIを活用する社内イベントでは、題材・評価方式だけでなく、誰もが試行錯誤を続けられる開発・検証環境を整えることが重要です。次回はこれらの声を運営設計に反映します。
得られた効果
技術面で見えたこと
参加者は、共通のtool仕様に沿ってMCPサーバーを実装し、実際の対戦で動かすところまで取り組んだことになります。MCPを仕様として理解するだけでなく、toolやパラメーターを設計し、クライアントからの要求に適切な応答を返却する実践的な経験につながりました。
上位チームの実装には、会話情報の構造化、プロンプト設計、リトライやメモリー管理など、異なる方向の工夫が見られました。対戦成績という共通の評価軸があったことで、コンテキスト管理・出力制御・エラーハンドリングを含む設計上の工夫が、推論や戦略と同様に結果へ影響することを確認できました。また、参加者は対戦結果を受けてプロンプト・戦略・状態管理を見直しており、結果に基づく改善サイクルを回す場にもなりました。
組織面で見えたこと
経験の幅にかかわらず生成AIに触れ、生成AI活用を実践する場となりました。これにより組織的な生成AI活用力の向上につながったと考えます。
部署対抗・最大3サーバーのエントリー形式にしたことにより、役職ごとの分担、戦略の検討、相互レビューに取り組むチームも見られました。さらに、他チームの実装や戦略を知る機会への要望が寄せられたことから、部署をまたいだ技術交流への関心を高めるよい機会になったと考えます。
まとめ
2025年度の社内プログラミングコンテストでは、「MCP × 人狼ゲーム」というテーマを通じて、組織的な生成AI活用人材の育成に取り組みました。
今回のコンテストで得た知見は、特定のゲーム・モデルに限られるものではありません。生成AIを活用するシステムでは、モデルを選ぶだけでなく、入力を構造化し、判断を支える処理を設計し、安定して動かすための工夫が求められます。コンテストは、こうした設計を実際に作り、結果を見ながら検証する場になりました。
生成AIやMCPを活用した仕組みを、実際に作り、競い、結果から学ぶ場を設ける。その取り組みを検討する際に、この記事が役立てば幸いです。
記事の執筆にあたっては情報の正確性に努めておりますが、掲載されている文章やソースコード、設定ファイル等の内容について、完全な正確性や安全性を保証するものではありません。活用される際は、必ず公式ドキュメント等をご自身で確認のうえご判断ください。

