Skip to main content
Glama
yangsheng6810

Department Web-Search MCP Gateway

Department Web-Search MCP Gateway

Ein selbst gehosteter Web-Suchdienst, den die gesamte Abteilung nutzen kann. Er verwendet eine einzelne angemeldete Browsersitzung (einen gemeinsamen Dienst-Account) wieder, sodass Intranet-/SSO-/Zustimmungs-Logins einmalig behandelt werden – jeder Client ruft einfach ein web_search-Tool auf, ohne Login pro Benutzer oder API-Schlüssel.

Jeder MCP-Client verbindet sich mit einer URL:

  • Chatbox (≥1.14)

  • OpenCode – lokal, auf einem gemeinsamen Server oder via vscode-remote

  • Claude Code (und andere Coding-Agenten, die MCP sprechen)

Es ist das T1 „zentralisierte Such-Gateway“ aus den Forschungsnotizen: eine interne Maschine + ein gemeinsames Chrome-Profil + ein HTTP-MCP-Endpunkt.


Wie es funktioniert

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 bedient sowohl MCP-Clients der 2025-Ära als auch der 2026-Ära am selben /mcp-Endpunkt, sodass die Kompatibilität des Client-Transports kein Problem darstellt.


Headless-Linux-Server + ein Windows-PC für den Login

Server haben keine GUI, aber ein Mensch kann sich an einem Windows-PC anmelden. Wählen Sie einen Modus in .env (BROWSER_MODE) – der Code ist identisch, nur die Konfiguration unterscheidet sich.

⚠️ Kopieren Sie KEIN Windows-Chrome-Profil-Verzeichnis nach Linux. Chromium verschlüsselt Cookies mit betriebssystemgebundenen Schlüsseln (DPAPI unter Windows, Keyring/„peanuts“ unter Linux), sodass ein kopiertes Profil den Login stillschweigend verliert. Verwenden Sie einen der unten stehenden betriebssystemübergreifend sicheren Modi.

Modus C – BROWSER_MODE=cdp (empfohlen): Linux-Gateway verbindet sich mit dem Windows-Browser

  • Windows-PC (bleibt eingeschaltet): Einmal mit dem gemeinsamen Account anmelden, dann Chrome mit einem lokalen Debug-Port laufen lassen:

    chrome --remote-debugging-port=9222 --remote-debugging-address=127.0.0.1 ^
           --user-data-dir=C:\dept-search-profile
  • Tragen Sie diesen Port sicher mit einem SSH-Reverse-Tunnel zum Linux-Server (auf dem Windows-PC ausführen; Win10/11 hat OpenSSH an Bord):

    ssh -R 9222:127.0.0.1:9222 linuxuser@gateway.server
  • Linux-Server: .envBROWSER_MODE=cdp, CDP_ENDPOINT=http://127.0.0.1:9222 (lokal auf dem Server, zurück zum Windows-Browser getunnelt). Dann npm start.

  • Der Login bleibt aktiv (Cookies werden aktualisiert, während der Browser verwendet wird); kein Profil-Kopieren; der nicht authentifizierte CDP-Port ist nie im Netzwerk. Nachteil: Windows-PC aus → Suchanfragen schlagen fehl, bis er wieder an ist (verwenden Sie Modus B, falls das nicht akzeptabel ist).

Modus B – BROWSER_MODE=storagestate: Snapshot, Linux autark

  • Windows-PC: npm run login (mit GUI), anmelden, Enter drücken → schreibt auth.json (betriebssystemunabhängiges JSON mit Cookies + localStorage).

  • Kopieren Sie auth.json auf den Linux-Server, setzen Sie BROWSER_MODE=storagestate, STORAGE_STATE_FILE=./auth.json, führen Sie npm start aus. Linux startet seinen eigenen Headless-Browser, der den Snapshot lädt – kein Tunnel, überlebt, wenn der Windows-PC aus ist.

  • Nachteil: ein eingefrorener Snapshot – erneut exportieren, wenn das SSO-Cookie abläuft; enthält nur Cookies + localStorage (nicht IndexedDB/Client-Zertifikate) – für die meisten SSOs ausreichend.

