Department Web-Search MCP Gateway
Department Web-Search MCP Gateway
Un servicio de búsqueda web autoalojado que todo el departamento puede compartir. Reutiliza una única sesión de navegador iniciada (una cuenta de servicio compartida), por lo que los inicios de sesión en intranet/SSO/muros de consentimiento se manejan una vez — cada cliente simplemente llama a una herramienta web_search, sin necesidad de inicio de sesión por usuario ni clave API.
Cualquier cliente MCP se conecta a una URL:
Chatbox (≥1.14)
OpenCode — local, en un servidor compartido, o mediante vscode-remote
Claude Code (y otros agentes de codificación que hablen MCP)
Es la "puerta de enlace de búsqueda centralizada" T1 de las notas de investigación: una máquina interna + un perfil compartido de Chrome + un endpoint MCP HTTP.
Cómo funciona
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 nothingcreateMcpHandler sirve tanto a clientes MCP de la era 2025 como de la era 2026 en el mismo endpoint /mcp, por lo que la compatibilidad del transporte del cliente no es una preocupación.
Servidores Linux sin pantalla + un PC con Windows para iniciar sesión
Los servidores no tienen interfaz gráfica, pero un humano puede iniciar sesión en un PC con Windows. Elige un modo en .env (BROWSER_MODE) — el código es idéntico, solo cambia la configuración.
⚠️ NO copies un directorio de perfil de Chrome de Windows a Linux. Chromium cifra las cookies con claves vinculadas al sistema operativo (DPAPI en Windows, keyring/"peanuts" en Linux), por lo que un perfil copiado pierde la sesión iniciada silenciosamente. Usa uno de los modos seguros entre sistemas operativos a continuación.
Modo C — BROWSER_MODE=cdp (recomendado): La puerta de enlace Linux se conecta al navegador Windows
PC con Windows (permanece encendido): inicia sesión una vez con la cuenta compartida, luego mantén Chrome ejecutándose con un puerto de depuración solo local:
chrome --remote-debugging-port=9222 --remote-debugging-address=127.0.0.1 ^ --user-data-dir=C:\dept-search-profileLleva ese puerto de forma segura al servidor Linux con un túnel inverso SSH (ejecutar en el PC con Windows; Win10/11 incluye OpenSSH):
ssh -R 9222:127.0.0.1:9222 linuxuser@gateway.serverServidor Linux:
.env→BROWSER_MODE=cdp,CDP_ENDPOINT=http://127.0.0.1:9222(local en el servidor, tunelizado de vuelta al navegador Windows). Luegonpm start.La sesión iniciada permanece activa (las cookies se actualizan mientras se usa el navegador); sin copia de perfil; el puerto CDP no autenticado nunca está en la red. Inconveniente: PC con Windows apagado → las búsquedas fallan hasta que se enciende (usa el Modo B si eso es inaceptable).
Modo B — BROWSER_MODE=storagestate: instantánea, Linux autosuficiente
PC con Windows:
npm run login(con pantalla), inicia sesión, presiona Enter → escribeauth.json(JSON de cookies + localStorage independiente del sistema operativo).Copia
auth.jsonal servidor Linux, configuraBROWSER_MODE=storagestate,STORAGE_STATE_FILE=./auth.json, ejecutanpm start. Linux ejecuta su propio navegador sin pantalla cargando la instantánea — sin túnel, sobrevive al apagado del PC con Windows.Compensación: una instantánea congelada — reexportar cuando caduque la cookie SSO; solo lleva cookies + localStorage (no IndexedDB/certificados de cliente) — suficiente para la mayoría de SSO.
Modo A — BROWSER_MODE=persistent: El PC con Windows lo ejecuta todo
Si un PC con Windows de repuesto puede ser el anfitrión del servicio siempre encendido: ejecuta
npm run loginallí (siembra el perfil), luegonpm startconBROWSER_MODE=persistent.Los servidores Linux son clientes puros que apuntan a
http://<windows-pc>:8787/mcp.El más simple de todos — sin túnel, sin ceremonia de instantánea.
La incorporación del cliente es idéntica en todos los modos: los clientes apuntan a la URL MCP de la puerta de enlace; la puerta de enlace se comunica con el modo de navegador que esté configurado.
Manual de puesta en marcha — Modo C (puerta de enlace Linux + navegador Windows)
La configuración confirmada: un servidor Linux ejecuta la puerta de enlace; un PC con Windows siempre encendido ejecuta un Chrome real (iniciado sesión una vez) y un túnel inverso SSH. No se descarga ningún navegador en el servidor Linux (solo playwright-core).
PC con Windows (una vez, luego dejar ejecutándose) — consulta windows/README.md
windows\start-browser.ps1→ Chrome dedicado en127.0.0.1:9222, perfilC:\dept-search-profile. Inicia sesión con la cuenta compartida (SSO/2FA). Mantenlo abierto.$env:GATEWAY_SSH = "linuxuser@gateway.server"; windows\start-tunnel.ps1→ mantienessh -R 9222:127.0.0.1:9222 gateway, reconexión automática.Convierte ambos en Tareas programadas (Al iniciar / Al iniciar sesión, ejecutar esté o no el usuario conectado) para que el PC sea un dispositivo de navegador auto-reparable.
Servidor de puerta de enlace Linux (esta máquina)
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,...}Apunta los clientes a http://<este-servidor>:8787/mcp (consulta Incorporación de clientes).
Verificar el túnel
En el servidor Linux:
curl -s http://127.0.0.1:9222/json/version # Chrome's JSON → tunnel + Chrome are upVacío / conexión rechazada → el Chrome de Windows o el túnel inverso aún no se están ejecutando; web_search fallará hasta que lo estén.
Configuración (una vez)
cd dept-web-search-gateway
npm install # also runs `playwright install chromium`
cp .env.example .env # then edit .env (see knobs below)1) Sembrar el inicio de sesión compartido (la clave)
Ejecutar una vez en una máquina con pantalla (o bajo xvfb-run -a):
npm run login
# or, for an internal portal:
LOGIN_START_URL=https://wiki.internal npm run loginSe abre una ventana real de Chrome. Inicia sesión con la cuenta de servicio compartida (SSO / 2FA), confirma que has iniciado sesión en el motor de búsqueda / portal, luego cierra la ventana. La sesión se persiste en BROWSER_PROFILE_DIR (por defecto ./.profile) y la puerta de enlace sin pantalla la reutilizará a partir de ahora.
¿Los servidores no tienen pantalla? Haz el paso
npm run loginen el PC con Windows, luego elige el Modo B (copiaauth.jsona Linux) o el Modo C (túnel SSH CDP a Linux) como se describe en "Servidores Linux sin pantalla + un PC con Windows para iniciar sesión" arriba. Renovación cuando caduque la sesión SSO: Modo A/B → volver a ejecutarnpm run login(y recopiarauth.jsonpara B); Modo C → simplemente volver a iniciar sesión en el Chrome de Windows.
2) Ejecutar la puerta de enlace
npm start # dev (tsx)
# or production:
npm run build && npm run start:prodDeberías ver:
[server] MCP gateway on http://0.0.0.0:8787/mcp (engine=bing)
[server] profile=./.profileIncorporación de clientes (entregar esto a tus colegas)
Reemplaza search.internal / 8787 con el host/puerto de tu puerta de enlace. Todos usan la misma URL.
Chatbox (≥1.14)
Configuración → MCP → Agregar servidor → elige Remoto / URL:
URL:
http://search.internal:8787/mcp(si
GATEWAY_TOKENestá configurado) añade una cabeceraAuthorization: Bearer <TOKEN>donde el cliente lo soporte; de lo contrario, protege con ACL de red.
Enlace profundo de un solo clic (ponlo en tu página de intranet):
chatbox://mcp/install?server=<base64 of {"name":"websearch","url":"http://search.internal:8787/mcp"}>OpenCode — las tres variantes
Añadir a opencode.json (proyecto) o ~/.config/opencode/opencode.json (global):
{
"mcp": {
"websearch": {
"type": "remote",
"url": "http://search.internal:8787/mcp",
"enabled": true
}
}
}opencode local: el mismo fragmento, host =
127.0.0.1o el host de la puerta de enlace.opencode de servidor: el proceso se ejecuta en el servidor → apunta directamente a la URL interna de la puerta de enlace (el servidor debe poder alcanzarla a través de la red interna).
opencode vscode-remote: el proceso se ejecuta en el host remoto → apunta a la URL interna de la puerta de enlace (accesible desde ese host). No se necesita túnel porque la puerta de enlace está en la red interna.
Verificar:
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/mcpCline / Cursor / otros
Si soportan MCP remoto, apunta a la misma URL. Si solo hacen stdio, ejecuta un pequeño shim local que llama a la puerta de enlace HTTP (un envoltorio de 20 líneas) — no incluido aquí, pero trivial de añadir.
Herramientas expuestas
Herramienta | Argumentos | Retorna |
|
| lista de |
|
|
|
El agente en Chatbox/OpenCode/Claude Code llamará a web_search cuando necesite información actualizada, y a read_webpage para leer una página específica — sin cableado adicional.
Opciones de configuración (.env)
Variable | Valor por defecto | Significado |
|
| dirección de enlace. |
| — | lista separada por comas de nombres de host que usan los clientes (habilita validación de cabecera Host). Configurar al enlazar 0.0.0.0 |
|
| puerto de escucha |
| — | si se configura, requiere |
|
|
|
|
| modo cdp: la URL CDP del navegador adjunto (generalmente un puerto tunelizado) |
|
| modo storagestate: instantánea de inicio de sesión exportada en Windows, copiada aquí |
|
| modo persistent: perfil de Chrome que contiene el inicio de sesión compartido |
|
|
|
|
| límite de concurrencia (un Chrome, pestañas aisladas) |
|
| tiempo de espera máximo por página |
|
|
|
| — | URL personalizada con marcador |
|
| resultados por consulta |
| — | alternativa opcional de búsqueda pública (necesita internet de salida), ej. |
Añadir un extractor personalizado para portal interno
extractBing en src/tools.ts está optimizado para el DOM de Bing. Para un portal interno, añade extractPortal(page, count) y selecciónalo por el nombre del motor en searchWithBrowser. El genérico extractGeneric ya retorna enlaces de anclaje + texto cercano como alternativa aceptable para DOMs desconocidos.
Notas de seguridad y operaciones
Enlazar y exponer: prefiere mantener la puerta de enlace en la red interna. Si enlazas
0.0.0.0, configuraALLOWED_HOSTSy usa un cortafuegos / ACL de red, o configuraGATEWAY_TOKEN, o ponlo detrás de un proxy inverso SSO.Perfil compartido = identidad compartida: cada búsqueda se atribuye a la cuenta compartida. Está bien para una cuenta de servicio del departamento; revisa si el destino audita por usuario o tiene cuota.
Renovación de sesión: vuelve a ejecutar
npm run logincuando caduque el SSO. Considera un cron semanal que envíe un recordatorio por correo, o un sondeo de salud que detecte un muro de inicio de sesión (read_webpageen una URL que requiera inicio de sesión conocido devuelve el texto de la página de inicio de sesión).Concurrencia / escala: un Chrome con pestañas aisladas maneja un departamento pequeño. Crece a un grupo de navegadores (N contextos persistentes) si se satura — la costura
withPagees el único lugar para cambiar.Chrome sin pantalla en Linux:
--no-sandbox --disable-dev-shm-usageya están configurados (amigable con contenedores).
Desarrollo y pruebas
Sondas están en
scripts/e importan desde../dist/, así que primero compila:npm run build.scripts/probe-search.mjs "<consulta>"— maneja el navegador compartido directamente (omite MCP); valida el adjunto CDP + el extractor de Bing.scripts/probe-mcp.mjs <url> "<consulta>"— se conecta a una puerta de enlace en ejecución a través de Streamable HTTP (la ruta real del cliente), lista herramientas, llama aweb_search. Inicia la puerta de enlace primero:node --env-file=.env dist/server.js.
Modo de desarrollo (
npm start→ tsx): en npm 11, elesbuildtransitivo detsxpostinstall está bloqueado porallow-scriptspor defecto. Apruebalo una vez (npm approve-scripts) o simplemente usa la ruta compilada en todos lados:npm run build && node --env-file=.env dist/server.js.
Estado
Este es un PoC / esqueleto revisable — verificado contra la API v2 del SDK de MCP
(@modelcontextprotocol/server 2.x, createMcpHandler / createMcpExpressApp
/ requireBearerAuth / toNodeHandler) y la API de contexto persistente de Playwright.
Antes de producción: fijar versiones exactas de dependencias, agregar pruebas y endurecer la
capa de autenticación (JWT / introspección en lugar de un token estático) si se expone
más allá de una red interna de confianza.
El contexto de diseño (topologías Modo A/B/C, el problema de cifrado de cookies entre sistemas operativos, los límites de SearXNG) se encuentra en la sección “Headless Linux servers + a Windows PC for login” anterior.
This server cannot be installed
Maintenance
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.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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