Skip to main content
Glama
HabaAndrei

custom-chrome-dev-mcp

by HabaAndrei

Custom

Custom Chrome Dev MCP

ローカル専用のMCP(Model Context Protocol)サーバーです。MCPクライアント(Claude Codeなど、MCPを話せるあらゆるクライアント)が、人間と同じように実際のChromeブラウザを操作できます。テレメトリなし、Third-partyサービスなし、クラウドなし。すべては共有トークンに守られ、あなたのマシン上だけで完結します。

ナビゲーション、タブ、知覚、操作、trusted入力、可観測性、キャプチャにわたる合計45個のツールを提供します。


由来

このプロジェクトは、Chrome公式のブラウザMCPに触発されています。Chrome DevToolsチームが公開したChrome DevTools MCPサーバーは、AIエージェントがスクレイピングしたHTMLではなく、DevTools Protocolを通じてブラウザを操作すべきだと初めて展開しました。

私たちはそのアイデンティティを複製し破壊しているのであって、出荷しているのではありません。 取り入れたものは次の通りです:

  • 前提 ブラウザを、MCPツールの組み合わせとしてエージェントへ公開する。

  • アクセシビリティ・ファーストの知覚 大量の素のHTMLを渡さず、安定した要素参照を持つコンパクトなa11yアウトラインをモデルに渡す。

  • 入力レイヤーとしてのChrome DevTools Protocol ページに見破られて無視できる合成イベントではなく、実際のtrustedなイベントを届ける。

このプロジェクトが意図的に異なる点

Chrome DevTools MCP

Custom Chrome Dev MCP

ブラウザ

デフォルトでは専用ユーザーデータディレクトリを持つ独自のChromeを起動。--browser-urlでつのサーバーに接続することも可能

あなたが開き終えたChrome・実際に動かすのは、あなかがいます。

アタッチ

DevTools Protocolエンドポイント経由でブラウザに接続します。

ブラウザ内部に住むChrome拡張機能、あなたが選択したタブに向かいます。

主な目的

ページのデバッグ、検査、プロファイリング

そのページを使う人間のように振る舞うこと

この最後の行がこのリポジトリの要点です。Chrome DevTools MCPは、たまにブラウザを動かすデバッグツールです。一方これは、たまたまデバッグに役立つ、人間を模るためのツールです。

⚠️ GoogleやChromeチームとは、提携・承認・サポートは一切ありません。 これは、彼らの設計から学び、破骸を目的とした、独立した再スキャンです。 公式サポートが欲しい場合は、公式サーバーをお使いください。


Related MCP server: monkeysee

人間らしさを維持する工夫

多くのブラウザ自動化は簡単に見分けがつきます。isTrusted=falseの合成イベント、実際に動かないフォーカス、一瞬で入力されるフィールド、履歴のないきれいな自動化プロファイル。それらはどれもシグナルです。

このプロジェクトは、それらを排除しようとしています:

  • 本当のあなたのプロファイル。 何度も操作を、あなたが既に使ているChrome上で実行します。クッキーも、ログインも、拡張機能も、履歴も、すべて維持されたまま。どこからも「まっさらな自動化」と区別を持って指摘されるものはありません。

  • Trusted入力。 realClickrealTypepresshoverdrag はDevTools Protocol経由でイベントを発行するため、ページには物理的なマウス・キーボードが生成するのと同等のisTrusted=trueイプロセントが届きます。

  • 本物のフォーカス。 フィールドのフォーカスを合わせるクリックでは、画面の裏で.valueを代入するのではなく、実際にフォーカスを正しい順序で移します。

  • 実際のキーストローク。 press は合成inputイベントを1つ送るのではなく、正しいテンコードとモディファイルを持つrawKeyDown / char / keyUp シーケンスを送出します。

  • 読み戻し検証。 fill はフィールドに実際にそのテキストが入ったことを確認します。ページが入力を受け取らなかったとき、エージェントは、人間と同じようにそれに気づけます。

目標は、ページが、あなたがキーボードの前に座って操作している人と同じように、エージェントに対しても動作することです。

高速な合成ツール(clicktype)も残っています。これらはより速く、多くのWebサイトで利用可能です。ページがそれらを無視する場合は、trusted系のツールに頼ってください。


動作の仕組み

トランスポートは1つです。MCPクライアントはstdioでサーバーに接続し、サーバーは、構成の長命なhubプロセスが保持するローカルWebSocketを介してChrome拡張機能に中継します。

