DuckDuckGo Search MCP Server

July 27, 2026 · View on GitHub

PyPI version PyPI downloads Python versions

A Model Context Protocol (MCP) server that provides web search capabilities through DuckDuckGo, with additional features for content fetching and parsing.

Quick Start

uvx duckduckgo-mcp-server

Features

  • Web Search: Search DuckDuckGo with advanced rate limiting and result formatting
  • Content Fetching: Retrieve and parse webpage content with intelligent text extraction
  • Rate Limiting: Built-in protection against rate limits for both search and content fetching
  • Error Handling: Comprehensive error handling and logging
  • LLM-Friendly Output: Results formatted specifically for large language model consumption

Installation

Install from PyPI using uv:

uv pip install duckduckgo-mcp-server

Usage

Running with Claude Desktop

  1. Download Claude Desktop
  2. Create or edit your Claude Desktop configuration:
    • On macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
    • On Windows: %APPDATA%\Claude\claude_desktop_config.json

Add the following configuration:

Basic Configuration (No SafeSearch, No Default Region):

{
    "mcpServers": {
        "ddg-search": {
            "command": "uvx",
            "args": ["duckduckgo-mcp-server"]
        }
    }
}

With SafeSearch and Region Configuration:

{
    "mcpServers": {
        "ddg-search": {
            "command": "uvx",
            "args": ["duckduckgo-mcp-server"],
            "env": {
                "DDG_SAFE_SEARCH": "STRICT",
                "DDG_REGION": "cn-zh"
            }
        }
    }
}

Configuration Options:

  • DDG_SAFE_SEARCH: SafeSearch filtering level (optional)
    • STRICT: Maximum content filtering (kp=1)
    • MODERATE: Balanced filtering (kp=-1, default if not specified)
    • OFF: No content filtering (kp=-2)
  • DDG_REGION: Default region/language code (optional, examples below)
    • us-en: United States (English)
    • cn-zh: China (Chinese)
    • jp-ja: Japan (Japanese)
    • wt-wt: No specific region
    • Leave empty for DuckDuckGo's default behavior
  • DDG_CA_CERTS: Path to a PEM CA bundle used to verify TLS certificates on outbound requests (optional). Needed behind TLS-intercepting proxies — see Running behind a TLS-intercepting proxy.
  1. Restart Claude Desktop

Running with Claude Code

  1. Download Claude Code
  2. Ensure uvenv is installed and the uvx command is available
  3. Add the MCP server: claude mcp add ddg-search uvx duckduckgo-mcp-server

Running with SSE or Streamable HTTP

The server supports alternative transports for use with other MCP clients:

# SSE transport
uvx duckduckgo-mcp-server --transport sse

# Streamable HTTP transport
uvx duckduckgo-mcp-server --transport streamable-http

The default transport is stdio, which is used by Claude Desktop and Claude Code.

When running with sse or streamable-http, override the default bind address (127.0.0.1:8000) with the --host and --port flags:

uvx duckduckgo-mcp-server --transport streamable-http --host 0.0.0.0 --port 7070

Running behind a reverse proxy or in Docker

FastMCP enables DNS-rebinding protection for the HTTP transports and, by default, only accepts Host/Origin headers for localhost. Behind a reverse proxy or in a container the client's Host header won't match, so requests fail with 421 Misdirected Request.

Fix it by allow-listing the host(s) and origin(s) clients actually use (preferred over disabling protection). Values support host, host:port, and wildcard-port host:*:

uvx duckduckgo-mcp-server --transport streamable-http --host 0.0.0.0 --port 7070 \
  --allowed-hosts ddg-mcp.example.com "ddg-mcp.example.com:*" \
  --allowed-origins "https://ddg-mcp.example.com"

Equivalent environment variables (comma-separated) are also available: DDG_ALLOWED_HOSTS, DDG_ALLOWED_ORIGINS.

As a last resort you can turn the check off entirely with --disable-dns-rebinding-protection (or DDG_DISABLE_DNS_REBINDING_PROTECTION=1). Prefer an allow-list — disabling protection removes a defense against DNS-rebinding attacks. When nothing is configured, the secure localhost-only default is preserved.

Running behind a TLS-intercepting proxy

Corporate proxies that re-sign HTTPS traffic with their own CA (via HTTPS_PROXY) cause outbound requests to fail with certificate verification errors, because the HTTP clients don't trust the proxy's self-signed CA (and httpx no longer reads the SSL_CERT_FILE environment variable). Point the server at your proxy's CA bundle:

uvx duckduckgo-mcp-server --ca-certs /path/to/proxy-ca.pem

Or set DDG_CA_CERTS=/path/to/proxy-ca.pem. The bundle is used by both the search and fetch_content tools, on the httpx and curl backends alike.

As a last resort, --no-ssl-verify (or DDG_SSL_VERIFY=0) disables certificate verification entirely. This exposes traffic to interception by anyone on the network path — prefer --ca-certs.

Backends (bypassing bot detection)

Some sites — and, as of recently, DuckDuckGo's own search endpoint (html.duckduckgo.com) — block the default httpx client because of its distinctive TLS fingerprint, regardless of User-Agent. Cloudflare Bot Management and similar filters key on the JA3/TLS handshake, not on headers, so html.duckduckgo.com may answer httpx with an empty HTTP 202 page (silently yielding "no results"). An opt-in backend, curl (implemented via curl_cffi), impersonates a real Chrome browser's TLS handshake and passes through those checks.

Both the search tool and the fetch_content tool support these backends.

Installation:

# Default install (httpx only)
uv pip install duckduckgo-mcp-server

