search-mcp
Click on "Deploy 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., "@search-mcpwhat happened in the Champions League final last night?"
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.
search-mcp
An MCP server with one tool: broad web search for current,
time-sensitive information. It returns short snippets (title, url, snippet), not full pages. It is backed by
the keyless multi-engine ddgs library, which fans out across several web search
engines with fallback (its encyclopedia engines, Wikipedia and Grokipedia, are left out: encyclopedic hits are
the wrong answer for current events).
It is deliberately small. It is meant to sit next to other, non-overlapping tools (an offline encyclopedia, a curated news feed, structured local data), so a small local model can pick the right tool from the docstrings alone. Design rationale: CLAUDE.md.
Tool
web_search(query, max_results=10, region=None)
arg | |
| sent to the engines verbatim, never rewritten |
| 1–25, default 10 |
|
|
Every result is one JSON text block with a status field. Callers branch on it, never on prose:
{"status":"ok","query":"...","backend":"auto-web","region":"wt-wt","safesearch":"moderate","max_results":10,
"attempts":1,"count":2,"results":[{"title":"...","url":"https://...","snippet":"..."}]}ok: the search ran and returned results. (results:[]is reserved for a backend that can prove a search was empty; ddgs can't, see below.)refused: input the caller can fix (blank query,max_resultsout of range, malformed region), withreasonandadvice. It is returned as a normal result, never raised.error: the search backend failed (blocked, rate-limited, timed out, network down), withkindanddetail. A backend outage is always reported as an error, never as an empty result. A failed search is retried server-side first (SEARCH_ATTEMPTS, default 2), because a second try with a different engine order often succeeds. Every result echoesattempts, so anerrorhas already been retried.kind:"empty_or_blocked"means no engine returned anything: ddgs counts an engine that blocks or rate-limits it as "no results", so it can't tell an obscure query from a blocked server. One reworded retry is reasonable; otherwise treat search as unavailable.
All resolved parameters are echoed back, so a result is reproducible. The tool declares a title and all four
MCP hints: read-only, non-destructive, idempotent, open-world.
Related MCP server: Web Search MCP Server
Run
uv sync
uv run search-mcp serve # stdio, for a local MCP client
SEARCH_MCP_TOKEN=secret uv run search-mcp serve --transport http --host 0.0.0.0 --port 8000 # streamable-http at /mcp
uv run pytest # no network: the backend is fakedenv | default | |
| unset | bearer token required on HTTP ( |
|
| seconds ddgs waits on each batch of engines |
|
| backend calls per search before reporting an error (each reshuffles the engines) |
| unset | optional outbound proxy for ddgs (read by the library itself) |
TLS note: behind a TLS-inspecting proxy,
uvmay reportUnknownIssuer. Pass--system-certs(or setUV_NATIVE_TLS=1) so it trusts the OS certificate store.
Claude Desktop / Claude Code (stdio)
{
"mcpServers": {
"search": { "command": "uv", "args": ["--directory", "/path/to/search-mcp", "run", "search-mcp", "serve"] }
}
}Docker
docker build -t search-mcp .
docker run --rm -p 8000:8000 -e SEARCH_MCP_TOKEN=... search-mcpThe server is stateless: no database, no volume. It needs outbound HTTPS to the public search engines.
Auth and exposure
Auth is deliberately simple: stdio, or streamable-HTTP with a single bearer token (SEARCH_MCP_TOKEN) on a
private network, for example behind mcpo. There is no OAuth, no users
and no audit log, by design. To publish it more widely, put a management layer in front of it: an MCP
gateway or auth proxy that handles OAuth, users and audit for all your servers at once.
A note on the backend
ddgs gets its results by scraping search-engine result pages. It needs no API key, but it is not a sanctioned
API, and engines may rate-limit or block it. That shows up here as status:"error". The backend sits behind a
single function (src/search_mcp/backend.py), so a sanctioned API (Brave, Mojeek) or a self-hosted SearXNG can
replace it by editing that one file.
AI assistance
search-mcp is developed openly with the help of Claude (Anthropic). Commits Claude helped write carry a
Co-Authored-By: Claude trailer. The code and design are open source so the work can be inspected, reused, and
given back.
License
MPL-2.0 © Daniel Núñez.
This server cannot be deployed
Maintenance
Related MCP Connectors
Executes live web/news search queries and returns clean, token-pruned results with zero ad bloat.
Search the web, images, videos, news, and local businesses with robust filters, freshness controls…
Web search, agentic search, news, page retrieval, sitemaps, and trending topics through Search1API.
Real-time web search for AI agents: ranked results, source URLs, and optional AI answers.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceFree web search and page fetching for AI agents. No account or API key required. Connect to https://search.parallel.ai/mcp over Streamable HTTP. Tools: web_search and web_fetch. Free-tier rate limits apply.21MIT
- AlicenseNot gradedqualityDmaintenanceEnables free web searching using Google search results without the need for API keys or authentication. It returns structured data including titles, URLs, and descriptions with configurable result limits.11 npm1MIT
- AlicenseAqualityCmaintenanceProvides web and news search via DuckDuckGo with support for region filtering, time ranges, and token optimization for AI assistants.229,366 npm1MIT
- AlicenseAqualityCmaintenanceEnables keyless multi-engine web, news, image, and video metasearch plus full-page markdown extraction for AI agents over MCP, with resilient fallback across DuckDuckGo, Bing, Brave, Google, and other backends.6MIT