Modus A – BROWSER_MODE=persistent: Windows-PC führt alles aus

  • Falls ein freier Windows-PC als ständig laufender Dienst-Host dienen kann: npm run login dort (legt das Profil an), dann npm start mit BROWSER_MODE=persistent.

  • Linux-Server sind reine Clients, die auf http://<windows-pc>:8787/mcp zeigen.

  • Am einfachsten von allen – kein Tunnel, keine Snapshot-Zeremonie.

Das Onboarding der Clients ist in jedem Modus identisch: Clients zeigen auf die MCP-URL des Gateways; das Gateway spricht mit dem konfigurierten Browser-Modus.


Inbetriebnahme-Runbook – Modus C (Linux-Gateway + Windows-Browser)

Das bestätigte Setup: Ein Linux-Server betreibt das Gateway; ein ständig eingeschalteter Windows-PC betreibt einen echten Chrome (einmal angemeldet) und einen SSH-Reverse-Tunnel. Es wird kein Browser auf dem Linux-Server heruntergeladen (nur playwright-core).

Windows-PC (einmalig, dann laufen lassen) – siehe windows/README.md

  1. windows\start-browser.ps1 → dedizierter Chrome auf 127.0.0.1:9222, Profil C:\dept-search-profile. Mit dem gemeinsamen Account anmelden (SSO/2FA). Offen lassen.

  2. $env:GATEWAY_SSH = "linuxuser@gateway.server"; windows\start-tunnel.ps1 → hält ssh -R 9222:127.0.0.1:9222 gateway aufrecht, automatische Wiederverbindung.

  3. Beide als Geplante Aufgaben einrichten (Beim Start / Bei Anmeldung, ausführen, ob Benutzer angemeldet oder nicht), sodass der PC ein selbstheilendes Browser-Gerät ist.

Linux-Gateway-Server (diese Maschine)

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,...}

Weisen Sie Clients auf http://<dieser-server>:8787/mcp (siehe Client-Onboarding).

Tunnel auf Richtigkeit prüfen

Auf dem Linux-Server:

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

Leer / Verbindung abgelehnt → der Windows-Chrome oder der Reverse-Tunnel läuft noch nicht; web_search wird fehlschlagen, bis er läuft.


Einrichtung (einmalig)

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

1) Gemeinsamen Login einrichten (der Kernpunkt)

Einmalig auf einer Maschine mit Bildschirm (oder unter xvfb-run -a) ausführen:

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

Ein echtes Chrome-Fenster öffnet sich. Mit dem gemeinsamen Dienst-Account anmelden (SSO / 2FA), bestätigen, dass Sie bei der Suchmaschine / dem Portal angemeldet sind, dann das Fenster schließen. Die Sitzung wird in BROWSER_PROFILE_DIR (Standard ./.profile) gespeichert und von nun an vom Headless-Gateway wiederverwendet.

Server sind headless? Führen Sie den Schritt npm run login auf dem Windows-PC aus, wählen Sie dann Modus B (kopieren Sie auth.json nach Linux) oder Modus C (SSH-Tunnel CDP nach Linux), wie oben unter „Headless-Linux-Server + ein Windows-PC für den Login“ beschrieben. Erneuerung, wenn die SSO-Sitzung abläuft: Modus A/B → npm run login erneut ausführen (und für B auth.json erneut kopieren); Modus C → einfach im Windows-Chrome erneut anmelden.

2) Gateway starten

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

Sie sollten sehen:

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

Client-Onboarding (diese Informationen an Ihre Kollegen weitergeben)

Ersetzen Sie search.internal / 8787 durch Ihren Gateway-Host/Port. Alle verwenden die gleiche URL.

Chatbox (≥1.14)