# With the optional browser backend
uv pip install "duckduckgo-mcp-server[browser]"

Backend options:

ValueBehaviorNeeds [browser]
httpxLightweight async HTTP. Default. Works on most sites.no
curlUses curl_cffi with Chrome 131 TLS impersonation. Passes TLS-fingerprint-based filters.yes
autoTries httpx first; on 403 or a Cloudflare challenge response, retries with curl.yes

Two ways to configure the backend:

  1. Server-wide default via the --fetch-backend CLI flag (applies to every fetch_content call):

    # Default behavior — uses httpx
    uvx duckduckgo-mcp-server
    
    # Force curl for every fetch (requires the [browser] extra)
    uvx --with "duckduckgo-mcp-server[browser]" duckduckgo-mcp-server --fetch-backend curl
    
    # Try httpx first, fall back to curl on 403 / Cloudflare challenge
    uvx --with "duckduckgo-mcp-server[browser]" duckduckgo-mcp-server --fetch-backend auto
    
  2. Per-call override via the backend argument on the fetch_content tool (overrides the CLI default for that single call). The tool exposes backend in its input schema, so an MCP client can choose "httpx", "curl", or "auto" on a fetch-by-fetch basis.

For fetch_content, the default stays httpx so users who don't need the impersonation don't pay for the extra dependency.

Search backend

Because DuckDuckGo's search endpoint now fingerprint-blocks plain httpx, the search tool defaults to auto: it tries httpx first and falls back to curl when it detects a block (HTTP 202/403). The fallback only works if the [browser] extra is installed; otherwise search returns a message telling you to install it.

Configure the search backend with the --search-backend CLI flag or the DDG_SEARCH_BACKEND environment variable (auto (default) / httpx / curl):

# Recommended: install the browser extra so the auto fallback can impersonate Chrome
uvx --with "duckduckgo-mcp-server[browser]" duckduckgo-mcp-server

# Force curl for every search
uvx --with "duckduckgo-mcp-server[browser]" duckduckgo-mcp-server --search-backend curl

# Opt out of the fallback (legacy behavior — may return no results while blocked)
uvx duckduckgo-mcp-server --search-backend httpx

Development

For local development:

# Install dependencies
uv sync

# Run with the MCP Inspector
mcp dev src/duckduckgo_mcp_server/server.py

# Install locally for testing with Claude Desktop
mcp install src/duckduckgo_mcp_server/server.py

# Run all tests
uv run python -m pytest src/duckduckgo_mcp_server/ -v

# Run only unit tests
uv run python -m pytest src/duckduckgo_mcp_server/test_server.py -v

# Run only e2e tests
uv run python -m pytest src/duckduckgo_mcp_server/test_e2e.py -v

Available Tools

1. Search Tool

async def search(query: str, max_results: int = 10, region: str = "") -> str

Performs a web search on DuckDuckGo and returns formatted results.

Parameters:

  • query: Search query string
  • max_results: Maximum number of results to return (default: 10)
  • region: (Optional) Region/language code to override the default. Leave empty to use the configured default region.

Region Code Examples:

  • us-en: United States (English)
  • cn-zh: China (Chinese)
  • jp-ja: Japan (Japanese)
  • de-de: Germany (German)
  • fr-fr: France (French)
  • wt-wt: No specific region

Returns: Formatted string containing search results with titles, URLs, and snippets.

Example Usage:

  • Search with default settings: search("python tutorial")
  • Search with specific region: search("latest news", region="jp-ja") for Japanese news

2. Content Fetching Tool

async def fetch_content(
    url: str,
    start_index: int = 0,
    max_length: int = 8000,
    backend: Optional[str] = None,
) -> str

Fetches and parses content from a webpage.

Parameters:

  • url: The webpage URL to fetch content from
  • start_index: Character offset to start reading from (for pagination)
  • max_length: Maximum number of characters to return
  • backend: Optional per-call override of the default fetch backend ("httpx", "curl", or "auto"). When omitted, uses whatever was set via --fetch-backend at server startup.

Returns: Cleaned and formatted text content from the webpage.

SSRF protection: By default fetch_content refuses URLs that resolve to loopback, private (RFC1918), link-local (including the 169.254.169.254 cloud metadata endpoint), reserved, multicast, or unspecified addresses, and it re-validates every redirect hop. Only http/https URLs are allowed. For trusted local deployments that need to fetch internal hosts, disable the guard with DDG_ALLOW_PRIVATE_URLS=1 or --allow-private-urls. See SECURITY.md for details.

Features in Detail

Rate Limiting

  • Search: Limited to 30 requests per minute
  • Content Fetching: Limited to 20 requests per minute
  • Automatic queue management and wait times

Result Processing

  • Removes ads and irrelevant content
  • Cleans up DuckDuckGo redirect URLs
  • Formats results for optimal LLM consumption
  • Truncates long content appropriately

Content Safety

  • SafeSearch Filtering: Configured at server startup via DDG_SAFE_SEARCH environment variable

    • Controlled by administrators, not modifiable by AI assistants
    • Filters inappropriate content based on the selected level
    • Uses DuckDuckGo's official kp parameter
  • Region Localization:

    • Default region set via DDG_REGION environment variable
    • Can be overridden per search request by AI assistants
    • Improves result relevance for specific geographic regions

Error Handling

  • Comprehensive error catching and reporting
  • Detailed logging through MCP context
  • Graceful degradation on rate limits or timeouts

Contributing

Issues and pull requests are welcome! Some areas for potential improvement:

  • Enhanced content parsing options
  • Caching layer for frequently accessed content
  • Additional rate limiting strategies

License

This project is licensed under the MIT License.

Star History

Star History Chart