本記事記述および実装内容は、多くの部分をAIで処理しており、人間チェックは甘いです
WSL + Windows Chrome を CDP attach する Playwright MCP 構成と、Plan→Implement→Verify→Report→HITL の検証ワークフローを Claude Opus 4.7 で動かしてみた
はじめに
Azure / Microsoft 系ソリューションの 検証作業を体系化する ことを目的に、自分の検証用モノレポを Claude Opus 4.7 + GitHub Copilot CLI 向けに整備しました。本記事では、その構成(custom agent / skill / MCP)を end-to-end でドライランした記録と、設計上の判断を共有します。
特に、WSL + Windows Chrome という多くの開発者が直面しそうな構成で、Playwright MCP を CDP 経由で動かす際の罠と回避策を中心にまとめます。
想定読者:
- Azure 検証や調査を反復的に行うエンジニア
- WSL 上で Copilot CLI / Claude Code を使っている方
- Opus 4.7 にアップグレードして「以前と挙動が違う」と感じている方
結論
- ✅ メイン Opus 4.7 セッションをそのままオーケストレーターにするのが Anthropic 推奨であり、専用の orchestrator sub-agent を作る必要はない
- ✅ 検証ワークフローは Plan → Implement → Deploy → Verify → Report → 🛑HITL → Qiita の 7 段階で sub-agent に委譲すると役割が綺麗に分かれる
- ✅
internal-reporterとqiita-reporterは分離する(人間レビュー必須・機密削除リスト適用のため) - ⚠️ WSL の
npmが Windows 版にフォールバックしていると Playwright MCP がERR_INVALID_URLで死ぬ - ⚠️
.wslconfigの[wsl2]セクションヘッダ漏れ で mirrored networking が無言で無視される
アーキテクチャ
環境
| 項目 | バージョン |
|---|---|
| Host | Windows 11 Pro Build 26200 |
| WSL | Ubuntu 24.04 / WSL 2.6.3 / Linux 6.6.87.2 |
| Browser | Chrome 147.0.7727.138 (Windows 側) |
| Python ランタイム | uv 0.11.8 |
| Node | nodejs (apt 版) — WSL 側必須 |
| Copilot CLI | v1.0.40 |
| AI モデル | Claude Opus 4.7 (1M context) |
| 主要 MCP | Azure MCP, Playwright MCP, GitHub MCP, mermaid, markdownlint, sequential-thinking |
構築手順
Step 1: Linux 版 node/npm を WSL に入れる
sudo apt update
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# 確認
which npm # 期待: /usr/bin/npm
node --version # 期待: v20.x.x
最大の罠: WSL から which npm を打って /mnt/c/... が返ってきたら危険信号です。appendWindowsPath=true の影響で Windows 側 npm.cmd がフォールバックされ、npx @playwright/mcp@latest ... が ERR_INVALID_URL で即終了します。Linux 版 npm を入れて PATH 順位を入れ替えれば解決します。
Step 2: WSL を mirrored networking モードに
.wslconfig の [wsl2] セクションヘッダ必須 がポイント。
[wsl2]
networkingMode=mirrored
PowerShell から:
wsl --shutdown
# 数秒待つ
wsl
確認:
ip addr show | grep "inet " | grep -v 127
# Windows と同じ subnet (192.168.x.x や 10.x.x.x) が見えれば mirrored 成功
.wslconfig は INI 形式です。[wsl2] セクションヘッダなしで networkingMode=mirrored だけ書くと エラーも警告も出ずに完全無視 されます。NAT モードのまま動き続けるので気付きにくい罠です。
Step 3: Windows Chrome を debug port 起動する .bat
@echo off
chcp 65001 >nul
setlocal EnableDelayedExpansion
set "CHROME_EXE=C:\Program Files\Google\Chrome\Application\chrome.exe"
set "PROFILE_DIR=%USERPROFILE%\.chrome-azure-profile"
start "Chrome Debug" "%CHROME_EXE%" ^
--remote-debugging-port=9222 ^
--user-data-dir="%PROFILE_DIR%" ^
--no-first-run ^
--no-default-browser-check ^
--new-window ^
https://portal.azure.com/
REM 疎通確認
timeout /t 5 /nobreak >nul
curl -s -o nul -w "HTTP %%{http_code}" http://localhost:9222/json/version
pause
.bat ファイルは必ず CRLF 改行で保存 すること。WSL からテキストエディタで作ると LF 改行になり、Windows CMD が解釈失敗して 黒窓が一瞬で消える という症状になります。chcp 65001 >nul を冒頭に置くと UTF-8 コメントを含めても安全です。
Step 4: Playwright MCP を CDP attach モードに設定
{
"mcpServers": {
"playwright": {
"type": "local",
"command": "npx",
"args": [
"-y",
"@playwright/mcp@latest",
"--cdp-endpoint", "http://localhost:9222"
],
"tools": ["*"]
}
}
}
これで WSL 側の Playwright MCP が 既存の Windows Chrome を制御 します。MFA 済セッション・拡張機能・ブックマークがそのまま使えるので、Azure Portal 検証で大変便利です。
Step 5: Custom agent と Skill を配置
GitHub Copilot CLI は以下のレイアウトを認識します:
.github/agents/<name>.agent.md # custom agent (frontmatter + プロンプト)
.agents/skills/<name>/SKILL.md # skill (lazy load 参照資料)
私は 7 本の agent (planner / implementer / deployer / verifier / ui-verifier / internal-reporter / qiita-reporter) を配置しました。
Step 6: Python は uv で統一する
#!/usr/bin/env python
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "requests>=2.31",
# ]
# ///
import requests
# ...
実行:
uv run check_learn.py
PEP 723 inline metadata で依存を宣言すると、pip install も venv も不要で、初回でも 50ms 程度で依存解決+実行されます。MCP サーバなどの単一ファイルツールはこの形式が圧倒的に楽です。
ハマりポイント
H1: Playwright MCP の page reference が古い tab を握ったままになる
検証中に Chrome のタブが閉じられると、Playwright MCP セッションは古い page ハンドルを握ったまま新しい操作を拒否します:
browserBackend.callTool: Target page, context or browser has been closed
回避策: browser_close を一度呼んで状態をクリアしてから browser_navigate を呼ぶ。MCP サーバの再起動は不要。
H2: WSL の npm が Windows 側にフォールバックしている
appendWindowsPath=true (デフォルト) で Linux 版 nodejs を入れていない場合、npx ... が /mnt/c/.../npm.cmd を呼んでしまい、Linux パスを引数に渡すと ERR_INVALID_URL で即死します。
回避策: apt install -y nodejs または NodeSource 経由で Linux 版を入れる。詳細は Step 1。
H3: .wslconfig の [wsl2] セクションヘッダ漏れ
networkingMode=mirrored だけ書いても完全無視されます。[wsl2] セクション必須。詳細は Step 2。
H4: Windows .bat の改行コードと文字コード
WSL でテキストエディタで作ると LF + UTF-8 BOMなしになり、CMD が解釈失敗して即終了します。CRLF + 冒頭に chcp 65001 >nul で解決。詳細は Step 3。
検証結果
実 Azure リソースを使わず、Microsoft Learn の Azure ドキュメントトップを題材に E2E ドライラン:
| シナリオ | 結果 | 備考 |
|---|---|---|
| HTTP 疎通 (smoke test) | ✅ PASS | TTFB 310ms |
| ページタイトル (Playwright UI) | ✅ PASS | "Azureドキュメント | Microsoft Learn" |
| 主要ナビゲーション存在 | ✅ PASS | header 1 + nav 4 |
すべての phase を 6 分で通過:
| Phase | 担当 role | 結果 |
|---|---|---|
| Plan | planner | ✅ verification-plan.md 生成 |
| Implement | implementer | ✅ uv run で動作 |
| Deploy | deployer | ⏭️ N/A (理由明示) |
| Verify | verifier (+ ui-verifier) | ✅ 3 シナリオ全 PASS |
| Internal Report | internal-reporter | ✅ REPORT.md 生成 + HITL 待ち停止 |
| 🛑 HITL ゲート | (人間) | ✅ 5項目回答 |
| Qiita Report | qiita-reporter | ✅ 本記事 |
まとめ
-
Opus 4.7 で「sub-agent を控えめに spawn する」傾向が強くなった ため、
copilot-instructions.mdに並列 fan-out を明示するのが効きます -
internal-reporterとqiita-reporterの責務分離 + 間に HITL ゲート を挟むことで、テナント ID やコスト実数の流出を防げます。Opus 4.7 の literal instruction following が強い特性ともマッチします - WSL + Windows Chrome の CDP attach 構成は MFA 済セッションをそのまま使えて便利。ただし npm / .wslconfig / .bat 改行コード の罠が積み重なるので、本記事の Step 1〜4 を順に踏むのがおすすめです
-
uv による Python 統一は単一ファイルスクリプト(PEP 723)が特に強力で、MCP サーバ等の小物ツールは
requirements.txtもvenvも不要になります
検証ワークフロー設計の詳細(agent 定義、skill 構成、MCP 設定)は別記事にまとめる予定です。