MCP client 1 (Claude) <-stdio-> bin/custom-chrome-dev-mcp.js ─┐
MCP client 2 (Claude) <-stdio-> bin/custom-chrome-dev-mcp.js ─┼─ src/hub.js (127.0.0.1:9876)
MCP client N (Claude) <-stdio-> bin/custom-chrome-dev-mcp.js ─┘              │
                                                                            │ WebSocket
                                                                            ▼
                                                              Chrome extension -> active tab

なぜ独立したハブプロセスなのか。 ポート9876を専有できるプロセスは1つだけですが、Claude Codeのセッションが複数開いている場面で、すべてがブラウザを参照したいケースが考えられます。そこで、ソケットを個々のセッション内部ではなくsrc/hub.jsに置いています。各クライアントはrole:"mcp"としてハブに接続し、拡張機能はrole:"extension"としてハブに接続し、ハブが仲介します。最初のセッションが起動したとき、ハブはデタッチされデブプロセスとして生成されるため、セッションが終わってもハブは存続します。それ以降のセッションは、すでに使っているハブを見つけます。

拡張機能の中には3つのレイヤーがあります:

  1. Walkerpage/walker.js) — ページのISOLATEDワールドに注入されます。要素解決、安定した eN 参照、高速な合成DOM操作を担当します。

  2. CDPcdp/) — trust時に入力、ページコンテキストでの evaluate、全ページのスクリーンショット、コンソールのlogやネットーネットのバッファは、この領域にで処理します。chrome.debugger を使います。

  3. Recordingrecording/) — CDPの画面描画フレームを、オフスクリーンドキュメントの MediaRecorder.webm にエンコードします。

🔒 拡張機能は、共有トークン(src/config.jsextension/src/config.js で同じ値になる AUTH_TOKEN)でハブに認証します。ハブは、異なる値を見せたピアを遮断します。

前提条件

要件

確認コマンド

Node.js

18 以降(22 で開発)

node --version

Chrome

Google Chrome / Chromiumの、最新に近いバージョン

chrome://version

MCPクライアント

Claude Code、またはstdioでMCPを実装しているクライアント

claude --version

グローバルインストールも、ビルドステップも、サインアップするようなサービスもありません。ランタイムのデペンデンシは @modelcontextprotocol/sdkws の2つだけです。しかもすべてが127 127.0.0.1上で動き続けます。


ローカルでのセットアップ

4つのステップと、最後の確認までで、所要時間は5分程度です。

1. クローンしてインストール

git clone <your-fork-url> custom-chrome-dev-mcp
cd custom-chrome-dev-mcp
npm install

ブラウザを接続する前に、ツリーが正常に揃っていることを確認します。オフラインのテストはブラウザを必要とせず、1秒未満で終わるので安心です:

npm test

22 passed と表示されたらOKです。失敗した場合は、次に進む前に修正してください。次の全工程がうまく動かなくなります。

2. 拡張機能をChromeへ読み込む

  1. chrome://extensions を開く。

  2. Developer mode(右上のトグル)をオンにする。

  3. Load unpacked をクリックし、extension/フォルダ(の中の manifest.json ではなく、フォルダ自体)を選択する。

  4. リストに Custom-chrome-dev-mcp が表示されます。

⚠️ 実際にブラウジングに使っているプロファイルで読み込んでください。 Chrome はプロファイルごとに拡張を管理するため、「Profile Observation」に読み込んだ拡張は、通常の「Default(デフォルト)」のウィンドウから見えません。後でツールがタブを認識しない場合、あるいはハブが text の形容(extension connected)を取らない場合、最初に確認すべき箇所です。chrome://version に表示される、現在のプロファイルパス(Profile Path)をご覧ください。

拡張機能IDは、 extension/manifest.json の public key に固定されています。そのため、どのマシンでも同じIDになります。環境間でコピーするものはありません。

3. MCPサーバーをクライアントに登録する

CLIを使う 場合は、リポジトリをクローンした絶対パス(プロジェクトルートで pwd を打つと表示されます)に置き換えます:

claude mcp add -s user custom-chrome-dev-mcp -- node /ABSOLUTE/PATH/TO/custom-chrome-dev-mcp/bin/custom-chrome-dev-mcp.js
  • -s user はプロジェクト全プロジェクトに登録します。-s local はこのプロジェクトだけに適用します。

  • 登録するのは bin/custom-chrome-dev-mcp.js です。このファイルがあったポイントなので、src/server.jsを指しても機能しません。

  • パスは 絶対パス でなければなりません。相対パスだと、クライアントの起動時のディレクトリ解釈されます。

  • 次のコマンドで確認できます:claude mcp list 実行の結果、✔ Connected よとなりが示されれば、確定です。

