Skip to main content
Glama
yangsheng6810

Department Web-Search MCP Gateway

部署 Web-Search MCP ゲートウェイ

部門全体で共有できるセルフホスト型ウェブ検索サービスです。単一のログインブラウザセッション(共有サービスアカウント)を再利用するため、イントラネット / SSO / 同意画面ログインは一度だけ処理されます。すべてのクライアントは web_search ツールを呼び出すだけで、ユーザーごとのログインや API キーは不要です。

任意の MCP クライアントが1つの URL に接続します:

  • Chatbox (≥1.14)

  • OpenCode — ローカル、共有サーバー上、または vscode-remote 経由

  • Claude Code(および MCP を話す他のコーディングエージェント)

これは調査ノートの T1「集中検索ゲートウェイ」 です:1台の内部マシン + 1つの共有 Chrome プロファイル + 1つの HTTP MCP エンドポイント。


仕組み

Chatbox / OpenCode(local|server|vscode-remote) / Claude Code
        │  remote MCP (Streamable HTTP, /mcp) — same URL for everyone
        ▼
┌──────────────────────────────────────────────┐
│  Gateway (this service, Node + Express)       │
│   • Bearer token (optional) + Host validation │
│   • MCP tools: web_search / read_webpage      │
└──────────────────────────────────────────────┘
        │  connectOverCDP / launchPersistentContext
        ▼
┌──────────────────────────────────────────────┐
│  Chrome (persistent profile, shared account)  │  ← logged in ONCE via `npm run login`
│   • per-request new tab (isolation)           │
│   • concurrency cap + timeouts                │
└──────────────────────────────────────────────┘
        │  optional fallback
        ▼
   SearXNG (if SEARXNG_URL set) — public-search fallback when browser returns nothing

createMcpHandler は、同じ /mcp エンドポイントで 2025 年世代と 2026 年世代の両方の MCP クライアント を提供するため、クライアントのトランスポート互換性は問題になりません。


Related MCP server: local-web-search-service

ヘッドレス Linux サーバー + ログイン用 Windows PC

サーバーには GUI がありませんが、人間が Windows PC でログインできます。.env でモードを選択します(BROWSER_MODE)— コードは同じで、設定のみが異なります。

⚠️ Windows Chrome の プロファイル ディレクトリを Linux にコピーしないでください。 Chromium は Cookie を OS にバインドされたキー(Windows では DPAPI、Linux ではキーリング/"peanuts")で暗号化するため、コピーしたプロファイルは静かにログインを失います。以下のクロス OS セーフなモードのいずれかを使用してください。

モード C — BROWSER_MODE=cdp(推奨):Linux ゲートウェイが Windows ブラウザに接続

  • Windows PC(常時オン):共有アカウントで一度ログインし、ローカルのみのデバッグポートで Chrome を起動したままにします:

    chrome --remote-debugging-port=9222 --remote-debugging-address=127.0.0.1 ^
           --user-data-dir=C:\dept-search-profile
  • そのポートを SSH リバーストンネル で Linux サーバーに安全に転送します(Windows PC で実行;Win10/11 には OpenSSH が同梱):

    ssh -R 9222:127.0.0.1:9222 linuxuser@gateway.server
  • Linux サーバー:.env → BROWSER_MODE=cdp、CDP_ENDPOINT=http://127.0.0.1:9222(サーバー上でローカル、Windows ブラウザにトンネル経由で戻る)。その後 npm start。

  • ログインはライブのまま(ブラウザが使用されるにつれて Cookie が更新されます);プロファイルのコピーは不要;認証されていない CDP ポートはネットワーク上に公開されません。欠点:Windows PC がオフになると、復帰するまで検索が失敗します(それが許容できない場合はモード B を使用)。

