
こんにちは、X Innovation推進室の小久保です。
今回は、Chrome拡張機能の開発効率向上を目的とした取り組みについてご紹介します。
Googleが公開した Chrome DevTools MCP を活用し、Kiro-CLI を組み合わせることで、Chrome拡張機能を自然言語ベースでスピーディに開発する手法を検証しました。
既に多くの方が取り組まれている領域ではありますが、もし何かの参考になれば幸いです。
Chrome DevTools MCPは、パフォーマンス分析やブラウザデバッグ、自動化を特徴としています。
本記事では、これらの機能を応用した拡張機能開発の手法をご紹介し、従来の開発プロセスと比較した効果や課題についても検証結果をお伝えします。
参考リンク:
Chrome DevTools MCP(GitHub)
Chrome DevTools MCP 解説記事(Chrome Developers)
前提条件
必要な環境
- Node.js: v18以上(ホットリロード用のローカルサーバー実行に必要)
- Google Chrome Beta: M144以上(Chrome DevTools MCP の
autoConnect機能を利用するため) - Kiro-CLI(または他のMCP対応AIエージェント)
環境設定
エムオーテックスの一部ではKiro-CLIを利用しているため、その設定例を提示します。他のAIエージェントをご利用の場合は適宜読み替えてください。
.aws/amazonq/mcp.json
{ "mcpServers": { "chrome-devtools": { "command": "npx", "args": [ "-y", "chrome-devtools-mcp@latest", "--autoConnect", "--channel=beta" ] } } }
設定のポイント:
--autoConnect: Chrome DevTools MCPサーバーが実行中のChromeインスタンスに自動接続
--channel=beta: Chrome M144が安定版に到達するまで指定が必要(執筆時点では143系が安定版)
Chrome Betaのインストールと設定
Google Chrome Beta をインストールします。
Chrome DevTools MCPの説明記事に記載があるのですが以下の機能を利用するためとなります。
Chrome DevTools MCP サーバーがリモート デバッグ接続をリクエストできる新機能が追加
chrome://inspect/#remote-debugging にアクセスし、Remote debugging を有効化してください。

これで準備は完了です
動作確認(Chrome DevTools MCP)
まずは簡単な指示を行い、Chrome DevTools MCPの機能を確認しました。
ページ遷移の確認
自然言語でページを開く指示を出し、navigate_page を使ったタブ起動を確認しました。
起動時にはリモートデバッグ許可のダイアログが表示されますが、許可を押下します。

無事に画面がオープンしました。

フォーム入力とログイン
続いて、ログインフォームへの入力が動作するか確認しました。
Kiro-CLIがChrome DevTools MCPの take_snapshot(DOM構造キャプチャ)を用いて画面構成を解釈し、fill_form で必要なフォームに値を入力しています。
注意: take_snapshot と take_screenshot は異なる機能です。
前者はDOM構造を取得し、後者は画像をキャプチャします。

その後、click 処理を実行し、wait_for でログイン後の画面描画を待機します。

wait_forを用いてログイン後の画面の描画がされることを待機してくれています。