⚠️ ~/.claude.json を手作業で編集しないでください。 このファイルは大きいため、コンマを1つ間違えるだけでClaude Code全体が壊れます。上記のCLIコマンドは安全に編集します。

mcpServers の下にサーバー項目を追加します:

{
  "mcpServers": {
    "custom-chrome-dev-mcp": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/TO/custom-chrome-dev-mcp/bin/custom-chrome-dev-mcp.js"]
    }
  }
}

4. MCPクライアントを再起動する

MCPクライアントは起動時、ツール一覧を一度だけ読み取ります。セッションの途中でサーバーを追加しても、再起動まで反映されません。Claude を再起動すると、45個のツールが表示されます。

再起動時に、クライアントはサーバーをT起動し、サーバーは 127.0.0.1:9876 で何も待機していなければ src/hub.js を生成します。

5. チェーン全体を検証する

スタックは client → server → hub → extension → tab の形です。どのリンクが切れているのかを推測するのではなく、全体を確かめることが重要です。

# The hub is up, and the extension found it:
tail -f "$TMPDIR/custom-chrome-dev-mcp-hub.log"
#   [hub] listening on 127.0.0.1:9876
#   [hub] extension connected      <- this line is the handshake succeeding

# Who owns the port (should be src/hub.js from THIS repo):
lsof -nP -iTCP:9876 -sTCP:LISTEN

続いて、クライアントに listTabs を依頼してください。開いているタブのJSON配列が返ってきたら、すべてのリンクが機能しています。次に screenshot を実行すると、PNG が ~/Downloads に保存され、かつインラインでも返ってきます。

拡張機能自身のコンソールを見るには:chrome://extensionsCustom-chrome-dev-mcpservice workerInspect で確認します。拡張側の障害はここに表示され、MCPクライアントには表示されません。

6. 実際に使う前に共有トークンに変えましょう

AUTH_TOKEN には、**src/config.jsextension/src/config.js に同じデフォルト値が入っています。このトークンが、自分のマシン上の別プロセスがあなたのログイン済みブラウザを操作することを防ぐ唯一の壁です。独自の値に変え、両方のファイルで変更してから、拡張機能を再読み込みしてください(オフラインテストが両者の一致を検証します)。


コード変更後の反映方法

2つの部分のリロード方法は異なるため、これを間違えると他の何よりも時間を割くことになります:

変更した対象

反映するには

extension/ 配下

拡張機能ページ(chrome://extensions)で reload ↻ をクリック 。実行では、前回のビルドがそのまま動作し続けます。

src/ 配下

MCP クライアントを再起動します。サーバープロセスは長期間存在し、古いツールスキーマを保持しています。

src/hub.js のみ

pkill -f src/hub.js を実行。次のツール呼び出しでハブが再診されます。


トラブルシューティング

症状

原因

修正方法

claude mcp list✘ Failed to connect と表示される

パスが正しくないか、bin/ のエントリポイントになっていない

bin/custom-chrome-dev-mcp.js への絶対パスで再登録する

クライアントにツールがまったく表示されない

セッションの途中で登録された

MCP クライアントを再起動する

Hub ログに extension connected と表示されない

拡張機能が読み込まれていない、別の Chrome プロファイルで読み込まれている、または2つの config.js ファイル間で AUTH_TOKEN が異なる

chrome://version の Profile Path を確認し、両方のトークンが一致しているか確認する

ツール呼び出しがハングして、最終的にタイムアウトする

サービスワーカーが停止した、または拡張機能側で例外が発生した

サービスワーカーのコンソールを開き、reload ↻ をクリックする

ポート 9876 を想定外のプロセスが使用している

このプロジェクトの別クローンから起動している hub がポートを占有している

lsof -nP -iTCP:9876 -sTCP:LISTEN を実行し、その PID を kill する

extension/ を編集したのに「反映されない」

Chrome が古いビルドを実行したままである

reload ↻ をクリックする

URL is banlisted

extension/src/config.jsBANLIST がそのホストをブロックしている

リストを編集する。最初からプレースホルダのエントリが入っている

refusing to act: … does not contain expectUrl

expectUrl ガードが正しく働いた

ガードを削除するか、実際の URL を指すようにする

スクリーンショットのパスが拒否される

書き込みがキャプチャディレクトリ内に制限されている

そのディレクトリのファイル名またはパスを使う

ツールが誤ったタブを操作する

バックグラウンドのタブがフォーカスを奪った

useTab で作業用タブを固定する


設定

どちらも起動時に src/config.js が読み取るオプションの環境変数です。

変数

デフォルト

説明

CUSTOM_CHROME_DEV_MCP_CAPTURE_DIR

~/Downloads

スクリーンショットと録画を書き込める唯一のディレクトリです。

CUSTOM_CHROME_DEV_MCP_WS_PORT

9876

Hub 用のポート。extension/src/config.js 側も変更しないと互いを見つけられません。

実際に使うときに合わせて変更したい値がもう1つあります。AUTH_TOKEN です。これは src/config.jsextension/src/config.js に同じ値で定義します。自分の値を指定してください。 他のローカルプロセスがあなたのブラウザを操作するのを防ぐのがこの値です。


利用可能なツール(45)

要素は次の3つの方法で対象にします。selector(CSS)、refsnapshotA11y が返す安定した eN の ID)、 または name(アクセシブルネーム。例:ボタンのラベル)です。以下の「target」はこれら3つのいずれかを指します。