モード B — BROWSER_MODE=storagestate:スナップショット、Linux 自己完結型

  • Windows PC:npm run login(ヘッドあり)を実行し、ログインし、Enter キーを押す → auth.json(OS に依存しない Cookie + localStorage の JSON)が書き込まれます。

  • auth.json を Linux サーバーにコピーし、BROWSER_MODE=storagestate、STORAGE_STATE_FILE=./auth.json を設定し、npm start を実行します。Linux はスナップショットを読み込んだ独自のヘッドレスブラウザを実行します — トンネル不要、Windows PC がオフでも動作します。

  • トレードオフ:凍結されたスナップショット — SSO Cookie の有効期限が切れたら再エクスポート;Cookie + localStorage のみを保持(IndexedDB/クライアント証明書は不可)— ほとんどの SSO で十分です。

モード A — BROWSER_MODE=persistent:Windows PC がすべてを実行

  • 予備の Windows PC を常時稼働のサービスホストとして使用できる場合:そこで npm run login を実行(プロファイルをシード)、その後 BROWSER_MODE=persistent で npm start を実行します。

  • Linux サーバーは http://<windows-pc>:8787/mcp を指す純粋なクライアントになります。

  • すべての中で最もシンプル — トンネルもスナップショットの手順も不要。

クライアントのオンボーディングはすべてのモードで同じです:クライアントはゲートウェイの MCP URL を指します;ゲートウェイは設定されたブラウザモードと通信します。


立ち上げ手順書 — モード C(Linux ゲートウェイ + Windows ブラウザ)

確認済みのセットアップ:Linux サーバー がゲートウェイを実行;常時稼働の Windows PC が実際の Chrome(一度ログイン)と SSH リバーストンネルを実行します。Linux サーバーにはブラウザはダウンロードされません(playwright-core のみ)。

Windows PC(一度実行し、その後は起動したまま)— windows/README.md を参照

  1. windows\start-browser.ps1 → 専用の Chrome を 127.0.0.1:9222 で起動、プロファイル C:\dept-search-profile。共有アカウント(SSO/2FA)でサインイン。開いたままにします。

  2. $env:GATEWAY_SSH = "linuxuser@gateway.server"; windows\start-tunnel.ps1 → ssh -R 9222:127.0.0.1:9222 gateway を維持、自動再接続。

  3. 両方をタスクスケジューラ(起動時 / ログオン時、ユーザーのログオン状態に関わらず実行)に設定し、PC を自己修復型ブラウザアプライアンスにします。

Linux ゲートウェイサーバー(このマシン)

cd dept-web-search-gateway
cp .env.example .env
# edit .env:
#   BROWSER_MODE=cdp                       (default)
#   CDP_ENDPOINT=http://127.0.0.1:9222     (the tunneled port, local on this server)
#   HOST=0.0.0.0
#   ALLOWED_HOSTS=search.internal,localhost   # hostnames clients will use
#   GATEWAY_TOKEN=...                      (optional; else rely on network ACL)
npm install                 # lean — playwright-core, no Chromium download
npm run build               # typecheck
npm start                   # dev (tsx); or `npm run build && npm run start:prod`
curl http://127.0.0.1:8787/health         # {"ok":true,...}

クライアントを http://<this-server>:8787/mcp に向けます(クライアントオンボーディングを参照)。

トンネルの健全性確認

Linux サーバー上で:

curl -s http://127.0.0.1:9222/json/version   # Chrome's JSON → tunnel + Chrome are up

空 / 接続拒否 → Windows Chrome またはリバーストンネルがまだ実行されていません;web_search は実行されるまで失敗します。


セットアップ(一度だけ)

cd dept-web-search-gateway
npm install                 # also runs `playwright install chromium`
cp .env.example .env       # then edit .env (see knobs below)

1) 共有ログインをシードする(核心)

ディスプレイがあるマシン(または xvfb-run -a 下)で一度だけ実行:

npm run login
# or, for an internal portal:
LOGIN_START_URL=https://wiki.internal npm run login

実際の Chrome ウィンドウが開きます。共有サービスアカウント(SSO / 2FA)でサインインし、検索エンジン / ポータルにログインしたことを確認してから、ウィンドウを閉じます。セッションは BROWSER_PROFILE_DIR(デフォルト ./.profile)に保存され、今後ヘッドレスゲートウェイによって再利用されます。

