Skip to main content
Glama
yangsheng6810

Department Web-Search MCP Gateway

MCP-шлюз веб-поиска отдела

Самодостаточный веб-поисковый сервис, которым может пользоваться весь отдел. Он использует один сеанс браузера с выполненным входом (общая служебная учётная запись), поэтому вход в интранет / SSO / страницы с согласием обрабатывается один раз — каждый клиент просто вызывает инструмент web_search, без отдельного входа или API-ключа.

Любой MCP-клиент подключается к одному URL:

  • Chatbox (≥1.14)

  • OpenCode — локально, на общем сервере или через vscode-remote

  • Claude Code (и другие агенты программирования, поддерживающие MCP)

Это T1 «централизованный поисковый шлюз» из исследовательских заметок: одна внутренняя машина + один общий профиль Chrome + одна 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, поэтому совместимость транспортного протокола клиента не имеет значения.


Серверы без графического интерфейса + ПК с Windows для входа

На серверах нет графического интерфейса, но человек может войти на ПК с Windows. Выберите режим в .env (BROWSER_MODE) — код одинаков, отличается только конфигурация.

⚠️ НЕ копируйте каталог профиля Windows Chrome на Linux. Chromium шифрует файлы cookie с помощью ключей, привязанных к ОС (DPAPI в Windows, keyring/«peanuts» в Linux), поэтому скопированный профиль незаметно теряет файлы cookie. Используйте один из безопасных для разных ОС режимов ниже.

Режим C — BROWSER_MODE=cdp (рекомендуется): шлюз Linux подключается к браузеру Windows

  • ПК с Windows (остаётся включённым): войдите один раз с общей учётной записью, затем оставьте Chrome запущенным с локальным отладочным портом:

chrome --remote-debugging-port=9222 --remote-debugging-address=127.0.0.1 ^
       --user-data-dir=C:\dept-search-profile
  • Передайте этот порт на сервер Linux безопасно с помощью обратного SSH-туннеля (запускается на ПК с Windows; в Win10/11 встроен OpenSSH):

ssh -R 9222:127.0.0.1:9222 linuxuser@gateway.server
  • Сервер Linux: .envBROWSER_MODE=cdp, CDP_ENDPOINT=http://127.0.0.1:9222 (локально на сервере, туннелирован обратно в браузер Windows). Затем npm start.

  • Сеанс остаётся активным (файлы cookie обновляются при использовании браузера); копирование профиля не требуется; неаутентифицированный порт CDP никогда не находится в сети. Недостаток: если ПК с Windows выключен — поиск не работает, пока он не включится (используйте Режим B, если это неприемлемо).

Режим B — BROWSER_MODE=storagestate: снимок, Linux самодостаточен

  • ПК с Windows: npm run login (с графическим интерфейсом), войдите, нажмите Enter → записывается auth.json (независимый от ОС JSON с файлами cookie + localStorage).

  • Скопируйте auth.json на сервер Linux, установите BROWSER_MODE=storagestate, STORAGE_STATE_FILE=./auth.json, запустите npm start. Linux запускает собственный безголовый браузер, загружающий снимок — без туннеля, работает даже при выключенном ПК с Windows.

  • Компромисс: замороженный снимок — повторно экспортируйте, когда истечёт срок действия SSO-куки; содержит только файлы cookie + localStorage (не IndexedDB/клиентские сертификаты) — подходит для большинства SSO.

Режим A — BROWSER_MODE=persistent: ПК с Windows запускает всё

  • Если есть запасной ПК с Windows, который может быть постоянно включённым хостом сервиса: выполните npm run login на нём (создаётся профиль), затем npm start с BROWSER_MODE=persistent.

  • Серверы Linux — это просто клиенты, указывающие на http://<windows-pc>:8787/mcp.

  • Самый простой вариант — без туннеля, без церемоний со снимками.

Подключение клиента одинаково во всех режимах: клиенты указывают на URL MCP-шлюза; шлюз взаимодействует с выбранным режимом браузера.


Инструкция по запуску — Режим C (шлюз Linux + браузер Windows)

Подтверждённая настройка: сервер Linux запускает шлюз; постоянно включённый ПК с Windows запускает настоящий Chrome (один раз выполнен вход) и обратный SSH-туннель. Браузер не загружается на сервер Linux (только playwright-core).

ПК с Windows (один раз, затем оставить работающим) — см. 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. Сделайте оба запланированными задачами (При запуске / При входе в систему, выполнять независимо от того, выполнен ли вход пользователя), чтобы ПК был самовосстанавливающимся браузерным устройством.