すべてのツールで使える共通パラメータ

  • tabId — 現在アクティブなタブではなく、特定のタブに対して操作する。

  • frameIdlistFrames から取得)— 特定のフレーム内で操作する。トップのドキュメントからはスクリプトを実行できないクロスオリジンの iframe も対象になる。

  • expectUrl — ガード:タブの URL がこの部分文字列を含む場合にのみ操作を許可する。

セッション全体で使うタブを useTab で固定しておくと、バックグラウンドのタブ(自動再生の動画や通知ポップアップ)が フォーカスを奪って操作対象を誤らせるのを防げます。

ナビゲーション

ツール

引数

説明

navigate

url

タブを指定 URL に移動させます(ページは置き換わります)。

newtab

url

現在のページを残したまま、新しい先頭タブで URL を開きます。

back / forward

-

履歴を戻る / 進む。

reload

hard?

リロードします。任意でキャッシュをバイパスします。

getUrl / getTitle

-

タブの URL / タイトル(内部ページでも機能します)。

waitForLoad

timeout?

タブの読み込みが完了するまでブロックします。

タブとフレーム

ツール

引数

説明

listTabs

-

すべてのウィンドウにあるすべてのタブ(idtitleurlactivepinned)。

activateTab

tabId

タグとそのウィンドウにフォーカスを当てる。

closeTab

tabId

指定した ID のタブを閉じる。

useTab

tabId?

作業タブを固定して、以降のどのツールも OS のフォーカス状態に関係なくそのタブを対象にする。tabId を省略すると現在のタブを固定する。

unpinTab

-

固定を解除する。ツールはアクティブなタブを対象にする通常動作に戻る。

listFrames

-

クロスオリジンも含むすべてのフレームを {frameId, parentFrameId, url, origin} として一覧にする。

知覚

ツール

引数

説明

snapshotA11y

-

表示されている操作可能な要素の簡潔なアクセシビリティ一覧を role "name" ref=eN の形式で返す。snapshot よりもこちらを推奨。 ref はナビゲーションや再スナップショットを行うと無効になります。

snapshot

-

<body> の生の outerHTML。50k 文字に切り詰めたもの。正確なマークアップが必要なときに使う。

getText

target

要素1つの innerText が返ります。前後の空白を除いた状態。

getAttribute

target, attr

属性を返す。存在しない場合、ライブ DOM のプロパティ(valuecheckedhref)にフォールバックします。

queryAll

selector, limit?

一致するすべての要素の text / href / value / visible を一度に返します。

viewport

-

devicePixelRatio、CSS ビューポート、スクロール位置。スクリーンショットの px を CSS px に変換するのに使う。

操作(合成イベント・高速)

ウォーカーが送出する非信頼イベントです。高速で、ほとんどのサイトには十分です。

ツール

引数

説明

click

target

バブリングする MouseEvent クリックを送出し、要素へフォーカスも当てます。.click() へのフォールバック。戻り値は {focused}

type

target, text

ネイティブセッターでフィールドの値を設定(<input><textarea>および contenteditable に対応)。戻り値は {value}

fill

target, text, verify?

フォーカス+セット+読み戻し確認。テキストが反映されていなければスロー。最も確実なテキスト入力手段なので、クリック→タイピングよりこちらを優先する。

assert

target, text?, value?

スクリーンショット無しでテキスト(部分一致)と値の一致を検証する → {ok, checks}

scroll

target?, direction?, amount?

要素が表示されるまでスクロールするか、ウィンドウをスクロールします(top / bottom は端まで移動)。