Einstellungen → MCP → Server hinzufügenRemote / URL wählen:

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

  • (falls GATEWAY_TOKEN gesetzt ist) einen Header Authorization: Bearer <TOKEN> hinzufügen, wo der Client dies unterstützt; andernfalls mit Netzwerk-ACL schützen.

Ein-Klick-Deep-Link (auf Ihre Intranet-Seite setzen):

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

OpenCode – alle drei Varianten

Zu opencode.json (Projekt) oder ~/.config/opencode/opencode.json (global) hinzufügen:

{
  "mcp": {
    "websearch": {
      "type": "remote",
      "url": "http://search.internal:8787/mcp",
      "enabled": true
    }
  }
}
  • Lokales opencode: gleicher Ausschnitt, Host = 127.0.0.1 oder der Gateway-Host.

  • Server opencode: der Prozess läuft auf dem Server → direkt auf die interne URL des Gateways zeigen (der Server muss sie über das interne Netzwerk erreichen können).

  • vscode-remote opencode: der Prozess läuft auf dem entfernten Host → auf die interne URL des Gateways zeigen (von diesem Host aus erreichbar). Kein Tunnel nötig, da das Gateway im internen Netzwerk ist.

  • Überprüfen: 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 / andere

Wenn sie Remote-MCP unterstützen, auf die gleiche URL zeigen. Wenn sie nur stdio unterstützen, einen kleinen lokalen Shim ausführen, der das HTTP-Gateway aufruft (ein 20-zeiliger Wrapper) – hier nicht enthalten, aber trivial hinzuzufügen.


Verfügbare Tools

Tool

Argumente

Rückgabe

web_search

query (str, erforderlich), engine (bing|google|duck|custom, optional)

Liste von {title, url, snippet} als Text + JSON

read_webpage

url (str, erforderlich)

# title + Haupttext (≤20k Zeichen), Login/SSO behandelt

Der Agent in Chatbox/OpenCode/Claude Code wird web_search aufrufen, wenn er aktuelle Informationen benötigt, und read_webpage, um eine bestimmte Seite zu lesen – keine zusätzliche Verkabelung nötig.


Konfigurationsoptionen (.env)

Variable

Standard

Bedeutung

HOST

0.0.0.0

Bind-Adresse. 127.0.0.1 = nur localhost (+automatischer DNS-Rebinding-Schutz)

ALLOWED_HOSTS

Komma-getrennte Liste von Hostnamen, die Clients verwenden (ermöglicht Host-Header-Validierung). Setzen, wenn 0.0.0.0 gebunden wird

PORT

8787

Lauschport

GATEWAY_TOKEN

Falls gesetzt, Authorization: Bearer <token> erforderlich. Leer = keine Authentifizierung (nur Netzwerk-ACL)

BROWSER_MODE

cdp

persistent / storagestate / cdp – siehe Topologie-Abschnitt

CDP_ENDPOINT

http://127.0.0.1:9222

CDP-Modus: die CDP-URL des angehängten Browsers (normalerweise ein getunnelter Port)

STORAGE_STATE_FILE

./auth.json

Storagestate-Modus: auf Windows exportierter Login-Snapshot, hierher kopiert

BROWSER_PROFILE_DIR

./.profile

Persistent-Modus: Chrome-Profil, das den gemeinsamen Login enthält

HEADLESS

true

false nur zum Debuggen

MAX_CONCURRENT_PAGES

4

Parallelitätsgrenze (ein Chrome, isolierte Tabs)

PAGE_TIMEOUT_MS

20000

Hartes Timeout pro Seite

SEARCH_ENGINE

bing

bing (optimierter Extractor) / google / duck / custom

SEARCH_URL_TEMPLATE

Benutzerdefinierte URL mit {q}-Platzhalter, z.B. https://wiki.internal/search?q={q} (überschreibt Engine-URL)

RESULT_COUNT

10

Ergebnisse pro Abfrage

