ddg-search
ddg-search
一个拒绝单点故障的 DuckDuckGo 搜索 MCP 服务器。一个进程,多个后端,自动故障转移,诚实的错误信息。
理念
网络搜索是编码代理的承重基础设施,而它总是以乏味的方式失败:速率限制、机器人检测、你的 VPS 提供商一时抽风。大多数服务器只给你一个 HTTP 客户端,然后寄希望于运气。这个服务器会把每个查询路由到多个后端——本机上的本地搜索器,加上你碰巧运行的任意数量的远程 duckduckgo-mcp-server 实例——并持续尝试,直到有响应或预算耗尽。
失败的后端会被超时隔离。表现良好的后端会获得更多流量。你得到的结果是一个紧凑的块,附有一行说明,注明是哪个后端提供的。
Related MCP server: DuckDuckGo Search MCP Server
安装
需要 Python 3.10+ 和 uv。
git clone <this repo> ~/.local/share/mcp/ddg-search # or anywhere you like
cd ~/.local/share/mcp/ddg-search
uv sync这就是全部仪式。uv sync 会创建 .venv、锁定依赖,并以可编辑模式安装包,因此对 src/ 的修改会在重启后生效。
接入你的代理
任何支持 stdio 的 MCP 客户端都可以。对于 mcp.json 风格的配置:
{
"mcpServers": {
"ddg-search": {
"type": "stdio",
"command": "/path/to/ddg-search/.venv/bin/python",
"args": ["-m", "ddg_search.server"],
"env": {
"DDG_SAFE_SEARCH": "OFF",
"DDG_SEARCH_BACKEND": "auto"
},
"timeout": 60000
}
}
}DDG_SAFE_SEARCH 仅用于内容过滤——它对机器人检测毫无作用,而且默认关闭,因为做研究的代理想要的是召回率,而不是一个监护人。
工具
search
参数 | 类型 | 默认值 | 说明 |
| string | required | 具体名词优于模糊的一词感觉 |
| int | 10 | 上游无论如何都限制在 10–11 左右 |
| string |
| DuckDuckGo 地区代码 |
|
|
| 手动模式跳过健康排序 |
| string |
| 一个后端名称/别名/IP(手动模式) |
| list |
| 有序回退链(手动模式) |
结果有意以紧凑形式返回:
via relay-b
3 results:
1. Some Page Title
https://example.com/page
The snippet text, labels stripped, no blank lines eating your tokens.
2. ...每个响应都会说明是哪个后端提供的。失败的尝试会列在 Attempts: 下,并带有一个标签,告诉你它是在哪里出错的:
标签 | 含义 |
| DuckDuckGo 返回零匹配——真正的无结果或机器人导致的空结果,从这里无法区分 |
| 本机的客户端失败。不要怪远程主机 |
| 远程后端响应异常 |
| 等待时 25 秒预算耗尽 |
当事情出错时,你会得到一个日志路径
路由器会区分“互联网只是在做互联网该做的事”和“这个工具真的坏了”。超时和空结果集只会得到它们的 [tag]。但当一次尝试以意味着我们这边出了问题的方式失败时——本地传输错误、远程后端响应异常——响应会以如下内容结尾:
log: /path/to/ddg-search/logs/20260822T090206-remote-tool-error.json该文件包含重放和诊断所需的一切:确切的查询和参数、每次尝试及其失败详情,以及当时每个后端状态的快照。如果你愿意,可以把 DDG_SEARCH_LOGS_DIR 指向其他位置;超时或空结果永远不会写入日志。
status
后端表:在线标志、本分钟观察到的尝试次数、最后状态、冷却到期时间。传入 probe: true 可以实际 ping 远程后端,而不是信任缓存状态。
配置
环境变量,全部可选:
变量 | 默认值 | 用途 |
|
|
|
|
| 本地传输: |
|
| 每次查询在所有后端上的总预算 |
|
| 每个后端的超时惩罚 |
|
| 每个后端的错误惩罚 |
|
|
|
|
| 路由器状态目录 |
后端位于 src/ddg_search/config.py。默认舰队是 local(本机)加上两个远程中继;编辑该元组以匹配你自己的基础设施。
值得了解的行为
故障转移优先选择健康且近期尝试次数最少的后端,这样流量会分散开来,而不是猛击一个可怜的盒子。
冷却按后端分别计时且有时间上限:超时让后端休息 90 秒,软失败休息 30 秒。一次成功会立即清零。
状态在重启后仍会保留在
state/router-state.json中。如果你想要失忆,就删除它;服务器会在下次启动时重新创建。
有一个怪癖值得单独说一段。DuckDuckGo 会向它不信任的客户端提供空页面,因此“无结果”可能意味着真的没有匹配,也可能是悄无声息的机器人标记——路由器无法区分这两者,它也不会假装能区分。它把空结果视为失败,并尝试下一个后端;如果每个后端都返回空结果,你会看到一个横幅,明确说明这有多模棱两可。
最后一件事:30 次/分钟的请求上限由每个 duckduckgo-mcp-server 实例强制执行,而不是在这里。路由器会在后端之间分散负载,但它不会谎称舰队并不具备的容量。
运行你自己的中继
任何能运行标准服务器的机器都可以作为后端:
pip install 'duckduckgo-mcp-server[browser]'
python -m duckduckgo_mcp_server.main --transport streamable-http --host 0.0.0.0 --port 18082将 BackendConfig(url="http://that-host/ddg-mcp") 指向它。realip/ 目录包含一个启动器,systemd 单元用它来在住宅 IP 上通过 mullvad-exclude 运行这样一个出口——如果你的数据中心出口比家庭连接遭受更糟糕的验证码待遇,这会很有用。
开发
uv sync # install everything including dev tools
uv run pytest # 26 tests, no network needed except one optional live check
uv run ruff check src tests # lint
uv run ruff format src tests # format
uv run pyrefly check # static types通过完整路由器进行快速手动冒烟测试:
uv run python -c "import asyncio; from ddg_search.router import SearchRouter; \
print(asyncio.run(SearchRouter().search('crawl4ai', 3, '', 'auto', None, None, None)))"另请参阅
fast-webfetch-mcp — 另一半:通过本地 Crawl4AI 浏览器打开这些搜索找到的 URL
Model Context Protocol — “MCP”的含义
duckduckgo-mcp-server — 底层实际执行抓取的搜索库
许可证
MIT。
Available Tools
2 toolssearchA
Search DuckDuckGo via ddg-search (local + remote backends). Discovery only — titles/URLs/snippets, not page proof. Then open promising URLs with fast-webfetch. Routing: auto = healthy low-use backends; manual = target/targets. On failure, read Attempts tags: [empty] = DDG no matches; [local]/[local-transport] = this machine (do not assume remote VPS missing packages); [remote-rpc]/[remote-tool-error] = remote answered badly; [timeout] = real wait timeout.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | DuckDuckGo query. Prefer exact nouns, error strings, version, site/domain, or API names. Avoid vague one-word searches. | |
| region | No | DuckDuckGo region code. Empty = default/global. | |
| target | No | Manual mode: single backend name, alias, or IP. Empty = all backends. | |
| targets | No | Manual mode: ordered backend names/aliases/IPs. Combined with target; duplicates ignored. | |
| route_mode | No | 'auto' for normal failover; 'manual' only when targeting specific backend(s). | auto |
| max_results | No | Max results. Use 5-10 normally; raise when the first page looks noisy. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the behavioral burden. It discloses the local+remote backend split, that it's read-only discovery, and decodes error tags to distinguish local vs remote failures. It does not mention rate limits, caching, or concurrency behavior, but for a search tool it covers the most critical operational behaviors.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single dense paragraph, but every sentence adds value: purpose, follow-up action, routing modes, and failure decoding. It is slightly long but not verbose; front-loads the core purpose before details. Could be improved with bullet points but is acceptable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 6 parameters (1 required), an output schema exists (not shown), and helper sibling 'status', the description covers all necessary operational context: what it returns (titles/URLs/snippets), when to use each route mode, how to interpret failures, and the follow-up tool (fast-webfetch). Nothing essential is missing—an agent could call this tool correctly without further clarification.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% so baseline is 3. The description does not add meaning beyond the schema; it repeats the routing guidance already in route_mode and the query tips already in the query parameter. The extra notes about backend combinations and error tags are behavioral rather than parameter-specific, so no increment.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Search DuckDuckGo via ddg-search'. It clearly delimits scope with 'Discovery only — titles/URLs/snippets, not page proof', distinguishing it from follow-up fetch tools and giving an agent an unambiguous sense of what it returns and what it does not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit routing rules: 'auto = healthy low-use backends; manual = target/targets' and tells when to use manual mode. It also instructs on failure interpretation: 'read Attempts tags' with specific meanings for [empty], [local]/[local-transport], [remote-rpc]/[remote-tool-error], and [timeout]. This is actionable when-to-use and how-to-handle guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
statusA
Show ddg-search backend router status (health, cooldowns, last errors). Optional probe pings backends. Use after search failures; if last_error is local/transport, fix the workstation ddg-search process before remote packages.
| Name | Required | Description | Default |
|---|---|---|---|
| probe | No | If true, probe backends before reporting. | |
| target | No | Optional single backend name/alias/IP. | |
| targets | No | Optional ordered backend names/aliases/IPs. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries full burden. It discloses that probe pings backends, but doesn't detail what the probe does when failures occur or the exact output structure. It does mention cooldowns and last errors as return content, which is useful. There's no contradiction with annotations since none exist.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences: purpose, key optional behavior, and usage context. Front-loads the main purpose and then adds actionable guidance. No wasted words—every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given an output schema exists (not described in detail but signaled), the return value structure need not be explained. Tool complexity is moderate (3 optional params, one boolean). The description explains when to use it and what to check for. It could mention what happens if probe=true and backends fail, but since it focuses on diagnostics, this is adequate. Sibling 'search' is the only other tool, and status is clearly distinct.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with 'probe', 'target', and 'targets' all described in the schema. The description mentions 'Optional probe pings backends' which aligns with the probe field but doesn't add much beyond the schema. It also implies target/targets are optional, consistent with schema defaults. Baseline 3 applies since schema already documents parameters fully.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clear verb ('Show') and resource ('ddg-search backend router status'). Distinguishes itself from sibling 'search' by explicitly targeting the router health, cooldowns, and errors—a diagnostic role that search does not play.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States when to use it ('after search failures') and gives a conditional directive ('if last_error is local/transport, fix the workstation...'). Doesn't explicitly rule out other scenarios, but provides useful decision context. Sibling 'search' is clearly the alternative primary action tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.2.0- First observed
search - First observed
status
TDQS
Scored across 2 tools
Search and status have completely distinct purposes: one performs queries, the other reports backend health. There is no overlap or ambiguity between them.
Both names are short, lowercase, and clear. Search is a verb while status is a noun, which is a minor stylistic deviation but not confusing.
With only two tools, the set feels minimal. However, the server's scope is narrow and the two tools cover its core responsibilities, so the count is reasonable if sparse.
The server covers search and backend status monitoring, and explicitly delegates page fetching to another tool. Minor gaps exist (e.g., no configuration or backend management), but the stated surface is fully supported.
Maintenance
Related MCP Connectors
Search the agentic web. 4,100+ sites, 11 tools incl. check_url + verify_mcp for probe-before-use.
Serper MCP — wraps the Serper Google Search API (serper.dev)
Web MCP: scrape/crawl sites, web search, brand assets, app stores, YouTube, Reddit, Hacker News.
Scrape, crawl and search the web for AI agents via MCP.
Related MCP Servers
- AlicenseAqualityFmaintenanceProvides web search functionality via DuckDuckGo for Claude Code and MCP-compatible clients, featuring advanced content exploration, navigation across search results, and detailed webpage analysis.317MIT
- FlicenseNot gradedqualityCmaintenanceBrings DuckDuckGo search (web, news, images, videos) to any MCP-compatible AI client without requiring an API key.-
- AlicenseAqualityBmaintenanceMCP server for DuckDuckGo web search, enabling AI agents to perform real-time text, news, and image searches without an API key.3MIT
- AlicenseNot gradedqualityDmaintenanceProvides keyless, privacy-focused web search through DuckDuckGo and SearxNG via MCP, with token-efficient tool discovery and caching.MIT