select

target, value? / label?

value または表示ラベルで <select> のオプションを選択します。

check

target, checked

チェックボックス / ラジオボタンを指定した状態に設定。すでに同じ状態であればクリックしません。

submit

target,

所属フォームを requestSubmit() します。クリックできるボタンが存在しないフォーム向け。

waitForSelector

target または text, timeout?

要素が見つかるか、指定したテキスト部分文字列が現れるまで待機します。

信頼される入力とエミュレーション — CDP

isTrusted=true の実イベントを送ります。これらは chrome.debugger を接続するため、タブに黄色の 「デバッグ中」 バナーが 常に表示されます。

ツール

引数

説明

realClick

target / x,y, button?, clickCount?

信頼済みクリック。右クリックやダブルクリックも含みます。

realType

target?, text

信頼済みテキスト挿入。指定があれば最初にそのターゲットにフォーカスします。

press

keys, target?

信頼済みキーとコンビネーション:"Enter""Tab""Meta+c"["ArrowDown","Enter"]

hover

target / x,y

実際のマウスを要素上に移動して :hover を発火させます(メニューやツールチップが表示されます)。

drag

from, to

信頼済みのプレス→ムーブ→リリースによるドラッグ&ドロップ。

uploadFile

selector, paths[]

OSのファイル選択ダイアログを介さずに <input type=file> へファイルを設定します。絶対パスが必要です。

setViewport

width, height, deviceScaleFactor?, mobile?, userAgent?

レスポンシブチェックのためのビューポート/デバイスをエミュレートします。

handleDialog

accept?, promptText?

次に来る alert / confirm / prompt に解答を事前に仕込んでおきます。ダイアログを出す操作のに設定してください。

detach

-

デバッガーを切り離してバナーを消します。次の CDP 呼び出しの際に再接続されます。

可観測性 — CDP、タブごとにバッファリング

キャプチャはデバッガが接続したときに開始されるため、ページ読み込み時の動作を取得したい場合は、最初の CDP 呼び出しの後にページを再読み込みしてください。

ツール

引数

説明

getConsole

level?, limit?, clear?

バッファされたコンソールログ、警告、エラー、未捕捉された例外。

listNetworkRequests

urlContains?, status?, failedOnly?, limit?

バッファされたリクエスト:メソッド、URL、ステータス、タイプ、タイミング。

getNetworkRequest

requestId, includeBody?

1件のリクエストを完全な形で取得します。includeBody を指定すると、(切り詰められた)レスポンスボディも取得します。

evaluate

expression

CDP 経由でページの実際のコンテキストで JS を実行します。eval をブロックする content script の CSP を回避します。Promise は待機されます。chrome:// ページでは利用できません。

キャプチャ

キャプチャディレクトリ(デフォルトは ~/Downloads設定 を参照)に保存されます。

ツール

引数

説明

screenshot

path?, format?, tabId?

表示中のビューポートを PNG/JPEG で保存 — ディスクに保存され、{devicePixelRatio, cssViewport} 付きでインラインで返されるので、モデルは1回の呼び出しで参照できます。

fullPageScreenshot

path?, tabId?

ビューポートの外まで含む、スクロール可能なページ全体を CDP 経由で取得します。

record

action, path?, tabId?

タブの録画を start / stop / status で制御し、.webm を生成します。完全に MCP 駆動 — ツールバーのクリックやユーザージェスチャは不要です。録画対象はデスクトップではなくタブです。

path はファイル名、またはキャプチャディレクトリの内側へのパスです。存在しないサブフォルダは作成されます。ディレクトリ外へ解決されるものは拒否されます。


最初の実動実行

セットアップ手順5が結線を検証します。ここではそれに続く興味深い部分、つまりページがスクリプトではなく実際のユーザーとして認識すること、が実証されます。クライアントを任意のページに向けて、以下の内容を依頼してください:

  1. snapshotA11y — コンパクトなアウトライン。ターゲット指定用の eN リファレンスが付いています。

  2. realClick {ref:"e3"} — 信頼されたクリック。タブに黄色の 「デバッグ中です」 バナーが表示されます。これは CDP のアタッチによるもので、あえて見えるようにしてあります。

  3. evaluate {expression:"'ok'"} — content script の CSP を迂回したページコンテキストの JS 実行。

  4. screenshot — キャプチャディレクトリに保存された PNG が、さらにインラインでも返されます。

  5. record {action:"start"}record {action:"stop", path:"clip.webm"} — タブの .webm を生成します。ツールバーのクリックもユーザー操作も不要です。ツールバーのアイコンは意図的に何も起動しません。

  6. detach — バナーを消去します。