SEARXNG_URL

Optionaler öffentlicher Such-Fallback (benötigt ausgehenden Internetzugang), z.B. http://127.0.0.1:8080


Hinzufügen eines benutzerdefinierten Extractors für ein internes Portal

extractBing in src/tools.ts ist auf Bings DOM abgestimmt. Für ein internes Portal fügen Sie extractPortal(page, count) hinzu und wählen es über den Engine-Namen in searchWithBrowser aus. Der generische extractGeneric gibt bereits Anker-Links + umgebenden Text als brauchbaren Fallback für unbekannte DOMs zurück.


Sicherheits- & Betriebshinweise

  • Binden & freigeben: Bevorzugen Sie, das Gateway im internen Netzwerk zu belassen. Wenn Sie 0.0.0.0 binden, setzen Sie ALLOWED_HOSTS und verwenden Sie eine Firewall / Netzwerk-ACL, oder setzen Sie GATEWAY_TOKEN, oder stellen Sie es hinter einen SSO-Reverse-Proxy.

  • Gemeinsames Profil = gemeinsame Identität: Jede Suche wird dem gemeinsamen Account zugeschrieben. Für einen Abteilungs-Dienst-Account in Ordnung; prüfen Sie, ob das Ziel pro Benutzer prüft oder ein Kontingent hat.

  • Sitzungsverlängerung: Führen Sie npm run login erneut aus, wenn das SSO abläuft. Erwägen Sie einen wöchentlichen Cron-Job, der eine Erinnerung per E-Mail sendet, oder eine Health-Probe, die eine Login-Wand erkennt (read_webpage auf einer bekannten Login-erforderlichen URL gibt den Text der Login-Seite zurück).

  • Parallelität / Skalierung: Ein Chrome mit isolierten Tabs bewältigt eine kleine Abteilung. Wachsen Sie zu einem Browser-Pool (N persistente Kontexte), wenn es gesättigt ist – die withPage-Nahtstelle ist der einzige Ort, der geändert werden muss.

  • Headless Chrome unter Linux: --no-sandbox --disable-dev-shm-usage sind bereits gesetzt (containerfreundlich).


Entwicklung & Testen

  • Probes befinden sich in scripts/ und importieren aus ../dist/, also zuerst bauen: npm run build.

    • scripts/probe-search.mjs "<Abfrage>" – treibt den gemeinsamen Browser direkt an (umgeht MCP); validiert CDP-Attach + den Bing-Extractor.

    • scripts/probe-mcp.mjs <url> "<Abfrage>" – verbindet sich mit einem laufenden Gateway über Streamable HTTP (der echte Client-Pfad), listet Tools auf, ruft web_search auf. Starten Sie zuerst das Gateway: node --env-file=.env dist/server.js.

  • Dev-Modus (npm start → tsx): Unter npm 11 wird das transitive esbuild-Postinstall von tsx standardmäßig durch allow-scripts blockiert. Einmal genehmigen (npm approve-scripts) oder einfach den kompilierten Pfad überall verwenden: npm run build && node --env-file=.env dist/server.js.


Status

Hierbei handelt es sich um ein überprüfbares PoC / Skelett — abgestimmt auf die v2 MCP SDK API (@modelcontextprotocol/server 2.x, createMcpHandler / createMcpExpressApp / requireBearerAuth / toNodeHandler) und Playwrights persistent-context API. Vor dem Produktionseinsatz: exakte Abhängigkeitsversionen festlegen, Tests hinzufügen und die Authentifizierungsschicht (JWT / Introspection anstelle eines statischen Tokens) absichern, falls Sie sie über ein vertrauenswürdiges internes Netzwerk hinaus freigeben.

Der Designkontext (Mode A/B/C-Topologien, die betriebssystemübergreifende Cookie-Verschlüsselungsfalle, SearXNG-Grenzen) befindet sich im obigen Abschnitt „Headless Linux servers + a Windows PC for login“.

-
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