Skip to main content
Glama
yangsheng6810

Department Web-Search MCP Gateway

部门 Web 搜索 MCP 网关

一个自托管的 Web 搜索服务,整个部门可以共享。它复用一个单一的已登录浏览器会话(一个共享服务账户),因此内网 / 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 客户端,因此客户端传输兼容性不是问题。


无头 Linux 服务器 + 用于登录的 Windows PC

服务器没有图形界面,但人类可以在 Windows PC 上登录。在 .env 中选择一种模式(BROWSER_MODE)——代码相同,仅配置不同。

⚠️ 不要将 Windows Chrome 配置文件目录复制到 Linux。Chromium 使用操作系统绑定的密钥加密 cookie(Windows 上为 DPAPI,Linux 上为 keyring/”peanuts”),因此复制的配置文件会静默丢失登录状态。请使用以下跨操作系统安全模式之一。

模式 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 服务器.envBROWSER_MODE=cdpCDP_ENDPOINT=http://127.0.0.1:9222(服务器本地,通过隧道回到 Windows 浏览器)。然后 npm start

  • 登录状态保持活跃(浏览器使用时 cookie 会刷新);无需复制配置文件;未认证的 CDP 端口永远不会暴露在网络中。缺点:Windows PC 关机 → 搜索失败,直到它重新上线(如果无法接受,请使用模式 B)。

模式 B — BROWSER_MODE=storagestate:快照,Linux 自给自足

  • Windows PCnpm run login(有界面),登录,按 Enter → 写入 auth.json(操作系统无关的 cookie + localStorage JSON)。

  • auth.json 复制到 Linux 服务器,设置 BROWSER_MODE=storagestateSTORAGE_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 → 在 127.0.0.1:9222 上启动专用 Chrome,配置文件为 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(SSH 隧道 CDP 到 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 — 所有三种风格

添加到 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 网关的微小本地 shim(一个 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 模式:所连接浏览器的 CDP URL(通常是一个隧道端口)

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


添加自定义内部门户提取器

src/tools.ts 中的 extractBing 针对 Bing 的 DOM 进行了调优。对于内部门户,添加 extractPortal(page, count) 并在 searchWithBrowser 中根据引擎名称选择它。通用的 extractGeneric 已经返回锚链接 + 附近文本,作为未知 DOM 的可用回退。


安全与运维说明

  • 绑定与暴露:最好将网关保留在内部网络上。如果您绑定 0.0.0.0,请设置 ALLOWED_HOSTS 并使用防火墙/网络 ACL,或设置 GATEWAY_TOKEN,或将其放在 SSO 反向代理后面。

  • 共享配置文件 = 共享身份:每次搜索都归因于共享账户。对于部门服务账户来说没问题;如果目标审计按用户或有限额,请检查。

  • 会话续期:当 SSO 过期时重新运行 npm run login。考虑设置一个每周 cron 任务发送提醒邮件,或一个健康探测来检测登录墙(read_webpage 在已知需要登录的 URL 上返回登录页面文本)。

  • 并发/规模:一个带有隔离标签页的 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


状态

这是一个 可审查的概念验证 / 骨架 —— 已对照 v2 MCP SDK API (@modelcontextprotocol/server 2.x、createMcpHandler / createMcpExpressApp / requireBearerAuth / toNodeHandler)和 Playwright 的持久上下文 API 进行了验证。投入生产之前:锁定精确的依赖版本、添加测试,并且如果在受信任的内部网络之外暴露此功能,请加固认证层(使用 JWT / 内省机制,而不是静态令牌)。

设计上下文(Mode A/B/C 拓扑、跨操作系统 Cookie 加密陷阱、 SearXNG 边界)详见上面的 “Headless Linux 服务器 + 用于登录的 Windows PC” 部分。

-
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