拡張機能開発の準備
Chrome拡張機能では、ブラウザ上の特定ページの要素を変更したり、独自機能を提供することが可能です。
今回はChrome拡張機能として、LANSCOPE エンドポイントマネージャー クラウド版 の管理画面において、ボタンの色味や並び順を変更するような機能の実装を試してみます。
開発環境のセットアップ
拡張機能の開発体験を向上させるため、ホットリロード対応の環境を構築しました。
通常、コード変更後は拡張機能の管理画面で手動再読み込みが必要ですが、これを自動化することでAIに開発を任せる際の手間を削減します。
プロジェクト構成
manifest.json
{ "manifest_version": 3, "name": "Simple Extension", "version": "1.0.0", "description": "A simple Chrome extension with hot reload", "permissions": ["tabs"], "background": { "service_worker": "background.js" }, "content_scripts": [ { "matches": ["<all_urls>"], "js": ["content.js"] } ] }
package.json
{ "name": "chrome-extension-template", "version": "1.0.0", "scripts": { "dev": "node reload-server.js", "build": "node build.js" } }
content.js
// 今回はここにコードを追記していきます console.log('Content script loaded');
background.js
const DEV_MODE = true; // Set to false for production if (DEV_MODE) { const RELOAD_INTERVAL = 1000; let lastModified = Date.now(); async function checkForChanges() { try { const response = await fetch('http://localhost:8080/reload'); const data = await response.json(); if (data.timestamp > lastModified) { lastModified = data.timestamp; const tabs = await chrome.tabs.query({}); tabs.forEach(tab => chrome.tabs.reload(tab.id)); setTimeout(() => chrome.runtime.reload(), 100); } } catch (e) { // Server not running } } setInterval(checkForChanges, RELOAD_INTERVAL); } chrome.runtime.onInstalled.addListener(() => { console.log('Extension installed'); });
reload-server.js
const http = require('http'); const fs = require('fs'); const path = require('path'); const PORT = 8080; const WATCH_DIR = __dirname; let lastModified = Date.now(); fs.watch(WATCH_DIR, { recursive: true }, (eventType, filename) => { if (filename && !filename.includes('node_modules')) { lastModified = Date.now(); console.log(`File changed: ${filename}`); } }); http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }); res.end(JSON.stringify({ timestamp: lastModified })); }).listen(PORT, () => { console.log(`Hot reload server running on http://localhost:${PORT}`); });
build.js
const fs = require('fs'); const path = require('path'); const distDir = path.join(__dirname, 'dist'); if (!fs.existsSync(distDir)) { fs.mkdirSync(distDir); } const files = ['manifest.json', 'content.js']; files.forEach(file => { fs.copyFileSync(file, path.join(distDir, file)); }); const bgContent = fs.readFileSync('background.js', 'utf8') .replace('const DEV_MODE = true;', 'const DEV_MODE = false;'); fs.writeFileSync(path.join(distDir, 'background.js'), bgContent); console.log('Build complete! Check the dist/ folder');
.gitignore
node_modules/ dist/ *.zip
開発サーバーの起動
npm run dev
Chromeで拡張機能を読み込み
chrome://extensions/を開く- 「デベロッパーモード」を有効化
- 「パッケージ化されていない拡張機能を読み込む」からプロジェクトフォルダを選択
本番ビルド
npm run build
dist/ フォルダに本番用ファイルが生成され、ホットリロード機能は自動的に無効化されます。
Chrome DevTools MCPを使った開発
Chrome DevTools MCPでは、画面のキャプチャを取得してHTMLを解析したり、フォームに値を入力したり、性能計測を行うことが可能です。
拡張機能で画面上の要素を特定する際、通常はDevToolsを使って手作業でHTMLを確認しますが、Chrome DevTools MCPを使うことで、自然言語ベースでDOM要素を特定し、コードを生成できると考えています。
拡張機能で画面上の要素を特定するケースの場合、基本的にDevtoolを使って手作業でHTMLの内容を確認することが多いかと思います。

Chrome DevTools MCPを使うと HTML上のDOMのセレクター取得(take_snapshot)を行って、それを拡張機能側で利用することで自然言語をベースでコードが開発できると思います。
AIエージェントへの拡張機能の認識
まず、AIエージェントのコンテキストに現在の拡張機能の内容を含めるため、ファイルを読み込ませて説明させました。


認識をしたのでここから開発の指示を与えてみます。
自然言語による要素の特定と改修
LANSCOPE エンドポイントマネージャー クラウド版の画面には、以下のようなボタンが存在しています。

ここで、ボタンの見栄えや並び順を変更する指示を出し、拡張機能で加工してみます。
今回はシンプルに、画面上のボタンのラベル名を指示するだけで該当要素を特定できました。
通常であれば、DevToolsでDOMを手動確認する必要がありますが、その手間が省けました。

要素が特定できたので、試しにボタンの並び順、背景色、枠線、ラベル色を変更してもらいました。
DOMの取得やコードの入力は手動で行っていません。

また、evaluate_script を使うことで、現在選択されているページ内のJavaScript関数を評価できるため、実際のHTMLベースで状況を確認することも可能です。

これにより、自然言語で指示を出しつつ、拡張機能の改修内容をすぐに反映・確認するという開発フローが実現できました。
開発効果と制約
開発効率の向上
- DOM要素特定の自動化: 従来のDevTools手動確認が不要に
- 自然言語による指示: 技術的な詳細を意識せずに開発可能 (ただし、言語やフレームワークの特性を意識した指示などある程度の知見は必要かと思います)
- リアルタイム確認: ホットリロードとの組み合わせで即座に結果確認 (拡張機能側の構成による部分は大きいですが)
現時点での制約
take_screenshotやtake_snapshot使用時のコンテキストオーバーフロー- 複雑なDOM構造での要素特定精度 (iframe系の要素は少し扱いが難しいかもしれません)
- 大規模な拡張機能開発での適用範囲
まとめ
今回の試みでは、Chrome DevTools MCPとKiro-CLIを組み合わせることで、自然言語ベースでChrome拡張機能を開発することができました。
細かい制約は上記の通りございますが従来にない指示レベルで拡張機能の開発が進められるため、非常に新鮮な体験でした。
今後も、この技術を活用してできることを模索していきたいと思います。