本記事の概要
統合エージェント開発環境をOSSで組み直す研究の公開予定リポジトリで、AIエージェントが3つのコーディングエージェントを比べた。モデルと課題は同じにそろえ、課題は8つである。素材は、このリポジトリの記録である。この比較では、親エージェントが並列実行のMCPサーバを呼び出す。並列実行のMCPサーバは研究の中で自作したプログラムで、呼び出されると子エージェントを並列に起動する。親がOpenHands CLIの3回の実行でだけ、起動した子エージェントの合計32件が1件も完了しなかった。実行記録のファイルの状態の欄も、測定の結果の欄も正常のままで、この結果は約1日のあいだ、比較の結果として扱われた。
原因は、コーディングエージェントの能力の差ではなく、測定用のスクリプトの作りにあった。測定用のスクリプトは、子エージェントが使うAPIキーの受け渡しを、親プロセスの環境変数の引き継ぎと、.envファイルの読み込みに任せていた。親がOpenHands CLIで、隔離した作業ディレクトリで実行した場合だけ、どちらの経路でもAPIキーが届かなかった。
AIエージェントは、APIキーをMCPサーバの設定のenv欄に書いて渡す形に、測定用のスクリプトを修正した。修正した後、親がOpenHands CLIの条件を、指示ファイル一式を置く場合と置かない場合の2つで、1回ずつ測り直した。指示ファイル一式は、作業ディレクトリに置くAGENTS.mdなどのファイルの組である。どちらの条件でも、APIキーが原因で子エージェントがすべて失敗することはなくなった。指示ファイル一式を置いた条件では、子エージェント8件がすべて完了した。置かない条件では、起動した16件のうち15件が、APIキーとは別の理由で完了しなかった。
本文は、最初の節で原因と修正の全体像を示す。その後の節は、次の順に並べた。
- 比較の結果がどう歪んだかを、3つの節で説明する。測定の条件と結果、失敗が結果に表れなかった理由、原因の切り分けの順である
- 親プロセスの環境変数がMCPサーバに届くかどうかを、公開のソースコードで実装ごとに確かめる
- 修正の内容を、3つの節で説明する。APIキーの渡し方の修正と測り直し、失敗を隠さない仕組みと単体テスト、APIキーの保護の順である
- 参考にした資料の節の前で、比較の測定を設計するときの規則を2つ示す
本文では、比べた3つのコーディングエージェントの製品名を出す。内容は各提供元の見解を代表するものではない。
記事から得られること
コーディングエージェントからMCPサーバを経由して別のエージェントを起動する方は、次の3つができるようになる。
- 自分の使うコーディングエージェントが、親プロセスの環境変数のうちどれをstdio形式のMCPサーバに渡すかを、ソースコードで確かめられる。渡す範囲は、実装によって違う
- 子エージェントが使うAPIキーを、MCPサーバの設定のenv欄に書いて渡す形に修正できる
- 測定の側の不備で起きた失敗を、コーディングエージェントの能力の結果として集計しない処理を、自分の測定に追加できる
この記事は、研究の公開予定リポジトリの実行記録と、執筆時に確認した公開のソースコードに基づく考察である。
APIキーの受け渡しが依存していた2つの暗黙の経路
この節では、比較の測定で子エージェントがすべて失敗した原因と、修正した後の形を先に説明する。
比較の測定は、3つのコーディングエージェントを、同じモデルと同じ課題で、条件を変えながら順に測った一連の実行である。コーディングエージェントは、端末から起動して、モデルを呼び出しながらファイルを編集し、コマンドを実行するCLIのプログラムである。比較の測定では、親エージェントが並列実行のMCPサーバを呼び出す。親エージェントは、課題を受け取って最初に起動されるコーディングエージェントのプロセスである。
並列実行のMCPサーバは研究の中で自作したMCPサーバで、呼び出されると子エージェントを並列に起動する。MCPサーバは、コーディングエージェントが呼び出すツールを、MCPという共通の手順で提供するプログラムである。この記事で扱うMCPサーバは、エージェントが子プロセスとして起動し、標準入出力で通信するstdio形式である。子エージェントは、並列実行のMCPサーバが起動するコーディングエージェントのプロセスである。
測定用のスクリプトは、親エージェントに課題を渡して起動し、結果をファイルの実体から判定して記録するPythonのスクリプトである。修正の前は、子エージェントのAPIキーが、次の2つの暗黙の経路のどちらかで届いていた。APIキーは推論サービスを呼び出すための認証情報である。推論サービスは、モデルをAPIで呼び出せるように提供するサービスである。
- 環境変数の引き継ぎ: 親プロセスが持つ環境変数が、起動した子プロセスにそのまま渡ることである
- .envファイルの読み込み: 並列実行のMCPサーバが.envファイルを読む経路である。.envファイルは、APIキーのような設定の値を「名前=値」の行で書いたファイルで、gitの管理から外してある
親がOpenHands CLIで、かつ隔離した作業ディレクトリで実行した場合だけ、2つの経路のどちらでもAPIキーが子エージェントに届かなかった。隔離した作業ディレクトリは、git worktreeで作った、リポジトリの別の作業ディレクトリである。この整理は研究の記録にある3つの条件を組み合わせたもので、研究の記録にこの形の文は無い。3つの条件は、節「実行記録を残した再実行による原因の切り分け」で説明する。
修正した後は、測定用のスクリプトが、APIキーをMCPサーバの設定のenv欄に書いて明示的に渡す。MCPサーバの設定のenv欄は、コーディングエージェントの設定ファイルの欄である。この欄には、MCPサーバごとに、起動するプロセスに渡す環境変数を書く。欄の名前は、OpenCodeではenvironment、残りの2つではenvである。
APIキーが必要なのに無いときは、並列実行のMCPサーバが子エージェントを起動する前に止まり、実行記録のファイルを失敗にする。実行記録のファイルは、並列実行のMCPサーバが1回の呼び出しごとに書くJSONのファイルである。起動した子エージェントの数と、完了した子エージェントの数と、状態の欄を持つ。
修正の前と後の経路を、次の図に示す。
修正の前
測定用のスクリプトを起動したシェル (APIキーを読み込んである)
└ 親エージェント
└ 並列実行のMCPサーバ
│ 経路1: 環境変数の引き継ぎ
│ 親がOpenHands CLIのときは届かなかった
│ 経路2: リポジトリの最上位の.envファイルを読む
│ 隔離した作業ディレクトリには.envファイルが無い
└ 子エージェント (APIキーの値は空の文字列)
修正の後
測定用のスクリプト
└ MCPサーバの設定のenv欄にAPIキーを書く
└ 並列実行のMCPサーバ
├ APIキーがある: 子エージェントを起動する
└ APIキーが必要なのに無い: 起動する前に止まり、実行記録のファイルを失敗にする
比較の測定の条件と、親エージェントごとの子エージェントの完了の数
この節では、比較の測定の条件と、親エージェントごとの結果を表で示す。
比較の測定の条件は次のとおりである。
- バージョン: バージョン1.16.0のOpenHands CLIと、バージョン0.21.13のQwen Codeと、バージョン1.18.18のOpenCodeを使った
- モデル: 全実行で1種類に固定し、推論サービスのOpenAI互換のエンドポイント経由で呼び出した
- 課題: 独立した8つのプログラミングの課題である。各課題は課題文とテストのスクリプトを持つ
- 親エージェントへの指示: 8件を漏れなく仕上げることと、テストのファイルを書き換えないことの2つである。ツールの名前は指示に出していない
- 並列実行のMCPサーバの渡し方: 各コーディングエージェントの設定ファイルに登録した。登録先は3つで違う。Qwen Codeの登録先は、作業ディレクトリに置く設定ファイルである。OpenCodeの登録先も、作業ディレクトリに置く設定ファイルである。OpenHands CLIの登録先は、専用の保存ディレクトリに置くmcp.jsonである
- 子エージェント: どの親エージェントの場合も、Qwen Codeの非対話モードで起動した
次の表は、並列実行のMCPサーバの呼び出しが起きた実行を、親エージェントごとにまとめたものである。
| 親エージェント | 呼び出しが起きた実行 | 実行記録のファイル | 起動した子エージェント | 完了した子エージェント |
|---|---|---|---|---|
| Qwen Codeの親 | 3回 | 実行ごとに1件、1件、2件 | 実行ごとに8件 | 実行ごとに8件、8件、7件 |
| OpenCodeの親 | 1回 | 3件 | 合計16件 | 合計8件 |
| OpenHands CLIの親 | 3回 | 合計4件 | 合計32件 | 合計0件 |
親がOpenHands CLIの3回の実行では、起動した子エージェント32件のうち、完了は0件だった。親がOpenCodeの実行では、親エージェントが編成のスクリプトの誤りを自分で修正して、実行し直した。編成のスクリプトは、並列実行のMCPサーバが実行する、子エージェントの起動の手順を書いたスクリプトである。
親がOpenHands CLIの3回の実行でも、8つの課題はすべて合格し、テストのファイルの書き換えは0件だった。記録からは、子エージェントが完了しなかった分を親エージェントが自分で解いたと読める。ただし、研究の記録に親エージェントの作業の内訳は無い。
子エージェントがすべて失敗しても結果に表れなかった判定の作り
この節では、子エージェントがすべて失敗した結果が、比較の結果として扱われ続けた仕組みを説明する。
測定用のスクリプトは、並列実行のMCPサーバが呼び出されたかを、実行記録のファイルがあるかどうかで判定した。実行記録のファイルは並列実行のMCPサーバのプロセスだけが書くので、呼び出しが無ければ作られない。
測定用のスクリプトは、子エージェントの起動の数と完了の数を、実行記録のファイルの欄を合計して記録した。課題の合否は、テストのファイルを元に戻してから各課題のテストを実行し、合格した課題の数で記録した。
子エージェントがすべて失敗しても、次の3つの理由で、失敗は結果に表れなかった。
- 実行記録のファイルがあれば、測定用のスクリプトはその実行を呼び出しありとし、結果の欄をsuccessにした。子エージェントが1件も完了していなくても、結果の欄はsuccessになる
- 並列実行のMCPサーバが書いた実行記録のファイルでも、状態の欄はすべて正常を示すokだった
- 8つの課題はすべて合格していたので、課題の合否からも失敗は見えなかった
親がOpenHands CLIで子エージェントの完了が0件だった結果は、約1日のあいだ、比較の測定の結果として扱われた。
実行記録を残した再実行による原因の切り分け
この節では、原因をどう切り分けたかを、作業の順に説明する。研究の記録では、AIエージェントが実装し、測定し、PRに対応した。このAIエージェントは、PRの差分を調べるレビュー用のAIエージェントとは別に動く。
AIエージェントは、親がOpenHands CLIの条件を1回だけ再実行した。このときは、実行記録のファイルを置くディレクトリを、実行の後も消さずに残した。取り出した記録では、8件の子エージェントがすべて、起動からおよそ1.2秒で終了していた。終了の理由は、認証の方式が選ばれていないという内容のエラーだった。
このエラーの文は、バージョン0.21.13のQwen Codeの、非対話モードの認証を調べるファイルにある。Qwen Codeは、非対話モードで起動したとき、認証の方式を、コマンドの引数と環境変数と設定ファイルから決める。どれからも決まらなければ、このエラーで止まる。
原因は次の3つの条件が重なったことだった。
- 親がOpenHands CLIのときは、親プロセスの環境変数が、並列実行のMCPサーバのプロセスに届かなかった。親がQwen CodeかOpenCodeのときは届いたので、シェルに読み込んだAPIキーが子エージェントまで届いていた
- 並列実行のMCPサーバは、環境変数にAPIキーが無いとき、自分のリポジトリの最上位のディレクトリの.envファイルを読む作りだった。比較の測定は隔離した作業ディレクトリで実行しており、そのディレクトリに.envファイルは無かった
- 測定用のスクリプトは、APIキーをMCPサーバの設定のenv欄に書いていなかった
並列実行のMCPサーバは、子エージェントを起動するとき、APIキーの値が取れなければ、空の文字列を環境変数に入れていた。
それ以前にも、親がOpenHands CLIの別の測定があった。この測定では、並列実行のMCPサーバを明示して呼び出させ、子エージェント1件が完了していた。研究の記録には、このときは主たる作業ディレクトリで実行して.envファイルが読まれた、という説明が最もよく合うと書かれている。どちらの作業ディレクトリで実行したかの記録は無いので、この説明は確定していない。
親プロセスの環境変数がMCPサーバに届くかどうかの実装ごとの違い
この節では、親プロセスの環境変数がstdio形式のMCPサーバに届くかどうかを、公開のソースコードで実装ごとに確かめた結果を示す。確認日は2026-09-29である。
次の表は、stdio形式のMCPサーバを起動するときに、各実装がMCPサーバのプロセスに渡す環境変数をまとめたものである。
| 実装 | MCPサーバのプロセスに渡す環境変数 | 設定のenv欄の扱い | 出典 |
|---|---|---|---|
| MCPの公式Python SDK | 既定では、引き継いで安全な環境変数の一覧だけである。POSIXではHOME、LOGNAME、PATH、SHELL、TERM、USERの6つである | 6つの上に重ねて渡す | stdioクライアントのソースコード |
| MCPの公式TypeScript SDK | POSIXでは、Python SDKと同じ6つである | 一覧の上に重ねて渡す | stdioクライアントのソースコード |
| バージョン0.21.13のQwen Code | 親プロセスの環境変数の全部である。この製品のデーモンと、その子プロセスの認証に使う3つの環境変数だけを除く | 全部の上に重ねて渡す | MCPクライアントのソースコード |
| バージョン1.18.18のOpenCode | 親プロセスの環境変数の全体である | environment欄を全体の上に重ねて渡す | MCPの処理のソースコード |
| バージョン1.16.0のOpenHands CLI | 依存の経路を読むと、MCPの公式Python SDKの既定の6つである | 設定のenv欄をMCPの公式Python SDKの起動の引数に渡す | 依存の定義、openhands-sdkのMCPの処理、fastmcpのstdioの処理 |
各行の補足は次のとおりである。
- MCPの公式Python SDKの同じ既定は、1.x系のstdioクライアントのソースコードにもある。最新のリリースは、2026-09-07に公開されたv2.2.0である
- Qwen Codeには、渡さない値を取り除く関数のファイル(sanitize-child-env.ts)がある。このファイルのコメントには、除く対象を内部用の値に限る理由が書かれている。理由は、利用者がシェルで実行するコマンドが、第三者の認証情報の引き継ぎに依存することである
- 2026-09-26にQwen Codeの0.24.6が公開された。その後のmainブランチでも、CLIのQwen Codeが親プロセスの環境変数の全体を引き継ぐ作りは同じである
- OpenCodeのdevブランチでも、作りは同じである。最新のリリースは、2026-09-28に公開されたv1.18.33である
- バージョン1.16.0のOpenHands CLIは、依存の定義でopenhands-sdkの1.21.0を固定している。openhands-sdkのMCPの処理は、設定をfastmcpのMCPの設定の型に渡す。fastmcpの現在のソースコードは、stdio形式のMCPサーバの設定のenv欄を、そのまま起動の引数に渡す。起動の引数の渡し先は、MCPの公式Python SDKである。OpenHands CLIの最新のリリースは、2026-05-08に公開された1.16.0で、測定に使ったバージョンと同じである
OpenHands CLIの行は、MCPの部分のソースコードを読んで得た説明である。この説明は、親がOpenHands CLIのとき環境変数が届かなかった観測に、最もよく合う。ただし、測定のときに入っていたfastmcpとMCPの公式Python SDKの正確なバージョンは確かめていない。そのため、この説明は、測定の環境で経路の全体を確かめた結果ではない。観測した事実は、この測定の起動の仕方に限られる。親がバージョン1.16.0のOpenHands CLIのとき、親プロセスの環境変数はMCPサーバに届かなかった。
3つのコーディングエージェントの公式ドキュメントには、環境変数を渡す欄の説明がある。確認したページは次の3つである。
一方で、3つのページのどれにも、起動したMCPサーバが親の環境の全体を受け取るかどうかの記述は無い。引き継ぎの挙動はソースコードの実装でだけ決まっていて、バージョンで変わりうる。
どちらの作りにも理由がある。公式のSDKの既定は、引き継ぐ環境変数を絞って、秘密の値の漏えいを避ける。Qwen Codeは、除く対象を製品の内部用の値に限っている。ソースコードのコメントには、利用者がシェルで実行するコマンドが第三者の認証情報の引き継ぎに依存する、という理由が書かれている。バージョン0.21.13のQwen Codeは、MCPサーバを起動するときも、同じ関数だけを通して親の環境変数を渡す。修正した後の測定用のスクリプトは、どちらの作りにも依存しない。測定用のスクリプトが、APIキーをMCPサーバの設定のenv欄に書いて明示的に渡すためである。
MCPサーバの設定のenv欄でAPIキーを明示的に渡す修正と測り直し
この節では、APIキーの渡し方の修正と、修正した後の測り直しの結果を示す。
AIエージェントは測定用のスクリプトを修正した。修正した後の測定用のスクリプトは、子エージェントが使うAPIキーを、MCPサーバの設定のenv欄に書いて明示的に渡す。AIエージェントは、並列実行のMCPサーバを明示して呼び出させる別の測定用のスクリプトも、同じ形に修正した。env欄に書いた値が3つのコーディングエージェントのすべてでMCPサーバに渡ることは、それ以前に別の値の受け渡しで確かめてあった。
AIエージェントは、OpenHands CLIのmcp.jsonにAPIキーが書かれることを、単体テストで確かめる形にした。その後、単体テストを3つのコーディングエージェントのすべてに広げた。
次の例は、MCPサーバの設定のenv欄にAPIキーを書く形を、公式ドキュメントの形に合わせて書き起こしたものである。サーバの名前と環境変数の名前と値は仮のものである。1つ目はQwen Codeの形で、OpenHands CLIのmcp.jsonも同じ形である。2つ目はOpenCodeの形である。
{
"mcpServers": {
"parallel-runner": {
"command": "python",
"args": ["-m", "example_parallel_runner"],
"env": {
"EXAMPLE_API_KEY": "replace-with-your-api-key"
}
}
}
}
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"parallel-runner": {
"type": "local",
"command": ["python", "-m", "example_parallel_runner"],
"environment": {
"EXAMPLE_API_KEY": "replace-with-your-api-key"
}
}
}
}
AIエージェントは、修正した後、親がOpenHands CLIの2つの条件を、1回ずつ測り直した。2つの条件は、エージェント向けの指示ファイル一式を置くかどうかで違う。エージェント向けの指示ファイル一式は、作業ディレクトリに置くAGENTS.mdと、スキルのファイルと、メモリのファイルの組である。次の表は、2つの条件で測り直した結果である。
| 条件 | 起動した子エージェント | 完了した子エージェント | 合格した課題 | 所要時間 |
|---|---|---|---|---|
| 指示ファイル一式を置く | 8件 | 8件 | 8つのうち8つ | 556.1秒 |
| 指示ファイル一式を置かない | 合計16件 | 合計1件 | 8つのうち8つ | 761.1秒 |
時間の上限は900秒だった。指示ファイル一式を置いた条件では、親エージェントが自分から並列実行のMCPサーバを呼び出した。子エージェント8件はすべて完了した。この実行は、親がOpenHands CLIの条件で、親エージェントが自分から並列実行のMCPサーバを呼び出し、起動した子エージェントがすべて完了した初めての実行だった。
指示ファイル一式を置かない条件でも呼び出しは起き、実行記録のファイルは3件だった。この条件で起動した16件のうち15件は、APIキーとは別の理由で完了しなかった。研究の記録には、この15件に、編成のスクリプトの誤りを修正して実行し直す型を含むと書かれている。この15件の原因の観測を続けることも、研究の記録に書かれている。
AIエージェントはこの結果から、次のように結論した。子エージェントの完了が0件だった原因は、コーディングエージェントの能力の差ではなく、測定用のスクリプトの作りにあった。AIエージェントは、レビュー用のAIエージェントの指摘を受けて、結論の範囲を書き直した。レビュー用のAIエージェントは、PRを作った後に、実装したエージェントとは別に起動するAIエージェントである。差分を読み取り専用で調べる。AIエージェントは、書き直した結論で、APIキーによって子エージェントがすべて失敗した問題が解消したと言い切った。残る15件の未完了は、APIキー以外の理由として分けた。
測り直しの2回の実行は、原因の切り分けのための追加の測定として、比較の集計とは別に記録した。測り直しは各条件で1回ずつだった。そのため、親がOpenHands CLIのときに、起動した子エージェントがすべて完了する頻度は、この記録からは言えない。
失敗を隠さない仕組みと、同じ取り残しを防ぐ単体テスト
この節では、APIキーの修正の後のPRで追加した、失敗を隠さない仕組みと、同じ取り残しを防ぐ単体テストを説明する。
AIエージェントは、APIキーが必要なのに無いときの処理を追加した。この場合、並列実行のMCPサーバは子エージェントを起動する前に止まり、実行記録のファイルを失敗にする。止まったことを子エージェントの1件の失敗として扱わず、呼び出しの全体を失敗にする。
このPRのレビューは3回あった。
- 初回のレビューで、レビュー用のAIエージェントは問題を実際に動かして示した。問題は、止める処理の例外が子エージェントの1件の失敗として扱われ、実行記録のファイルの状態が正常のまま残ることだった
- 2回目のレビューで、レビュー用のAIエージェントは、並列と直列の編成の書き方では、同じ例外がまだ正常のまま扱われることを示した
- 3回目のレビューを受けて、AIエージェントは、止める処理が一度動いたら実行記録のファイルに失敗の印を残す形にした。編成のスクリプトが例外を受け止めて握りつぶしても、この印は残る
AIエージェントは、同じPRで、APIキーが空のときに、空の文字列で呼び出し側の環境変数を上書きしていた処理をやめた。修正した後の並列実行のMCPサーバは、APIキーが無いとき、呼び出し側の環境にある認証を、そのまま子エージェントに渡す。
AIエージェントは、同じPRで、測定用のスクリプトが記録する行に、測定の側に不備があったことを示す印を自動で付ける処理も追加した。この印が付いた行は、エージェントの能力の観測として集計に数えない。印を付ける条件は、課題の実行が次の3つをすべて満たす場合である。
- 終了コードが0でない
- テストの実行が0回である
- 起動から採点までの合計が15秒に満たない
条件を狭くした理由は、能力の不足による失敗を測定の側の不備として集計から外すと、集計が実力より良く見えることである。この印を付ける処理は、並列実行のMCPサーバの呼び出しを判定する処理とは別の処理である。
同じ型の取り残しは、別の環境変数でも起きた。子エージェントのQwen Codeには、隔離したディレクトリを環境変数で渡す。このディレクトリは、利用者のホームディレクトリの代わりに使う。測定用のスクリプトは、親がQwen Codeのときだけ、親を起動する時点でこの値を設定していた。そのため、この値は、親がQwen Codeのときだけ、環境変数の引き継ぎで子エージェントまで届いた。親が残りの2つのときは、親を起動する時点でこの値が無いので、子エージェントに届かなかった。
AIエージェントは、この値もMCPサーバの設定のenv欄に書き、3つのコーディングエージェントのすべてに明示的に渡す形にした。この形は単体テストで確かめた。レビュー用のAIエージェントは、同じ取り残しがある2か所を指摘した。2か所は、別の測定用のスクリプトと、結合テストだった。AIエージェントは2か所とも同じ形に修正した。
AIエージェントは、その後のPRで、MCPサーバの設定のenv欄を組み立てる処理を、1つの関数にまとめた。呼び出し側が別々に値を設定すると、登録する場所が増えたときに、同じ取り残しが起きるためである。単体テストは、env欄に入る環境変数の名前の集合が、決めた集合と完全に一致することを確かめる。新しい認証情報が気づかれずに設定ファイルに書かれると、この単体テストが失敗する。
APIキーをenv欄に書いたことで追加した保護
この節では、APIキーを明示的に渡す修正によって生じた新しいリスクと、同じPRで追加した保護を説明する。
修正の後は、env欄に書いたAPIキーが、作業ディレクトリの中の設定ファイルに値のまま書かれる。レビュー用のAIエージェントは、このPRに7件の指摘を返した。指摘には、Critical、High、Medium、Lowの4段階の重大度が付く。7件の重大度はすべてMediumだった。AIエージェントは、7件のうちAPIキーの保護に関わる指摘を受けて、次の2つを修正した。
- 測定用のスクリプトの記録とコミットに、APIキーの値が入る経路を塞いだ。記録を書く前にAPIキーらしい値を機械的に伏せる処理を追加し、単体テストで確かめた。コミットの前にAPIキーの値の混入を調べる検査も修正し、APIキーの値の入ったファイルをステージして、コミットが拒否されることを確かめた
- APIキーは、子エージェントを起動する並列実行のMCPサーバの設定にだけ書く形にした。APIキーを使わない別のMCPサーバの設定には書かない。この形も単体テストで確かめた
比較の測定を設計するときの2つの規則
この節では、この記録から一般化できる、比較の測定を設計するときの規則を2つ示す。研究の記録に、この形の文は無い。
- 比較の測定を始める前に、コーディングエージェントごとに違う暗黙の挙動を洗い出す。親プロセスの環境変数がMCPサーバに届くかどうかは、その挙動の1つである
- 認証情報を環境変数の引き継ぎに任せず、測定用のスクリプトから明示的に渡す
規則1の根拠は、親がOpenHands CLIのときだけ環境変数が届かなかった観測と、引き継ぐ範囲が実装ごとに違うソースコードである。規則2の根拠は、env欄で明示的に渡す修正と測り直しの節と、失敗を隠さない仕組みの節に書いた事実である。
補足として、外部の評価の実行基盤でも、同じ型の失敗が起きた。AIエージェントは、外部の評価の実行基盤で、Qwen CodeをACPで動かした。ACPは、エディタとコーディングエージェントをつなぐための公開の手順である。この実行は、Qwen Codeの起動とACPの接続までは進み、認証の段階でエラーになった。課題の得点は0だった。AIエージェントは、その時点の実行基盤を起動する処理の中に、モデルの認証の情報をコンテナに渡す設定の項目を見つけられなかった。研究の記録では、これを原因としている。同じリポジトリの測定用のスクリプトは、環境変数と設定ファイルの写しを渡して、同じ認証を通していた。AIエージェントは、この実行を能力の観測でなく、測定の側の不備として記録した。
親プロセスの環境変数の引き継ぎの挙動は、公式ドキュメントでなく、使っているバージョンのソースコードで確かめられる。読む箇所は、stdio形式のMCPサーバを起動する処理である。その処理が親の環境の全体を渡すか、一覧で絞るかを確かめてから、そのバージョンのコーディングエージェントを比較の測定に使うとよい。
参考にした資料
本文で参照した公開の資料は次のとおりである。いずれも2026-09-29に確認した。
- MCPの公式Python SDKのstdioクライアントのソースコード https://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/client/stdio.py
- MCPの公式Python SDKの1.x系のstdioクライアントのソースコード https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/src/mcp/client/stdio/__init__.py
- MCPの公式Python SDKのv2.2.0のリリースのページ https://github.com/modelcontextprotocol/python-sdk/releases/tag/v2.2.0
- MCPの公式TypeScript SDKのstdioクライアントのソースコード https://github.com/modelcontextprotocol/typescript-sdk/blob/main/packages/client/src/client/stdio.ts
- バージョン0.21.13のQwen CodeのMCPクライアントのソースコード https://github.com/QwenLM/qwen-code/blob/v0.21.13/packages/core/src/tools/mcp-client.ts
- バージョン0.21.13のQwen Codeの、渡さない値を取り除く関数のソースコード https://github.com/QwenLM/qwen-code/blob/v0.21.13/packages/core/src/utils/sanitize-child-env.ts
- バージョン0.21.13のQwen Codeの、非対話モードの認証を調べるソースコード https://github.com/QwenLM/qwen-code/blob/v0.21.13/packages/cli/src/validateNonInterActiveAuth.ts
- Qwen Codeの0.24.6のリリースのページ https://github.com/QwenLM/qwen-code/releases/tag/v0.24.6
- バージョン1.18.18のOpenCodeのMCPの処理のソースコード https://github.com/anomalyco/opencode/blob/v1.18.18/packages/opencode/src/mcp/index.ts
- OpenCodeのv1.18.33のリリースのページ https://github.com/anomalyco/opencode/releases/tag/v1.18.33
- バージョン1.16.0のOpenHands CLIの依存の定義 https://github.com/OpenHands/OpenHands-CLI/blob/1.16.0/pyproject.toml
- OpenHands CLIの1.16.0のリリースのページ https://github.com/OpenHands/OpenHands-CLI/releases/tag/1.16.0
- バージョン1.21.0のopenhands-sdkのMCPの処理のソースコード https://github.com/OpenHands/software-agent-sdk/blob/v1.21.0/openhands-sdk/openhands/sdk/mcp/utils.py
- fastmcpのstdioの処理のソースコード https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/client/transports/stdio.py
- OpenHands CLIのMCPサーバの公式ドキュメント https://docs.openhands.dev/openhands/usage/cli/mcp-servers
- Qwen CodeのMCPサーバの公式ドキュメント https://qwenlm.github.io/qwen-code-docs/en/developers/tools/mcp-server/
- OpenCodeのMCPサーバの公式ドキュメント https://opencode.ai/docs/mcp-servers/