Findle
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Findlesearch web for 'MCP servers' and fetch top result as markdown"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Findle
Local Web Search + Fetch-as-Markdown over MCP
A fully local stack that gives LM Studio, Claude Code, GSD Pi and OpenCode two capabilities through MCP (Model Context Protocol), behind a single endpoint:
Web search — via a self-hosted SearXNG metasearch engine (no API key, queries stay local), wrapped by mcp-searxng.
Fetch a page as clean markdown — two engines:
fetch(lightweight, static HTML) — zcaceres/fetch-mcp, fast, no browser.fetch-js(JS-rendering) — Crawl4AI, Playwright/Chromium, for SPAs.
All three capability servers are aggregated by mcphub
into one merged MCP endpoint. Everything runs in Docker, bound to 127.0.0.1. Clients
register one URL and see all tools.
Architecture
┌────────────────────── Docker (localhost) ──────────────────────┐
│ │
MCP clients │ ┌──────────┐ │
┌───────────────┐ │ │ │ search ┌─────────────┐ ┌──────────┐ │
│ LM Studio │ │ │ │───────────▶│ mcp-searxng │────▶│ SearXNG │ │
│ Claude Code │ │ │ mcphub │ └─────────────┘ │ (local) │ │
│ GSD Pi │ HTTP/mcp ──┼──▶│ :8800 │ fetch ┌─────────────┐ └──────────┘ │
│ OpenCode │ │ │ /mcp │───────────▶│ fetch │ (static HTML) │
└───────────────┘ │ │ │ └─────────────┘ │
│ │ │ fetch-js ┌─────────────┐ │
│ │ │───────────▶│ crawl4ai │ (Chromium / JS) │
│ └──────────┘ └─────────────┘ │
│ │
└────────────────────────────────────────────────────────────────┘Related MCP server: searxng-mcp
Endpoint
What | URL |
MCP (all tools) |
|
mcphub admin dashboard |
|
Authentication
The /mcp endpoint requires a bearer token (enableBearerAuth: true in
mcphub/mcp_settings.json). Every client must send:
Authorization: Bearer <token>The token lives in mcphub/mcp_settings.json under bearerKeys[].token. That file is
gitignored because mcphub also writes other secrets into it at runtime (OAuth client
secrets, the admin password hash). A sanitized mcphub/mcp_settings.example.json is
committed as the template — copy it and fill in your own values on first run:
cp mcphub/mcp_settings.example.json mcphub/mcp_settings.json
# then edit mcp_settings.json: set a random bearerKeys[].token, a UUID id,
# and the bcrypt hash of your admin passwordRotate the token by editing mcphub/mcp_settings.json (or via the admin dashboard's
Keys section) and restarting mcphub (docker compose restart mcphub). The admin
dashboard at http://localhost:8800/ uses the separate MCPHUB_ADMIN_PASSWORD from
.env, not this token.
Bring it up
cp .env.example .env # then edit .env: set SEARXNG_SECRET, MCPHUB_ADMIN_PASSWORD,
# and CRAWL4AI_API_TOKEN
cp mcphub/mcp_settings.example.json mcphub/mcp_settings.json
# then edit it: set bearerKeys[].token, the admin bcrypt hash,
# and the fetch-js Authorization header = your CRAWL4AI_API_TOKEN
docker compose up -d --build # first run builds the fetch image + pulls Chromium (~1.5GB)
docker compose ps # all five services should be runningVerify
# 1. SearXNG JSON API (proves the json format is enabled)
docker compose exec searxng wget -qO- "http://localhost:8080/search?q=test&format=json" | head
# 2. Open the mcphub dashboard at http://localhost:8800/ and confirm all three
# upstream servers (web-search, fetch, fetch-js) show as connected.
# 3. Inspect the merged endpoint's tools
npx @modelcontextprotocol/inspector
# then connect to http://localhost:8800/mcp and confirm tools from all three appear.End-to-end: in any client below, ask "search the web for X and fetch the top result as
markdown." Use the fetch tool for docs/blogs/news and fetch-js for JS-heavy SPAs.
Tests
tests/ holds a pytest suite (Python 3.10+, needs pytest and mcp):
pip install pytest mcp # or: uv run --with pytest --with mcp python -m pytest tests/ -v
pytest tests/ -vtest_fetch_container.py— exercises every tool of thefetchcontainer in isolation (fetch_html/markdown/txt/json/readable/youtube_transcript). Self-contained: it starts the builtfindle-fetchimage on a throwaway port and tears it down. SetFETCH_MCP_URLto test an already-running endpoint instead.test_stack.py— integration test through the mcphub gateway with bearer auth: checks the endpoint rejects unauthenticated calls, that all 17 merged tools are advertised, and that web search, static fetch, and JS-rendered fetch each return content. Requires the stack to be up; reads the bearer token frommcphub/mcp_settings.json(override withMCPHUB_BEARER_TOKEN/STACK_MCP_URL).
The YouTube-transcript test is marked xfail (non-strict) — YouTube often blocks datacenter
IPs or a video lacks captions, so it passes whether or not the transcript comes back.
Client configuration — one URL + bearer token each
Replace <token> below with the value of bearerKeys[].token from
mcphub/mcp_settings.json.
LM Studio — %USERPROFILE%\.lmstudio\mcp.json
{
"mcpServers": {
"findle": {
"url": "http://localhost:8800/mcp",
"headers": { "Authorization": "Bearer <token>" }
}
}
}Claude Code
claude mcp add --transport http findle http://localhost:8800/mcp \
--header "Authorization: Bearer <token>"OpenCode — opencode.json
{
"mcp": {
"findle": {
"type": "remote",
"url": "http://localhost:8800/mcp",
"headers": { "Authorization": "Bearer <token>" }
}
}
}GSD Pi — project .mcp.json (or local-only .gsd/mcp.json)
{
"mcpServers": {
"findle": {
"url": "http://localhost:8800/mcp",
"headers": { "Authorization": "Bearer <token>" }
}
}
}Security notes
Network exposure. Only mcphub's port is published, on
127.0.0.1only. The three capability servers and SearXNG are reachable only on the internal Docker network. Do not switch mcphub to0.0.0.0without addingOrigin-header validation (DNS-rebinding protection).Non-root. Every container runs as an unprivileged user (searxng→
977, mcp-searxng & fetch→1000, crawl4ai→999, mcphub→nobody) withno-new-privilegesset, so a container escape doesn't start as root. Consider daemon-leveluserns-remapto also unmap container-root from host-root.Gateway auth. The
/mcpendpoint requires a bearer token (see Authentication). OAuth dynamic registration is disabled and client secrets +stateare required, so the endpoint can't be used to self-register clients.crawl4ai (
fetch-js) is token-gated. crawl4ai binds loopback-only unless a credential is set;CRAWL4AI_API_TOKENboth exposes it on the docker network and makes it require that token on every request. mcphub sends it via thefetch-jsheadersentry inmcp_settings.json— the two values must match. crawl4ai drives a real Chromium against arbitrary pages, so this is the highest-risk component; the non-root + token gating limit the blast radius.mcp-searxng (
web-search) binds loopback by default (MCP_HTTP_HOST=0.0.0.0exposes it on the docker net). It's unauthenticated like the staticfetchserver — fine while internal-only. To require a token, setMCP_HTTP_HARDEN=true+MCP_HTTP_AUTH_TOKEN+MCP_HTTP_ALLOWED_ORIGINSand add a matching header to itsmcp_settings.jsonentry.SSRF. The fetch engines can be aimed at internal URLs. zcaceres/fetch-mcp and Crawl4AI block private/loopback targets — keep that on. (The official Python
mcp-server-fetchwas deliberately not used: no SSRF protection, CVE-2025-65513.)Secrets.
.envandmcphub/mcp_settings.jsonhold all secrets and are gitignored; commit the*.exampletemplates instead. Set a realMCPHUB_ADMIN_PASSWORDso the dashboard isn't left open.
Notes / things to adjust
mcphub also exposes per-server paths (
/mcp/web-search, etc.) and an AI "smart routing" endpoint (/mcp/$smart, needs an embedding model). We use the merged/mcpfor all tools.The
fetchimage builds zcaceres/fetch-mcp from source and assumes the build output isdist/index.js. If upstream changes the output path, updatefetch/Dockerfile.SearXNG's request limiter is disabled (single-user local). For heavier use, add a
valkeysidecar and enable the limiter per the SearXNG docs.Prefer no gateway? An earlier three-endpoint layout (each server published directly) also works; mcphub just collapses it to one URL per client. See git history / the plan file.
License
This project's own files (compose, Dockerfile, configs, tests, docs) are licensed under the MIT License — see LICENSE.
Third-party components
This repo orchestrates third-party services pulled at runtime/build; it does not bundle or redistribute their source. Each keeps its own license:
Component | License |
AGPL-3.0-or-later | |
MIT | |
Apache-2.0 | |
MIT | |
MIT | |
Bun (build-time only) | MIT |
Apache-2.0 | |
Node.js base image | MIT |
SearXNG is AGPL-3.0. It runs as the stock upstream image, unmodified — only a
settings.yml is supplied via volume mount, which is not a derivative of SearXNG's source. This
repo therefore does not inherit AGPL. If you offer this stack as a network service to others,
AGPL entitles those users to SearXNG's corresponding source, which is the public upstream image.
Forking and modifying SearXNG's own code would bring AGPL obligations onto that modified code.
The Python test dependencies (see requirements.txt) are all permissive — MIT, BSD, Apache-2.0,
MPL-2.0 (certifi), and PSF.
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 Servers
- Alicense-qualityDmaintenanceAn MCP server that wraps a local SearXNG instance to provide private, customizable web search capabilities. It enables AI assistants to perform queries with support for specific parameters like results limits, language, and time ranges.223MIT
- AlicenseAqualityAmaintenanceMCP server for private web search via self-hosted SearXNG with local reranking, full-page content fetching via Firecrawl, and optional Ollama-powered query expansion and summaries.76916MIT
- Alicense-qualityAmaintenanceA minimal MCP server that exposes a private SearXNG instance as a search tool over streamable-HTTP, enabling web search from the llama.cpp WebUI or any compatible MCP client.1MIT
- Flicense-qualityBmaintenanceA self-hosted MCP server providing private web search, web page fetching, and current date/time tools, powered by a bundled SearXNG instance for API-key-free local search.2
Related MCP Connectors
Serper MCP — wraps the Serper Google Search API (serper.dev)
An MCP server that gives your AI access to the source code and docs of all public github repos
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
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/jgraber/findle'
If you have feedback or need assistance with the MCP directory API, please join our Discord server