サーバーはヘッドレスですか? Windows PC で npm run login 手順を実行し、上記の 「ヘッドレス Linux サーバー + ログイン用 Windows PC」 で説明されているようにモード B(auth.json を Linux にコピー)またはモード C(CDP を SSH トンネルで Linux に転送)を選択します。SSO セッションの有効期限が切れた場合の更新:モード A/B → npm run login を再実行(B の場合は auth.json を再コピー);モード C → Windows Chrome で再ログインするだけです。

2) ゲートウェイを実行

npm start                   # dev (tsx)
# or production:
npm run build && npm run start:prod

次のように表示されるはずです:

[server] MCP gateway on http://0.0.0.0:8787/mcp  (engine=bing)
[server] profile=./.profile

クライアントオンボーディング(これを同僚に渡す)

search.internal / 8787 をゲートウェイのホスト/ポートに置き換えます。全員が同じ URL を使用します。

Chatbox (≥1.14)

設定 → MCP → サーバーを追加 → リモート / URL を選択:

  • URL: http://search.internal:8787/mcp

  • (GATEWAY_TOKEN が設定されている場合)クライアントがサポートしていればヘッダー Authorization: Bearer <TOKEN> を追加;そうでなければネットワーク ACL で保護します。

ワンクリックディープリンク(イントラネットページに配置):

chatbox://mcp/install?server=<base64 of {"name":"websearch","url":"http://search.internal:8787/mcp"}>

OpenCode — 3つのフレーバーすべて

opencode.json(プロジェクト)または ~/.config/opencode/opencode.json(グローバル)に追加:

{
  "mcp": {
    "websearch": {
      "type": "remote",
      "url": "http://search.internal:8787/mcp",
      "enabled": true
    }
  }
}
  • ローカル opencode:同じスニペット、ホスト = 127.0.0.1 またはゲートウェイホスト。

  • サーバー opencode:プロセスはサーバー上で実行 → ゲートウェイの内部 URL を直接指します(サーバーは内部ネットワーク経由で到達可能である必要があります)。

  • vscode-remote opencode:プロセスはリモートホスト上で実行 → ゲートウェイの内部 URL を指します(そのホストから到達可能)。ゲートウェイが内部ネットワーク上にあるため、トンネリングは不要です。

  • 確認:opencode mcp list。

Claude Code

claude mcp add --transport http websearch http://search.internal:8787/mcp
# with a token:
claude mcp add --transport http --header "Authorization: Bearer <TOKEN>" \
  websearch http://search.internal:8787/mcp

Cline / Cursor / その他

リモート MCP をサポートしている場合は、同じ URL を指します。stdio のみの場合は、HTTP ゲートウェイを呼び出す小さなローカルシム(20行のラッパー)を実行します — ここには含まれていませんが、追加は簡単です。


公開ツール

ツール

引数

戻り値

web_search

query(str、必須)、engine(bing|google|duck|custom、オプション)

{title, url, snippet} のリスト(テキスト + JSON)

read_webpage

url(str、必須)

# title + メインテキスト(≤20k 文字)、ログイン/SSO 処理済み

Chatbox/OpenCode/Claude Code のエージェントは、新しい情報が必要なときに web_search を呼び出し、特定のページを読むために read_webpage を呼び出します — 追加の配線は不要です。


設定ノブ(.env)

変数

デフォルト

意味

HOST

0.0.0.0

バインドアドレス。127.0.0.1 = ローカルホストのみ(+自動 DNS リバインディング保護)

ALLOWED_HOSTS

—

クライアントが使用するホスト名のカンマ区切りリスト(Host ヘッダー検証を有効化)。0.0.0.0 にバインドする場合は設定

PORT

8787

リッスンポート

GATEWAY_TOKEN

—

設定されている場合、Authorization: Bearer <token> を要求。空 = 認証なし(ネットワーク ACL のみ)

BROWSER_MODE

cdp

persistent / storagestate / cdp — トポロジーセクションを参照

CDP_ENDPOINT

http://127.0.0.1:9222

cdp モード:接続先ブラウザの CDP URL(通常はトンネルされたポート)

STORAGE_STATE_FILE

./auth.json