Сервер шлюза 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

Пусто / соединение отклонено → Chrome на Windows или обратный туннель ещё не запущены; 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) и будет использоваться безголовым шлюзом в дальнейшем.

Серверы без графического интерфейса? Выполните шаг npm run login на ПК с Windows, затем выберите Режим B (скопируйте auth.json на Linux) или Режим C (SSH-туннель CDP на Linux), как описано в разделе «Серверы без графического интерфейса + ПК с Windows для входа» выше. Обновление при истечении сеанса SSO: Режим A/B → повторно запустите npm run login (и повторно скопируйте auth.json для B); Режим C → просто повторно войдите в Chrome на Windows.

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 — все три варианта

Добавьте в 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 (строка, обязательно), engine (bing|google|duck|custom, необязательно)

список {title, url, snippet} в виде текста + JSON

read_webpage

url (строка, обязательно)

# 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: URL CDP подключённого браузера (обычно туннелированный порт)

STORAGE_STATE_FILE

./auth.json

режим storagestate: снимок входа, экспортированный на Windows, скопирован сюда

BROWSER_PROFILE_DIR

./.profile

режим persistent: профиль Chrome, хранящий общий сеанс входа

HEADLESS

true

false только для отладки

MAX_CONCURRENT_PAGES

4

ограничение параллельности (один Chrome, изолированные вкладки)

PAGE_TIMEOUT_MS

20000

жёсткий таймаут на страницу

SEARCH_ENGINE

bing

bing (настроенный извлекатель) / google / duck / custom

SEARCH_URL_TEMPLATE

пользовательский URL с плейсхолдером {q}, например https://wiki.internal/search?q={q} (переопределяет URL движка)

RESULT_COUNT

10

результатов на запрос

SEARXNG_URL

дополнительный запасной публичный поиск (требует исходящий интернет), например http://127.0.0.1:8080


Добавление пользовательского извлекателя для внутреннего портала

extractBing в src/tools.ts настроен на DOM Bing. Для внутреннего портала добавьте extractPortal(page, count) и выберите его по имени движка в searchWithBrowser. Универсальный extractGeneric уже возвращает ссылки на якоря + близлежащий текст как приемлемый запасной вариант для неизвестных DOM.


Заметки по безопасности и эксплуатации

  • Привязка и доступ: предпочтительно оставлять шлюз во внутренней сети. Если вы привязываетесь к 0.0.0.0, установите ALLOWED_HOSTS и используйте брандмауэр / сетевой ACL, или установите GATEWAY_TOKEN, или поместите за обратный прокси с SSO.

  • Общий профиль = общая идентичность: каждый поиск приписывается общей учётной записи. Нормально для служебной учётной записи отдела; проверьте, если целевая система отслеживает пользователей или имеет квоту.

  • Обновление сеанса: повторно запустите npm run login, когда истечёт SSO. Рассмотрите еженедельный cron, отправляющий напоминание по электронной почте, или проверку работоспособности, которая обнаруживает страницу входа (read_webpage на известном URL, требующем входа, возвращает текст страницы входа).

  • Параллельность / масштабирование: один Chrome с изолированными вкладками справляется с небольшим отделом. Для увеличения масштаба используйте пул браузеров (N постоянных контекстов), если он насыщается — место для изменения — это только withPage.

  • Безголовый Chrome на Linux: --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 транзитивный esbuild от tsx блокируется allow-scripts по умолчанию. Разрешите один раз (npm approve-scripts) или используйте скомпилированный путь везде: npm run build && node --env-file=.env dist/server.js.


Статус

Это обозреваемый PoC / скелет — проверенный на соответствие API v2 MCP SDK (@modelcontextprotocol/server 2.x, createMcpHandler / createMcpExpressApp / requireBearerAuth / toNodeHandler) и API постоянного контекста Playwright. Перед производством: зафиксируйте точные версии зависимостей, добавьте тесты и укрепите уровень аутентификации (JWT / интроспекция вместо статического токена), если вы выставляете его за пределы доверенной внутренней сети.

Дизайн-контекст (топологии режимов A/B/C, межплатформенная проблема шифрования cookie, границы SearXNG) находится в разделе «Безголовые серверы Linux + ПК с Windows для входа» выше.

-
license - not tested
-
quality - not tested
C
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 Connectors

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

  • Multi-engine search for AI agents. Trust scoring, local corpus, MCP-native. Self-hostable, BYOK.

  • Self-hosted MCP gateway: turn any API, database or MCP server into AI connectors — no code.

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/yangsheng6810/web-search-mcp'

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