
こんにちは。株式会社アドグローブ ソリューション事業部の新川です。
今回はGemini CLIの「拡張機能」とchrome-devtools-mcpについてご紹介します。
はじめに
最近はClaude CodeやCodexなどのニュースで盛り上がっていますが、GoogleのGeminiも見逃せません。
先日「Gemini CLI Extension」が発表され、拡張機能のインストールが可能になりました。
生成AIによるコード生成やレビュー、ドキュメント作成などはもちろん便利ですが、MCPの設定やSuper Claudeのように環境の構築手順が複雑なものも多いです。
その点、Gemini CLI Extensionは非常にシンプルで、誰でも簡単に導入できます。
この記事では、Gemini CLI Extensionがどのように開発体験を変えるのか、特に「chrome-devtools-mcp」という拡張機能を中心に紹介します。
Gemini CLI Extensionとは?

Gemini CLI Extensionは、Gemini CLIの機能を自由に追加・拡張できる仕組みです。
💡 Gemini CLIについて
Gemini CLI自体の基本的な使い方については、弊社ブログの「GoogleのAIエージェント「Gemini CLI」を試してみる」で詳しく解説していますので、初めての方はそちらもご参照ください。
Extensionのインストール方法
Extensionの最大の魅力は、その導入の手軽さです。
gemini extensions install <GitHubリポジトリのURL>
たったこれだけのコマンドで、Gemini CLIに新しい機能を追加できます。
これまでのように複雑なセットアップや設定は不要です。

Extensionのアップデート方法
アップデートも非常に簡単です。
gemini extensions update <拡張機能名>
このコマンド一つで、インストール済みの拡張機能を最新バージョンに更新できます。 開発中のツールが頻繁に更新される場合でも、常に最新の状態で利用できるのは大きなメリットです。
さらに、Gemini CLIはログイン時にアップデート可能な拡張機能があると通知してくれるため、更新を見逃すこともありません。

chrome-devtools-mcpが便利すぎる
数ある拡張機能の中でも、特にフロントエンド開発者にとって革命的なのが「chrome-devtools-mcp」です。
これは、Gemini CLIからChromeブラウザを直接操作し、デバッグやパフォーマンス分析、アクセシビリティ診断などを対話形式で実行できるようにする拡張機能です。
chrome-devtools-mcp自体はこれまでにも存在していましたが、VSCodeでMCPサーバーの設定や起動、Geminiで設定が必要など、導入が非常に面倒でした。 それが今回、Gemini CLI Extensionとして提供されることで、導入が非常に簡単になりました。
chrome-devtools-mcpのインストール
chrome-devtools-mcpのインストールも非常に簡単です。
gemini extensions install https://github.com/ChromeDevTools/chrome-devtools-mcp
これだけで、Gemini CLIにchrome-devtools-mcpが追加されます。
⚠️ セキュリティに関する重要な注意事項
ブラウザで表示している内容がGeminiに送信されます。
機密情報や個人情報を含むページ(社内システム、管理画面、個人のメールなど)での利用には十分注意してください。本番環境やプライベートな情報が含まれるページでの使用は避けることを強く推奨します。
chrome-devtools-mcpでできること
chrome-devtools-mcpで何ができるのか、特に便利な機能をいくつか紹介します。
コンソールエラーを自動修正
これまではChromeのDevToolsを開いてコンソールエラーを確認し、手動でGeminiにエラーを貼り付けて修正案をもらう必要がありました。
chrome-devtools-mcpを使えば、Gemini CLIから直接コンソールを確認し、エラーの原因特定から修正案の提示、さらにはコードの修正までを対話形式で行えます。
例:未定義のエラーを発生させるコード
誰でも一度は経験があると思いますが、エディタ上では特にエラーも出ていないのに、ブラウザのコンソールでだけ undefined エラーに遭遇する、あの嫌なパターンを例に試してみます。
const obj: any = {};
console.log(obj.a.b);
例:未定義のエラーを修正する
実際にGeminiに依頼すると、下記のように動作します:
ユーザー
http://localhost:5173/ で発生しているエラーを修正して。サーバーは起動済み。
Geminiの動作(ポイント)
Geminiに依頼すると、まるで人間が操作しているかのように、自動でブラウザを立ち上げてエラーを解決してくれます。
- ブラウザに接続: GeminiがChromeブラウザに接続し、操作を開始します。
- コンソールを確認: DevToolsのコンソールを開き、エラーメッセージを読み取ります。
- 原因を特定: エラーログから、問題が
app/routes/home.tsxにあることを突き止めます。 - コードを直接修正: エディタに戻り、原因となっていたコードを直接修正します。
- ブラウザをリロードして確認: 再びブラウザに切り替え、ページをリロード。コンソールにエラーが出ていないことを確認して、作業を完了します。
この一連の動作はchrome-devtools-mcp拡張機能によるものですが、参考までに実際のログも載せておきます。
📋 詳細なログを見る(クリックで展開)
Gemini
✦ 承知いたしました。サーバーはすでに起動済みとのことですので、次にブラウザのコンソールログを確認します。
現在開いているページをリストアップし、対象のページに接続します。
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ list_pages (chrome-devtools MCP Server) {} │
│ │
│ # list_pages response │
│ # Pages │
│ 0: http://localhost:5173/ [selected] │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ ページはすでに開いているようですね。では、コンソールに表示されているメッセージを取得して、エラーの原因を調査します。
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ list_console_messages (chrome-devtools MCP Server) {} │
│ │
│ # list_console_messages response │
│ # Console messages │
│ undefined> client:732:8: [vite] connecting... [vite] connecting... │
│ undefined> client:826:11: [vite] connected. [vite] connected. │
│ Info> react-dom_client.js?v=b2be203f:20100:53: %cDownload the React DevTools for a better development experience: │
│ https://react.dev/link/react-devtools font-weight:bold %cDownload the React DevTools for a better development experience: │
│ https://react.dev/link/react-devtools font-weight:bold │
│ undefined> client:809:28: [vite] hot updated: /app/routes/home.tsx [vite] hot updated: /app/routes/home.tsx │
│ undefined> client:809:28: [vite] hot updated: /app/routes/home.tsx [vite] hot updated: /app/routes/home.tsx │
│ undefined> client:809:28: [vite] hot updated: /app/app.css [vite] hot updated: /app/app.css │
│ undefined> client:809:28: [vite] hot updated: /app/routes/home.tsx [vite] hot updated: /app/routes/home.tsx │
│ Error> %o │
│ │
│ %s │
│ │
│ %s │
│ JSHandle@error The above error occurred in the <Home> component. React will try to recreate this component tree from scratch using the error boundary │
│ you provided, RenderErrorBoundary. %o │
│ │
│ %s │
│ │
│ %s │
│ {} The above error occurred in the <Home> component. React will try to recreate this component tree from scratch using the error boundary you │
│ provided, RenderErrorBoundary. │
│ react-dom_client.js?v=b2be203f:6998:18 │
│ react-dom_client.js?v=b2be203f:7030:10 │
│ react-dom_client.js?v=b2be203f:994:71 │
│ react-dom_client.js?v=b2be203f:7075:10 │
│ react-dom_client.js?v=b2be203f:5488:17 │
│ react-dom_client.js?v=b2be203f:5500:12 │
│ react-dom_client.js?v=b2be203f:994:71 │
│ react-dom_client.js?v=b2be203f:9487:12 │
│ react-dom_client.js?v=b2be203f:9955:26 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9904:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9960:12 │
│ react-dom_client.js?v=b2be203f:12921:119 │
│ react-dom_client.js?v=b2be203f:12800:10 │
│ react-dom_client.js?v=b2be203f:12013:8 │
│ react-dom_client.js?v=b2be203f:11947:16 │
│ react-dom_client.js?v=b2be203f:13514:8 │
│ react-dom_client.js?v=b2be203f:13411:121 │
│ react-dom_client.js?v=b2be203f:12073:85 │
│ react-dom_client.js?v=b2be203f:369:10 │
│ hmr-runtime:187:20 │
│ hmr-runtime:179:29 │
│ hmr-runtime:514:10 │
│ Error> React Router caught the following error during render JSHandle@error React Router caught the following error during render {} │
│ chunk-G7KIHQ6P.js?v=b2be203f:5586:14 │
│ react-dom_client.js?v=b2be203f:18544:19 │
│ react-dom_client.js?v=b2be203f:7083:10 │
│ react-dom_client.js?v=b2be203f:5488:17 │
│ react-dom_client.js?v=b2be203f:5500:12 │
│ react-dom_client.js?v=b2be203f:994:71 │
│ react-dom_client.js?v=b2be203f:9487:12 │
│ react-dom_client.js?v=b2be203f:9955:26 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9904:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9960:12 │
│ react-dom_client.js?v=b2be203f:12921:119 │
│ react-dom_client.js?v=b2be203f:12800:10 │
│ react-dom_client.js?v=b2be203f:12013:8 │
│ react-dom_client.js?v=b2be203f:11947:16 │
│ react-dom_client.js?v=b2be203f:13514:8 │
│ react-dom_client.js?v=b2be203f:13411:121 │
│ react-dom_client.js?v=b2be203f:12073:85 │
│ react-dom_client.js?v=b2be203f:369:10 │
│ hmr-runtime:187:20 │
│ hmr-runtime:179:29 │
│ hmr-runtime:514:10 │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ コンソールログによると、<Home>コンポーネントのレンダリング中にエラーが発生しているようです。
エラーを特定するため、/Volumes/workspace/adglobe/blog/blog-gemini-extensions/app/routes/home.tsx のコードを確認します。
╭──────────────────────────────────╮
│ ✓ ReadFile app/routes/home.tsx │
╰──────────────────────────────────╯
✦ コードを確認したところ、home.tsxファイル内にエラーの原因となっている箇所を見つけました。
空のオブジェクトobjの未定義のプロパティにアクセスしようとしているため、エラーが発生しています。
1 export default function Home() {
2 const obj: any = {};
3 console.log(obj.a.b);
4 return <Welcome />;
5 }
この問題のある2行を削除して修正します。
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ Edit app/routes/home.tsx: import type { Route } from "./... => import type { Route } from "./... │
│ │
│ 9 } │
│ 10 │
│ 11 export default function Home() { │
│ 12 - const obj: any = {}; │
│ 13 - console.log(obj.a.b); │
│ 12 return <Welcome />; │
│ 13 } │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ エラーの原因となっていたコードを削除しました。これでエラーは解消されたはずです。
念のため、再度コンソールログを確認して、エラーが消えていることを確認します。
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ list_console_messages (chrome-devtools MCP Server) {} │
│ │
│ # list_console_messages response │
│ # Console messages │
│ undefined> client:732:8: [vite] connecting... [vite] connecting... │
│ undefined> client:826:11: [vite] connected. [vite] connected. │
│ Info> react-dom_client.js?v=b2be203f:20100:53: %cDownload the React DevTools for a better development experience: │
│ https://react.dev/link/react-devtools font-weight:bold %cDownload the React DevTools for a better development experience: │
│ https://react.dev/link/react-devtools font-weight:bold │
│ undefined> client:809:28: [vite] hot updated: /app/routes/home.tsx [vite] hot updated: /app/routes/home.tsx │
│ undefined> client:809:28: [vite] hot updated: /app/routes/home.tsx [vite] hot updated: /app/routes/home.tsx │
│ undefined> client:809:28: [vite] hot updated: /app/app.css [vite] hot updated: /app/app.css │
│ undefined> client:809:28: [vite] hot updated: /app/routes/home.tsx [vite] hot updated: /app/routes/home.tsx │
│ Error> %o │
│ │
│ %s │
│ │
│ %s │
│ JSHandle@error The above error occurred in the <Home> component. React will try to recreate this component tree from scratch using the error boundary │
│ you provided, RenderErrorBoundary. %o │
│ │
│ %s │
│ │
│ %s │
│ {} The above error occurred in the <Home> component. React will try to recreate this component tree from scratch using the error boundary you │
│ provided, RenderErrorBoundary. │
│ react-dom_client.js?v=b2be203f:6998:18 │
│ react-dom_client.js?v=b2be203f:7030:10 │
│ react-dom_client.js?v=b2be203f:994:71 │
│ react-dom_client.js?v=b2be203f:7075:10 │
│ react-dom_client.js?v=b2be203f:5488:17 │
│ react-dom_client.js?v=b2be203f:5500:12 │
│ react-dom_client.js?v=b2be203f:994:71 │
│ react-dom_client.js?v=b2be203f:9487:12 │
│ react-dom_client.js?v=b2be203f:9955:26 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9904:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9960:12 │
│ react-dom_client.js?v=b2be203f:12921:119 │
│ react-dom_client.js?v=b2be203f:12800:10 │
│ react-dom_client.js?v=b2be203f:12013:8 │
│ react-dom_client.js?v=b2be203f:11947:16 │
│ react-dom_client.js?v=b2be203f:13514:8 │
│ react-dom_client.js?v=b2be203f:13411:121 │
│ react-dom_client.js?v=b2be203f:12073:85 │
│ react-dom_client.js?v=b2be203f:369:10 │
│ hmr-runtime:187:20 │
│ hmr-runtime:179:29 │
│ hmr-runtime:514:10 │
│ Error> React Router caught the following error during render JSHandle@error React Router caught the following error during render {} │
│ chunk-G7KIHQ6P.js?v=b2be203f:5586:14 │
│ react-dom_client.js?v=b2be203f:18544:19 │
│ react-dom_client.js?v=b2be203f:7083:10 │
│ react-dom_client.js?v=b2be203f:5488:17 │
│ react-dom_client.js?v=b2be203f:5500:12 │
│ react-dom_client.js?v=b2be203f:994:71 │
│ react-dom_client.js?v=b2be203f:9487:12 │
│ react-dom_client.js?v=b2be203f:9955:26 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9904:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9900:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:10071:12 │
│ react-dom_client.js?v=b2be203f:10789:12 │
│ react-dom_client.js?v=b2be203f:9960:12 │
│ react-dom_client.js?v=b2be203f:12921:119 │
│ react-dom_client.js?v=b2be203f:12800:10 │
│ react-dom_client.js?v=b2be203f:12013:8 │
│ react-dom_client.js?v=b2be203f:11947:16 │
│ react-dom_client.js?v=b2be203f:13514:8 │
│ react-dom_client.js?v=b2be203f:13411:121 │
│ react-dom_client.js?v=b2be203f:12073:85 │
│ react-dom_client.js?v=b2be203f:369:10 │
│ hmr-runtime:187:20 │
│ hmr-runtime:179:29 │
│ hmr-runtime:514:10 │
│ undefined> client:809:28: [vite] hot updated: /app/routes/home.tsx [vite] hot updated: /app/routes/home.tsx │
│ undefined> client:809:28: [vite] hot updated: /app/routes/home.tsx [vite] hot updated: /app/routes/home.tsx │
│ undefined> client:809:28: [vite] hot updated: /app/app.css [vite] hot updated: /app/app.css │
│ undefined> client:809:28: [vite] hot updated: /app/routes/home.tsx [vite] hot updated: /app/routes/home.tsx │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ コンソールログにまだエラーが表示されていますが、これは古いログの可能性があります。ページを再読み込みして、最新の状態でコンソールログを再取得します。
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ navigate_page (chrome-devtools MCP Server) {"url":"http://localhost:5173/"} │
│ │
│ # navigate_page response │
│ # Pages │
│ 0: http://localhost:5173/ [selected] │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ リロードしました。コンソールを再確認して、エラーが消えたか見てみます。
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ list_console_messages (chrome-devtools MCP Server) {} │
│ │
│ # list_console_messages response │
│ # Console messages │
│ undefined> client:732:8: [vite] connecting... [vite] connecting... │
│ undefined> client:826:11: [vite] connected. [vite] connected. │
│ Info> react-dom_client.js?v=b2be203f:20100:53: %cDownload the React DevTools for a better development experience: │
│ https://react.dev/link/react-devtools font-weight:bold %cDownload the React DevTools for a better development experience: │
│ https://react.dev/link/react-devtools font-weight:bold │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ エラーメッセージが表示されなくなったので、問題は解決したと判断します。作業を完了します。
このように、従来は手動で行っていた「DevToolsを開く → エラーを確認 → コードを修正 → 再確認」という一連の流れを、Geminiとの対話だけで完結できます。
パフォーマンス診断と改善
コンソールログから修正するだけでも十分便利なのですが、chrome-devtools-mcpの真価はここからです。
この拡張機能は、パフォーマンス診断やアクセシビリティ診断も行えます。
ページの表示速度は、ユーザー体験に直結する重要な指標です。
chrome-devtools-mcpは、Core Web Vitalsなどのパフォーマンス指標を専門家のように分析し、具体的な改善策まで提案してくれます。
例:LCP(Largest Contentful Paint)の改善
今回はGeminiにToDoアプリを作成して、その環境に対してパフォーマンス診断を依頼してみました。
Core Web Vitalsのスコアを測定し、LCP、INP、CLSの各指標に基づいた改善案を提示してもらいます。
ユーザー
http://localhost:5173/todo のパフォーマンス測定をして改善案を出して サーバーは起動済み 実際の修正はせず改善案のみを提示して todoの追加や削除についても操作して
Geminiの分析結果(要約)
Geminiに依頼すると、ブラウザ上でTODOの追加・削除といった操作を自動で行いながら、パフォーマンスを計測します。まるで専門家がDevToolsのPerformanceタブを分析するように、Core Web Vitalsのスコアを測定し、具体的な改善案を提示してくれました。
測定結果: - LCP: 56ミリ秒(非常に高速) - INP: 27ミリ秒(即座に反応) - CLS: 0.00(完璧なスコア)
改善提案: 1. レンダリングブロックリソースの最適化:重要でないCSS/JSの遅延読み込み 2. テキスト圧縮の有効化:Gzip/Brotliで約18.9KBの削減可能 3. 効率的な再レンダリング:React.memoの活用を継続 4. 動的コンテンツのスペース予約:将来的な画像読み込みに備えた対策
📋 詳細な分析レポートを見る(クリックで展開)
Gemini
✦ パフォーマンス測定が完了しました。Core Web Vitals(LCP, INP, CLS)の指標に基づいた結果の要約と改善案を以下に提案します。
パフォーマンス測定結果の要約
まず、全体的にCore Web Vitalsのスコアは非常に良好です。
* LCP (Largest Contentful Paint): 56ミリ秒
* ページの主要コンテンツが表示されるまでの時間です。非常に高速です。
* INP (Interaction to Next Paint): 27ミリ秒
* ユーザー操作への応答性を示す指標です。非常に高速であり、UIが即座に反応していることを示します。
* CLS (Cumulative Layout Shift): 0.00
* 視覚的な安定性を示す指標です。レイアウトのずれは一切なく、完璧なスコアです。
Core Web Vitalsに基づく改善案
現在のスコアは良好ですが、将来的にアプリケーションが複雑化してもこのパフォーマンスを維持・向上させるために、以下の改善案を提案します。
1. LCP(読み込みパフォーマンス)の改善
LCPは既に高速ですが、トレース結果からさらに改善できる点が2つ見つかりました。
* レンダリングをブロックするリソースの最適化
* 問題点: 現在、ページの初期表示を遅らせる可能性のあるCSSやJavaScriptファイルがいくつか存在します。
* 改善案: 重要でないCSSやJavaScriptの読み込みを遅延(defer)させることを検討してください。例えば、ページの初期表示に不要なコンポーネントのスタイルや、画面の下の方でしか使われない
機能のJavaScriptを非同期で読み込むことで、ブラウザはより早くページの主要コンテンツの描画を開始でき、LCPがさらに短縮されます。
* テキスト圧縮の有効化
* 問題点: サーバーからのレスポンスが圧縮されていません。
* 改善案: サーバー設定でGzipやBrotliといったテキスト圧縮を有効にしてください。トレースによると、これにより約18.9KBのデータ転送量を削減でき、リソースのダウンロード時間を短縮してLCP
を改善できます。
2. INP(インタラクティブ性)の維持
INPは27ミリ秒と非常に優秀です。この応答性を維持するためのベストプラクティスを提案します。
* 効率的な再レンダリングの維持
* 現状と推奨事項: 現在の高速な応答性はおそらく効率的なUI更新が行われているためです。今後も、リスト項目などのコンポーネントにReact.memoを適用したり、リスト全体ではなく変更があった
項目のみを再描画するような設計を維持することが重要です。これにより、アプリケーションが拡大してもINPのスコアを低く保つことができます。
3. CLS(視覚的安定性)の維持
CLSは0.00と完璧なスコアです。このスコアを維持するための予防的なアプローチを提案します。
* 動的コンテンツのためのスペース予約
* 現状と推奨事項: 現在はレイアウトシフトが発生していませんが、将来的に画像や広告、外部から埋め込まれたコンテンツなどを非同期で読み込む機能を追加する場合は注意が必要です。コンテン
ツが読み込まれた際にレイアウトがずれないよう、あらかじめwidthとheightを指定するか、CSSのaspect-ratioプロパティを使って表示領域を確保しておくことを強く推奨します。
パフォーマンス分析も手動で行うと非常に手間がかかりますが、chrome-devtools-mcpを使えばGeminiに任せるだけで簡単に実施できます。
3. アクセシビリティ診断
誰もが快適に使えるWebサイトであるために、アクセシビリティは不可欠です。chrome-devtools-mcpは、専門的な知識がなくてもアクセシビリティの問題点を洗い出してくれます。
例:アクセシビリティの改善提案
ユーザー
http://localhost:5173/todo のアクセシビリティを測定して改善案を出して サーバーは起動済み 実際の修正はせず改善案のみを提示して
Geminiの診断結果(要約)
Geminiは、DevToolsのAccessibilityタブで診断するように、自動でページをスキャンします。その結果、スクリーンリーダーやキーボード操作の観点から、以下のような具体的な改善案を提示してくれました。
主な問題点と改善案:
入力フィールドのラベル不足(最重要)
- 問題:スクリーンリーダーが入力欄の目的を理解できない
- 解決:
<label>要素またはaria-label属性を追加
Todoリストの構造
- 問題:意味的に正しいHTMLマークアップがない
- 解決:
<ul>と<li>要素でリスト構造を明示
削除ボタンの関連付け
- 問題:どの項目を削除するか不明確
- 解決:
aria-labelでボタンの対象を具体的に説明
📋 詳細な改善提案を見る(クリックで展開)
Gemini
✦ はい、アクセシビリティの測定と分析が完了しました。以下に改善案を提案します。
アクセシビリティ測定結果の要約
全体的にシンプルな構造ですが、スクリーンリーダーの利用者などにとって改善できる重要な点がいくつか見つかりました。
1. 入力フィールドのラベル不足(最重要)
2. Todoリストの構造
3. Todo項目と削除ボタンの関連付け
アクセシビリティ改善の提案
1. 入力フィールドにラベルを追加する
* 問題点: 新しいTodoを入力するテキストボックスにラベルが関連付けられていません。これにより、スクリーンリーダーの利用者はこの入力欄が何のためのものか(「Todo名を入力する」など)を理解
できません。
* 改善案:
* 方法A(推奨): <label>要素を使用して、入力欄に可視ラベルを付けます。
1 <label for="new-todo-input">新しいTodo:</label>
2 <input id="new-todo-input" type="text" placeholder="例: 買い物に行く" />
* 方法B: デザイン上、可視ラベルを置きたくない場合は、aria-label属性を使ってスクリーンリーダー向けに説明を提供します。
1 <input type="text" aria-label="新しいTodoを入力" placeholder="例: 買い物に行く" />
2. Todoリストを意味的に正しいHTMLで構造化する
* 問題点: Todo項目がリスト(<ul>や<ol>)としてマークアップされていません。スクリーンリーダーはこれを単なるテキストとボタンの連続として読み上げてしまい、「リストが何項目あるか」といっ
た文脈を伝えられません。
* 改善案: Todoリスト全体を<ul>要素で囲み、各Todo項目(テキストと削除ボタン)を<li>要素で囲みます。
1 <ul>
2 <li>
3 <span>Todoのテキスト</span>
4 <button>Delete</button>
5 </li>
6 <li>
7 <span>別のTodo</span>
8 <button>Delete</button>
9 </li>
10 </ul>
3. 削除ボタンのアクセシビリティを向上させる
* 問題点: 「Delete」というボタン名は、どの項目を削除するのかが明確ではありません。スクリーンリーダーは「(Todoのテキスト)、Delete、ボタン」のように読み上げるため文脈から推測は可能で
すが、より明確にすることが望ましいです。
* 改善案: aria-label属性を使い、どの項目を削除するボタンなのかを具体的に示します。
1 <button aria-label={`Delete ${todo.text}`}>
2 Delete
3 </button>
これにより、スクリーンリーダーは「Delete "買い物に行く"」のように、より具体的に読み上げることができます。
これらの修正を行うことで、視覚的な情報に頼らないユーザーでも、このTodoアプリケーションをより快適に利用できるようになります。
アクセシビリティは優先度が低くなりがちですが、chrome-devtools-mcpを使えば簡単に診断と改善案の取得ができるため、積極的に取り組むことができます。
4. レスポンシブデザインの確認
Web開発では、PC、タブレット、スマートフォンなど、さまざまなデバイスでレイアウトが崩れないかを確認するレスポンシブ対応が欠かせません。
chrome-devtools-mcpを使えば、この確認作業も効率化できます。「viewportを375pxにして」のように指示するだけで、ブラウザの表示領域を瞬時に変更できます。
例:レスポンシブ表示の確認
ユーザー
375pxと1024pxのviewportでスクリーンショットを撮って
Geminiの動作(ポイント)
Geminiに依頼すると、指定されたviewportに自動でリサイズして、スクリーンショットを撮影してくれます。
- 375pxにリサイズ: Geminiがブラウザのviewportを375x812に変更します。
- スクリーンショット撮影:
sp-view.pngとしてスクリーンショットを保存します。 - 1024pxにリサイズ: Geminiがブラウザのviewportを1024x768に変更します。
- スクリーンショット撮影:
tablet-view.pngとしてスクリーンショットを保存します。
📋 詳細なログを見る(クリックで展開)
Gemini
✦ 承知いたしました。まず、viewportを375x812にリサイズしてスクリーンショットを取得します。
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ resize_page (chrome-devtools MCP Server) {\"width\":375, \"height\":812} │
│ ✓ take_screenshot (chrome-devtools MCP Server) {\"filePath\":\"sp-view.png\"} │
│ │
│ # take_screenshot response │
│ Took a screenshot of the current page\'s viewport. │
│ Saved screenshot to sp-view.png. │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ 次に、viewportを1024x768にリサイズしてスクリーンショットを取得します。
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ resize_page (chrome-devtools MCP Server) {\"width\":1024, \"height\":768} │
│ ✓ take_screenshot (chrome-devtools MCP Server) {\"filePath\":\"tablet-view.png\"} │
│ │
│ # take_screenshot response │
│ Took a screenshot of the current page\'s viewport. │
│ Saved screenshot to tablet-view.png. │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ スクリーンショットをsp-view.pngとtablet-view.pngとして保存しました。
実際に取得できたスクリーンショット
| 375px | 1024px |
|---|---|
![]() |
![]() |
このように、複数のデバイスサイズでの表示確認とスクリーンショット撮影をコマンド一つで実行できるため、手動でブラウザを伸縮させる手間が省け、確認漏れも防げます。
⚠️ 注意 Geminiの動作は常に同じ結果を返すとは限らないため、再現性が求められるE2E(End-to-End)の自動テストには向きません。あくまで開発中の手動確認を効率化するための補助的なツールと考えるのが良いでしょう。
5. 他にも広がる可能性
chrome-devtools-mcpの能力はこれだけにとどまりません。
- DOMの調査: 「このボタンのCSSが効かない理由は?」
- ネットワークの分析: 「このページで最も重いリソースは?」
など、これまでChrome DevToolsを開いて手動で行っていた多くの作業を、自然言語でGeminiに指示するだけで完結できてしまいます。
その他の便利な拡張機能
Git操作を支援する「GitKraken Git MCP Server」
chrome-devtools-mcpの他にも、開発を効率化する拡張機能は存在します。例えば「GitKraken Git MCP Server」もその一つです。
gemini extensions install https://github.com/gitkraken/gitkraken-mcp-server
これを導入すると、git branchやgit commitといったGit操作を、Geminiとの対話を通じて自然言語で実行できるようになります。「変更をステージングしてコミットして」のように指示するだけで、Geminiが適切なコマンドを実行してくれるため、複雑なGitコマンドを覚える手間が省けて便利です。
Figmaのデザインからコードを生成する「Figma」
これはまだ試せていないのですが、「Figma」もExtensionを公開しています。。
gemini extensions install https://github.com/figma/figma-gemini-cli-extension
この拡張機能を導入し、Figmaアカウントで認証すると、GeminiはFigmaのデザインファイルを理解できるようになります。
「このFigmaデザインを実装して」のように、FigmaのURLを渡すだけで、デザインからコードを生成したり、デザインシステムで定義された変数やコンポーネントの情報を抽出したりすることが可能です。これにより、デザインとコードの一貫性を保ちながら、実装の初期段階を自動化できます。
※なお、この拡張機能の利用には、Figmaの有料プランの契約が必要です。
まとめ
結局、Gemini CLI Extensionの何が嬉しいかというと、これまで「便利そうだけどセットアップが面倒…」と敬遠していたようなツールを、installコマンド一発で使えるようにしてくれる、その手軽さに尽きるんじゃないかと思います。
この記事で紹介したchrome-devtools-mcpなんて、まさにその代表例です。
ブラウザのデバッグ、パフォーマンス診断、はたまたGit操作まで、これまで専門知識を要した作業がどんどん自然言語の対話に置き換えられていく。
こういう定型作業から解放されるだけでも、私達開発者はもっと本質的な問題に集中できるわけで、これは本当にありがたい話です。
もし今、あなたが使っているツールで「これもセットアップがなぁ…」と感じるものがあれば、Gemini CLI Extensionを探してみると、意外な掘り出し物が見つかるかもしれません。
アドグローブでは、さまざまなポジションで一緒に働く仲間を募集しています!
詳細については下記からご確認ください。みなさまからのご応募お待ちしております。