信頼された操作による違いを実感するために、リスナーを仕掛けて比較してみてください:

// via evaluate
window.__e = []; document.querySelector("button")
  .addEventListener("click", e => window.__e.push(e.isTrusted));

clickfalse を報告します。一方 realClicktrue を報告します。この対比こそがこのプロジェクトの存在理由であり、ブラウザテストレーンはその点を直接アサートします。


テストの実行

テストスイートには2つのレーンがあり、その分割こそがポイントです。

オフラインレーン — ブラウザ不要、CI で実行

npm test        # node test/run.mjs --lane=offline

1 秒未満で完了し、必要なのは Node だけです。SDK のインメモリトランスポートを介して src/server.js に対して実際の MCP ハンドシェイクをプロセス内で 実行するため、サーバーが実際に公開している表面に対して検証を行います:

  • 公開されているすべてのツールに拡張ハンドラが存在し、その逆も同様であること — ミラー化されたアーキテクチャが招きやすい失敗です。

  • 同じツール名が2つのハンドラグループによって要求されないこと(スプレッドでマージされるため、重複は暗黙的に失われます)。

  • すべてのツールが実際の説明文と、共通の tabId / frameId / expectUrl スコープを持つこと。

  • すべてのツールが最低1件のテストで実行されること — テストなしでツールを増やすと、ブラウザなしでも CI が失敗します。

  • キャプチャパスの許可リストが ..、深い ..、絶対パス、シンボリックリンクによる逃げ道を現実のリゾルバに対して実際に拒否していること。

  • 禁止リストが挙動によって確認されていること — 主張する対象をブロックし、一般のサイトを過剰にブロックしないこと。

  • ハブがループバックのみにバインドし、両側でトークンが一致し、マニフェストが過度に広い権限を要求せず、ツールバーのアイコンが意図的に何もしない状態であり、*.pem がコミットされていないこと。

ブラウザレーン — 実際の Chrome を操作

# 1. Disconnect the MCP client (close Claude Code, or disable this server for the run)
# 2. Free port 9876 - the hub is long-lived and outlives the session that spawned it
pkill -f src/hub.js
# 3. Start the suite; it binds 9876 itself and waits for the extension
npm run test:browser
# 4. Reload the extension in chrome://extensions so it connects to the suite

⚠️ ステップ1は必須です。 接続中の MCP クライアントは、ソケットが消えたことを検出すると、ハブを約 ~1.2 秒ごとに再生成します。そのため、ポート 9876 を再び占有し、スイートは EADDRINUSE で終了します。クライアントがアタッチされたままハブを終了しても解決にはなりません — クライアントは別のハブを起動するだけです。

このスイートは、フィクスチャサーバーと、実際のハブと同じワイヤプロトコルを話すブリッジを立ち上げるため、実際のメッセージ契約を実行します。各スイートはツールグループのミラーになっており、すべてのテストはリセットされたページを基礎としたフィクスチャから開始されるため、どのテストも別のテストの変更を引き継ぎません。

最後にツールカバレッジが表示され、45 個のツールのうち実行されないものがあれば失敗します。

オプション

コマンド

効果

npm test

オフラインレーンのみ(CI のゲート)

npm run test:browser

ブラウザレーンのみ

npm run test:all

両方

npm run test:list

実行せずにすべてのスイートとテストを一覧表示する

node test/run.mjs --grep=fill

スイート/名前が一致するテストだけを実行する

テスト構成

test/
├── run.mjs                    # CLI: lanes, filtering, coverage, reporting
├── lib/
│   ├── runner.js              # suite registry, isolation, timeouts
│   ├── assert.js              # assertions with diagnostic messages
│   ├── wait.js                # eventually() - polling, not fixed sleeps
│   ├── mcp-probe.js           # real in-process MCP handshake
│   ├── bridge.js              # stands in for the hub; tracks tool coverage
│   ├── fixture-server.js      # serves the fixture pages
│   └── page.js                # the browser session + per-test reset
├── fixtures/
│   ├── index.html             # the fixture page (a real file, with __reset())
│   └── frame.html             # child frame, for frameId targeting
└── suites/
    ├── 01-contract.suite.js   # offline
    ├── 02-security.suite.js   # offline
    ├── 10-navigation.suite.js
    ├── 20-tabs.suite.js
    ├── 30-perception.suite.js
    ├── 40-interaction.suite.js
    ├── 50-trusted-input.suite.js
    ├── 60-observability.suite.js
    └── 70-capture.suite.js