storagestate モード:Windows でエクスポートされ、ここにコピーされたログインスナップショット

BROWSER_PROFILE_DIR

./.profile

persistent モード:共有ログインを保持する Chrome プロファイル

HEADLESS

true

デバッグ時のみ false

MAX_CONCURRENT_PAGES

4

同時実行数の上限(1つの Chrome、分離されたタブ)

PAGE_TIMEOUT_MS

20000

ページごとのハードタイムアウト

SEARCH_ENGINE

bing

bing(調整済み抽出器) / google / duck / custom

SEARCH_URL_TEMPLATE

—

{q} プレースホルダー付きのカスタム URL(例:https://wiki.internal/search?q={q})(エンジン URL を上書き)

RESULT_COUNT

10

クエリあたりの結果数

SEARXNG_URL

—

オプションの公開検索フォールバック(アウトバウンドインターネットが必要)(例:http://127.0.0.1:8080)


カスタム内部ポータル抽出器の追加

src/tools.ts の extractBing は Bing の DOM に合わせて調整されています。内部ポータルの場合は、extractPortal(page, count) を追加し、searchWithBrowser 内のエンジン名で選択します。汎用の extractGeneric は、未知の DOM に対するパス可能なフォールバックとして、アンカーリンクと近くのテキストをすでに返します。


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

  • バインドと公開:ゲートウェイは内部ネットワーク上に保持することを推奨します。0.0.0.0 にバインドする場合は、ALLOWED_HOSTS を設定し、ファイアウォール / ネットワーク ACL を使用するか、GATEWAY_TOKEN を設定するか、SSO リバースプロキシの背後に配置します。

  • 共有プロファイル = 共有 ID:すべての検索は共有アカウントに帰属します。部門サービスアカウントには問題ありませんが、ターゲットがユーザーごとに監査したりクォータがある場合は確認してください。

  • セッション更新:SSO の有効期限が切れたら npm run login を再実行します。リマインダーをメールで送信する週次 cron、またはログインウォールを検出するヘルスプローブ(read_webpage で既知のログイン必須 URL を呼び出し、ログインページのテキストが返されるか確認)を検討してください。

  • 同時実行性 / スケール:1つの Chrome と分離されたタブで小規模な部門を処理できます。飽和する場合は、ブラウザプール(N 個の永続コンテキスト)に拡張します — withPage の継ぎ目が変更する唯一の場所です。

  • Linux 上のヘッドレス Chrome:--no-sandbox --disable-dev-shm-usage はすでに設定されています(コンテナフレンドリー)。


開発とテスト

  • プローブは scripts/ にあり、../dist/ からインポートするため、最初にビルドします:npm run build。

    • scripts/probe-search.mjs "<query>" — 共有ブラウザを直接操作します(MCP をバイパス);CDP アタッチと Bing 抽出器を検証します。

    • scripts/probe-mcp.mjs <url> "<query>" — 実行中のゲートウェイに Streamable HTTP 経由で接続し(実際のクライアントパス)、ツールを一覧表示し、web_search を呼び出します。最初にゲートウェイを起動します:node --env-file=.env dist/server.js。

  • 開発モード(npm start → tsx):npm 11 では、tsx の推移的な esbuild の postinstall がデフォルトで allow-scripts によってブロックされます。一度承認するか(npm approve-scripts)、またはすべての場所でコンパイル済みパスを使用します:npm run build && node --env-file=.env dist/server.js。


ステータス

これはレビュー可能なPoC / スケルトンです — v2 MCP SDK API (@modelcontextprotocol/server 2.x, createMcpHandler / createMcpExpressApp / requireBearerAuth / toNodeHandler) および Playwright の永続コンテキストAPI に対して検証済みです。本番環境では、依存関係のバージョンを固定し、テストを追加し、信頼できる内部ネットワークの外に公開する場合は認証レイヤーを強化(静的トークンの代わりにJWT / イントロスペクション)してください。

設計コンテキスト(Mode A/B/C トポロジー、OS間のCookie暗号化の落とし穴、 SearXNGの境界)は、上記の「Headless Linux servers + a Windows PC for login」 セクションにあります。

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers