npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@marrowdev/browse-mcp

v0.19.1

Published

Drive your own Chrome from an AI agent, with its logins intact. A local stdio MCP server: it maps what a page affords, acts on it, and hands the keyboard back to you for logins, 2FA and CAPTCHAs instead of solving them.

Readme

marrow-browse — ローカル stdio MCP(実ブラウザを操縦する)

ユーザー自身の Chrome を、専用プロファイルで Playwright から駆動する stdio MCP。 AI は外の脳として browse_open / browse_act / browse_read / browse_paginate / browse_wait_for_human / browse_list / browse_close / browse_shutdown を使う。

🤝 browse_wait_for_human だけは向きが逆(2026-08-03・Marrow #16)。他は「AI が動く」道具だが、 これは人が動くのを AI が待つ道具 —— CAPTCHA・ログイン・2FA・同意画面。デスクトップ通知を出し、 条件が満たされるまで上限付きで待ち、終わり方を全部名前で返す(cleared / already / navigated / widget-gone / timed-out / page-gone / blind)。⚠️ チャレンジを自動で解かない・ 自動化を隠さない —— 人間チェックは人間が通す、という線は意図的(証跡が正直であることがこの製品の価値)。

🚨 弱い名前が 2 つあるのは意図的(navigated / widget-gone)。観測していないことを名乗らないため:

| 名前 | 観測したこと | 言えないこと | |---|---|---| | navigated | ページが 1 回移った | 多段ログインの途中の段かもしれない(Marrow #63・npm で実測) | | widget-gone | チャレンジ部品が消えた | サイトが受け入れたかは見ていない(#22・Stripe で実測) |

⭐ #22 の実測: Stripe は multicaptcha(hCaptcha + HUMAN Security)を併走させ、人が hCaptcha を 解いて部品が消えた後に 401 を返し、しかもそれを**「メールまたはパスワードが正しくありません」と 名乗った。⇒ 見えるチャレンジを人が通しても、ブラウザ自体を見ている 2 つ目の検査は覆らない。 どちらの名前も expect(行き先)を渡せば cleared になる —— 行き先を名乗れた**時だけ cleared。

⚠️ browse_close は 1 ページ、browse_shutdown はブラウザごと(2026-07-31 に分離)。 ブラウザが生きている限りセッション Cookie も生きるので、remember-me を持たないサイトの ログインも残る。browse_shutdown を呼ぶとそのサーバは二度と起動できない(原因未特定)。

インストール

npm i -g @marrowdev/browse-mcp

前提物は Google Chrome だけ(node は 20 以上 —— ⚠️ 2026-08-13 実測で 18 では起動しない。 playwright-core が Playwright requires Node.js 20 or higher. と言って止まる。 🚨 package.json の engines は長く >=18 を名乗っていた= npm は通し、走らせると死ぬ形だった)。⚠️ Chrome は同梱しないし、落としてもこない —— 掴むのはあなたが昨日ログインしたままの Chromeなので、代替ブラウザや playwright の同梱 chromium を 使うと素のプロファイルで起動する=この道具の意味が消える。見つからなければ chrome-not-found と 名前で止まり、CHROME_PATH の設定を促す(スタックトレースは出さない)。

MCP クライアントの設定(例: ~/.claude.json):

"marrow-browse": {
  "command": "marrow-browse",
  "env": {
    "MARROW_BROWSE_HEADLESS": "0",
    "MARROW_BROWSE_IDLE_MS": "1800000"
  }
}

🤝 初回は MARROW_BROWSE_HEADLESS=0(表示あり)で。窓が出たら、使いたいサイトに人が一度 ログインする —— 以後そのプロファイルにセッションが residing するので、AI はその先を歩ける。 ⚠️ パスワードはこの道具に渡さない(渡す口が無い。打つのは人とブラウザの autofill)。

リポの clone から動かす場合(開発)

⚠️ 上とは別経路。clone には run.sh が在り、起動ごとに焼き直す(焼いた物を残さない)。

"marrow-browse": {
  "type": "stdio",
  "command": "<clone>/browse-mcp/run.sh",
  "env": {
    "PATH": "<node 20+ の bin>:/usr/bin:/bin",
    "MARROW_PROFILE_DIR": "<state>/marrow/profiles/default",
    "MARROW_BROWSE_HEADLESS": "0",
    "CHROME_PATH": "/usr/bin/google-chrome"
  }
}

🚨 run.sh を通すこと。bun run browse-mcp/index.ts で直に起動しない —— playwright の connectOverCDP は bun でハングする(playwright-core 1.58.1 / 1.52 / 1.48 / 1.44 / 1.40 の 5 版で 2026-08-02 に実測・全部 timeout)。run.sh は node 向けに焼いてから node で走らせる、 そのためだけに在る。⚠️ この行が要る理由は run.sh の冒頭が全部書いている。

🚨 <clone> を実パスに読み替えるのは読む人。ここに実パスを焼かない —— 2026-08-11 の分割で /home/takaki2/dev/Marrow を焼いたこの例が丸ごと存在しない場所を指すようになり、 live 登録もろとも 2 日間死んでいた(2026-08-13 実測・このリポの #1)。⚠️ 環境依存の絶対パスは、 書いた面の数だけ次に腐る面が増える。

⚠️ 落とし穴 3 つ(全部踏んだ):

  1. env は MCP の起動設定側で渡す。 StdioClientTransport は呼び出し側の env を素通ししない —— シェルで export しても効かず、既定パスに落ちる。
  2. PATH に node 20+ を入れる(2026-08-13 実測)。run.sh は最後に exec node するので、 クライアントが渡す最小 PATH で **/usr/bin/node(18 系)**を掴むと、esbuild は緑のまま playwright が requires Node.js 20 or higher で止まる。🚨 ビルドが通ってから死ぬので 「起動した」ように見える。nvm を使っているなら ~/.nvm/versions/node/<ver>/bin を明示する。
  3. ~~cd を書く~~ → ✅ もう要らない(2026-08-13)。run.sh は冒頭で自分の位置から repo root へ移るので、/bin/sh -c と cd を挟まず run.sh を絶対パスで直接 command にする。 ⚠️ 2026-08-10 に「この設定を書き換える作業で cd を 2 回落とした」と書いてあった落とし穴は、 消えやすい物を無くす方で塞いだ。無関係な cwd(/tmp)から起動して緑を確認済み。
  • 起動(手で): <clone>/browse-mcp/run.sh(bun install 済みであること=バンドラが devDependency)
  • プロファイルの仕組み・器の制約・実測記録・移植の分界線 → リポのルートにある USAGE.md

🚨 ここをリンクにしないこと(#12)。この README は npm に同梱されて配られるので、 パッケージの外へ登る相対リンクは npmjs.com で 404 する —— clone では緑に見えるまま、 ②に初めて会う人の所でだけ切れる。⚠️ 絶対 URL も使えない: 出所は LAN の Gitea で、 外からは辿れない(repository / homepage を意図的に載せていないのと同じ理由)。 💭 公開ページが出来たら(Marrow #38)そこを指すのが本筋。check-dist.mjs が prepublishOnly から見張っていて、登るリンクが在れば publish が止まる。

設定を更新したら /mcp reconnect

🚨 設定エントリを変えた直後の reconnect だけ、前のサーバが取り残される(2026-08-10 実測・ クライアントのログと 5/5 で一致)。定義が変わらない reconnect では、クライアントが SIGINT → SIGTERM できちんと止めている。

✅ Linux では新しいサーバが起動時に前の自分を落とすので、放っておいてよい (stderr に swept 1 older self/selves: <pid> と出る)。 🚨 macOS にはその掃除が無い(/proc を読む実装のため)。あちらでは手で:

ps -eo pid,ppid,pgrp,lstart,args | grep target/browse-mcp.mjs   # 同じ pgrp の古い方が残骸

⚠️ pkill -f target/browse-mcp.mjs は使わないこと —— 他セッションの現用サーバも 同じコマンド行なので、まとめて落とす。pid を見てから落とす。

  • スモークテスト: bun run browse-mcp/probes/probe-paginate-wire.ts(MCP の面を実際に叩く) ⚠️ 昔ここは poc/act-perceive/test-client.ts を指していたが、poc/ は 2026-08-11 の分割で Marrow に残ったので、このリポには無い(→ #4)。 🚨 browse-mcp/probes/e2e-lifecycle.ts は回さないこと —— あれだけ共有プロファイルを使い browse_shutdown まで踏むので、走らせるとログインを失いうる(前科あり)。

この repo の中に置いてある理由

src/affordance.ts(perceive / act)に直接依存するため。mcp-servers/ に移すと 別リポの内部実装を相対 import することになり、複製に逆戻りしやすい。

🚨 その懸念は実際に当たった。ここへ昇格したとき(2026-07-30)旧 poc/act-perceive/core.ts を 消さなかったので、同じ export を持つ 2 つ目の実体が残り、5 本の PoC がそちらを使い続けた。 修正が丸一日届かなかった(ref 一意化バグ)。2026-07-31 に core.ts を削除して解消。 src/affordance.ts が唯一の実体。ここにコピーを作らないこと。

⚠️ 2026-08-11 の分割後もこの理由は変わっていない —— 変わったのは「この repo」が Marrow ではなく marrow-browse を指すようになったことだけ。browse-mcp/ と src/ が 兄弟のままなのはそのため(移設で import を 1 行も書き換えていない)。 💭 Marrow 側が同じ 5 本を使う必要は、コピーではなく @marrowdev/browse-core で満たしている。

| MCP | 経路 | 何を操縦するか | 置き場 | |---|---|---|---| | marrow-browse(これ) | stdio・ローカル | 本人のブラウザ(ログイン済みセッション) | この repo | | marrow-lan | HTTP(:3002) | macmini の worker(取得サービス・LAN 限定・課金なし) | ~/dev/mcp-servers/marrow-lan-mcp | | marrow | — | ③ SaaS(Edge 経由・課金) | Marrow の mcp-saas/(npm @marrowdev/cloud-mcp) |

環境変数

| | 既定 | | |---|---|---| | MARROW_PROFILE_DIR | OS 別(Linux ~/.local/share/marrow/profiles/default) | ログインが溜まる器。⚠️ 日常プロファイルを指さない | | MARROW_BROWSE_HEADLESS | 1(0 で表示あり) | 初回ログインは表示ありで | | CHROME_PATH | OS 別の候補から実在する最初の 1 つ(Linux /usr/bin/google-chrome → -stable → /opt/google/chrome/chrome、macOS は /Applications と ~/Applications の app bundle) | ⚠️ Chromium / Brave / Edge は候補に入れない。探しているのは「ページを開ける物」ではなく本人の Chrome のログイン済みプロファイルなので、代替を掴むと素のプロファイルで起動する=②の意味が消える。見つからなければ chrome-not-found で止まる(browse-mcp/probes/probe-chrome-missing.ts)| | MARROW_BROWSE_MAX | 8 | 同時 page 数(⚠️ 器 1 つに Chrome 1 つなので page 単位) | | MARROW_BROWSE_IDLE_MS | 300000 | アイドル回収。⚠️ 実際の登録は 1800000(30 分)で上書き=既定値を運用値と読まない。刈るのはページだけでブラウザは畳まない | | MARROW_BROWSE_LAUNCH_TIMEOUT_MS | 20000 | 起動の上限(⚠️ Playwright の launch 既定は 180 秒) | | MARROW_BROWSE_NEWPAGE_TIMEOUT_MS | 20000 | newPage() の上限(newPage は timeout 引数を取らないので外側で囲む) | | MARROW_BROWSE_NOTIFY | 1 | 人を呼ぶデスクトップ通知(0 で切る)。Linux は notify-send -u critical・macOS は osascript。⚠️ 窓は前に出さない(Wayland に手段が無く、上がらなくても例外が出ない=嘘になる)ので、報せ自体が行き先(サイト名)を持つ ——🚨 持つのは title(Marrow — <host>)。本文の最終行に置いていたら切り詰めで最初に消える場所だった(Marrow #58) | | MARROW_BROWSE_NOTIFY_CMD | — | 通知コマンドの差し替え。検出器用の縫い目(probe-handoff.ts が偽の通知器で「人が何を読むか」を実測する) |

🚧 通知の面はここから広げない(2026-08-03 に決めた): 一方向・撃ちっぱなしの「人が要る」 信号だけ。返事は受け取らない。 ボタン / 音 / 既読 / 常駐は全部「返事を受け取る」側で、 そこからが UI の所有 —— 返事が要る用事は client の仕事(MCP elicitation)。 ⚠️ 文面は英語 1 本。ここに翻訳表を置かない(呼び出し側がその人の言語を知っている LLM なので、 表を持つのは逆さま)。理由と逃げ道の全文は notify.ts の冒頭(⚠️ ソースなので同梱されない・リンクにしない・#12)。