セキュリティに関する注意

この拡張は、ログイン済みのブラウザを操作できます。必ず読みかつてください。

  • ループバックのみ。 ハブは 127.0.0.1 にバインドするため、LAN からは到達できません — このマシン上のプロセスだけがアクセスできます。

  • トークンハンドシェイク。 ピアェアは接続時に AUTH_TOKEN を提示する必要があり、提示しない場合はハブが切断します。出荷時のデフォルトから変更してくださいsrc/config.jsextension/src/config.js 内の同一定数)— これが、他のローカルプロセスによるブラウザ操作を防ぐものです。

  • ファイルの書き込みはキャプチャディレクトリに限定されます。 src/capture/capture-path.js は要求されたすべてのパスを解決し、.. の走査およびシンボリックリンクされたサブディレクトリ経由のものも含め、外部に解決されるものを拒否します。これは見た目以上、任意のパスへの書き込みは事実上のコード実行になります。

  • ホスト禁止リスト。 extension/src/config.jsBANLIST は、重要なドメイン(銀行、PayPal、Gmail)へのナビゲーションとスクリプト実行をブロックします。必要に応じて調整してください。注意: スクリーンショットと録画はレンダリングされたピクセルを取得するものであり、禁止リストではフィルタされません。

  • デバッガのバナーは仕様です。 CDP ツールは chrome.debugger にアタッチし、永続した黄色の 「デバッグ中」 バーを表示します。これは、何かがタブを操作しているという視覚的な信号です。detach で除去できます。

  • evaluate は、ページの実際のコンテキストで任意の JS を実行します。

  • 内部ページは対象外です — 拡張は chrome:// および chrome-extension:// の URL をスクリプト化できません。

  • 署名するキーはこのリポジトリに置かれていません。 拡張 ID は extension/manifest.json 内の公開 key によって固定されます。一致する秘密鍵はバージョン管理の外に置く必要があります(.gitignore*.pem をブロック)。コードと同じ ID で .crx を再パッケージするときにのみ必要で、アドオンとして読み込む場合は使用しません。


アーキテクチャ

サーバーと拡張はミラー構造です。src/tools/ の各ツールグループは、extension/src/handlers/ に同じ名前のハンドラファイルがあります。ツールを追加するには、そのペア双方に手を加えます — 片側はスキーマとドキュメント、もう一方は実装です。

グループ

サーバー(スキーマ + ドキュメント)

拡張(実装)

navigation

src/tools/navigation.js

extension/src/handlers/navigation.js

tabs

src/tools/tabs.js

extension/src/handlers/tabs.js

perception

src/tools/perception.js

extension/src/handlers/perception.js

interaction

src/tools/interaction.js

extension/src/handlers/interaction.js

trusted input

src/tools/trusted-input.js

extension/src/handlers/trusted-input.js

observability

src/tools/observability.js

extension/src/handlers/observability.js

capture

src/tools/capture.js

extension/src/handlers/capture.js

その他のすべてはサポートインフラです:

  • bin/custom-chrome-dev-mcp.js - MCP クライアントに登録する実行可能ファイルです。サーバーを起動する以外のことはしません。

  • src/config.js / extension/src/config.js - 調整可能な全設定をサイドごとに1ファイルで管理します。AUTH_TOKEN とポートは2つの間で一致させる必要があります。

  • src/relay/hub-client.js - role:"mcp" として hub に接続し、存在しない場合は hub を起動し、各ツール呼び出しをソケット上のリクエスト/レスポンスに変換します。

  • src/hub.js - ws://127.0.0.1:9876 を所有する長期的なリレー。拡張機能のソケットを1つと各セッションのクライアントを保持し、それらの間で多重化します。回線上で ID を付け直し(セッション間で衝突する可能性がある)、すでにポートを所有する hub がある場合は自身を終了します。

  • src/capture/capture-path.js - 書き込み許可リスト。すべてのキャプチャパスはここを経由します。

  • extension/src/connection.js - hub ソケットとハートビートを担当します。MV3 のサービスワーカーは、約30秒間アイドル状態が続くと破棄され、それによってソケットは静かに切断されます。30秒未満のハートビートが両方を生かしたままにし、アラームが強制終了後にワーカーを復活させます。

  • extension/src/tabs.js - 呼び出しがどのタブを対象にするか(明示的な tabId > 固定タブ > アクティブタブ)、expectUrl ガード、禁止リストのチェックを行います。

  • extension/src/walker-bridge.js + extension/src/page/walker.js - 安定した element-ref システムを備えた注入済み ISOLATED-world スクリプトと、それに到達できる唯一のモジュール。

  • extension/src/cdp/ - session.js(アタッチ/デタッチ、cdp()、要素の中心)、keyboard.js(キー名 → CDP キーイベント)、dialogs.js(ネイティブダイアログのポリシー)、buffers.js(コンソール + ネットワークリングバッファ、タブごとに最大500件)。

  • extension/src/recording/ - chrome.tabCapture には MCP 呼び出しにないユーザージェスチャーが必要です。そのため、録画は代わりに CDP screencast を使用します。JPEG フレームをオフスクリーンの MediaRecorder に中継します(サービスワーカーには DOM がないため)。

  • test/ - 2レーン構成のスイート。ブラウザを必要としないオフライン CI ゲートと、実際の Chrome を操作するブラウザレーンがあります。テストの実行 を参照してください。


プロジェクト構成

.
├── bin/
│   └── custom-chrome-dev-mcp.js   # executable entry - register THIS with your client
├── src/
│   ├── server.js                  # composes config + relay + tool registry
│   ├── config.js                  # port, token, capture dir, timeouts
│   ├── hub.js                     # long-lived relay owning :9876
│   ├── relay/
│   │   └── hub-client.js          # session -> hub socket; call()
│   ├── capture/
│   │   └── capture-path.js        # write allowlist for screenshots/recordings
│   └── tools/                     # ONE FILE PER TOOL GROUP - the public surface
│       ├── index.js               # the registry
│       ├── schemas.js             # shared arg shapes + passthrough helper
│       ├── navigation.js
│       ├── tabs.js
│       ├── perception.js
│       ├── interaction.js
│       ├── trusted-input.js
│       ├── observability.js
│       └── capture.js
├── extension/                     # Chrome MV3 extension
│   ├── manifest.json
│   └── src/
│       ├── background.js          # service worker entry - wiring only
│       ├── config.js              # token, banlist, buffer caps, asset paths
│       ├── connection.js          # hub socket + MV3 keepalive heartbeat
│       ├── tabs.js                # tab resolution, pinning, ban check
│       ├── walker-bridge.js       # channel to the injected page script
│       ├── cdp/
│       │   ├── session.js         # attach/detach, cdp(), element centres
│       │   ├── keyboard.js        # key names -> CDP key events
│       │   ├── dialogs.js         # native alert/confirm/prompt policy
│       │   └── buffers.js         # console + network ring buffers
│       ├── recording/
│       │   ├── recorder.js        # CDP screencast -> offscreen encoder
│       │   ├── offscreen.html
│       │   └── offscreen.js       # MediaRecorder host
│       ├── page/
│       │   └── walker.js          # injected DOM driver (ISOLATED world)
│       └── handlers/              # MIRRORS src/tools/ - one file per group
│           ├── index.js           # the handler table + dispatch
│           ├── navigation.js
│           ├── tabs.js
│           ├── perception.js
│           ├── interaction.js
│           ├── trusted-input.js
│           ├── observability.js
│           └── capture.js
└── test/                          # two lanes: offline (CI) + browser
    ├── run.mjs                    # CLI entry
    ├── lib/                       # runner, assertions, bridge, fixtures, session
    ├── fixtures/                  # the fixture pages, as real files
    └── suites/                    # one suite per tool group

クレジット

Chrome DevTools MCP(Chrome DevTools チーム制作)に触発されています。独立した再実装であり、Google とは関係なく、Google からの承認やサポートを受けていません。


ライセンス

MIT. Copyright (c) 2026 Haba Andrei.

自由に使って、フォークして、リリースしてください。唯一の条件は、著作権表示と許諾表示が実質的なコピーにそのまま含まれることです。

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP clients to drive a real, logged-in Chrome browser for web automation tasks like navigation, clicking, typing, and screenshotting.
    1
    1
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Drive your real, signed-in Chrome browser from any MCP client, enabling browser automation such as navigation, clicking, typing, and screenshots through standard MCP tools.
    1
  • A
    license
    C
    quality
    A
    maintenance
    MCP server for browser automation that drives Chrome via an extension, preserving login state and offering 45 tools for navigation, interaction, scraping, and screenshots.
    53
    4
    MIT

View all related MCP servers

Related MCP Connectors

  • Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.

  • Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.

  • Stealth web browser for agents: search, fetch, click, download and type in persistent MCP sessions.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/HabaAndrei/custom-chrome-dev-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server