DuckDuckGo MCP Server

Most search engines are like wizards: impressive, vaguely alarming, and entirely uninterested in explaining themselves. This MCP server is more like a clerk at Unseen University—two services, no fuss: DuckDuckGo search and Jina-powered page fetches, neatly converted for LLM digestion. It will not save the world, but it will save you from copy-pasting it.
A Model Context Protocol (MCP) server that provides two capabilities:
- Search the web using DuckDuckGo
- Fetch and convert web content using Jina Reader
Features
- DuckDuckGo web search with safe search controls
- Fetch and convert URLs to markdown or JSON using Jina Reader
- LLM-friendly output format option for search results
- CLI for search, fetch, serve, and version commands
- MCP tools for LLM integration
- Docker support for containerized deployment
Installation
Prerequisites
- Python 3.10 or higher
- uv (recommended) or pip
Install from PyPI (recommended)
# Using uv (recommended)
uv pip install duckduckgo-mcp
# Or using pip
pip install duckduckgo-mcp
Install with UVX (for Claude Desktop)
# Install UVX if you haven't already
pip install uvx
# Install the DuckDuckGo MCP package
uvx install duckduckgo-mcp
Install via Smithery
To install DuckDuckGo MCP Server for Claude Desktop automatically via Smithery:
npx -y @smithery/cli install @cyranob/duckduckgo-mcp --client claude
Install from source
For development or to get the latest changes:
# Clone the repository
git clone https://github.com/CyranoB/duckduckgo-mcp.git
cd duckduckgo-mcp
# Install with uv (recommended)
uv pip install -e .
# Or with pip
pip install -e .
Docker
Build and run with Docker:
# Build the image (uses version from latest git tag)
docker build --build-arg VERSION=$(git describe --tags --abbrev=0 | sed 's/^v//') -t duckduckgo-mcp .
# Or specify a version manually
docker build --build-arg VERSION=2.0.2 -t duckduckgo-mcp .
# Run the server (MCP servers use STDIO, so typically run within an MCP client)
docker run -i duckduckgo-mcp
Usage
Starting the Server (STDIO Mode)
# Start the server in STDIO mode (for use with MCP clients like Claude)
duckduckgo-mcp serve
# Enable debug logging
duckduckgo-mcp serve --debug
Testing the Search Tool
# Search DuckDuckGo (JSON output, default)
duckduckgo-mcp search "your search query" --max-results 5 --safesearch moderate
# Search with LLM-friendly text output
duckduckgo-mcp search "your search query" --output-format text
Testing the Fetch Tool
# Fetch a URL and return markdown
duckduckgo-mcp fetch "https://example.com" --format markdown
# Fetch a URL and return JSON
duckduckgo-mcp fetch "https://example.com" --format json
# Limit output length
duckduckgo-mcp fetch "https://example.com" --max-length 2000
# Include generated image alt text
duckduckgo-mcp fetch "https://example.com" --with-images
Version Information
# Show version
duckduckgo-mcp version
# Show detailed version info
duckduckgo-mcp version --debug
MCP Client Setup
This MCP server works with any MCP-compatible client. Use one of the setups below.
Python 3.10-3.13 is supported (3.14 not yet). Use --python ">=3.10,<3.14" with uvx to enforce. Verified with Python 3.12 and 3.13.
Claude Desktop
- Open Claude Desktop > Settings > Developer > Edit Config.
- Edit the config file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
- macOS:
- Add the server config under
mcpServers:{ "mcpServers": { "duckduckgo": { "command": "uvx", "args": ["--python", ">=3.10,<3.14", "duckduckgo-mcp", "serve"] } } } - Restart Claude Desktop.
Claude Code
Add a local stdio server:
claude mcp add --transport stdio duckduckgo -- uvx --python ">=3.10,<3.14" duckduckgo-mcp serve
Optional: claude mcp list to verify, or claude mcp add-from-claude-desktop to import.
Codex (CLI + IDE)
Add via CLI:
codex mcp add duckduckgo -- uvx --python ">=3.10,<3.14" duckduckgo-mcp serve
Or configure ~/.codex/config.toml:
[mcp_servers.duckduckgo]
command = "uvx"
args = ["--python", ">=3.10,<3.14", "duckduckgo-mcp", "serve"]
OpenCode
Add to your OpenCode config (~/.config/opencode/opencode.json or project opencode.json):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"duckduckgo": {
"type": "local",
"command": ["uvx", "--python", ">=3.10,<3.14", "duckduckgo-mcp", "serve"],
"enabled": true
}
}
}
Or run opencode mcp add and follow the prompts.
Cursor
Add to ~/.cursor/mcp.json (global) or .cursor/mcp.json (project):
{
"mcpServers": {
"duckduckgo": {
"command": "uvx",
"args": ["--python", ">=3.10,<3.14", "duckduckgo-mcp", "serve"]
}
}
}
Verify with:
cursor-agent mcp list
MCP Tools
The server exposes these tools to MCP clients:
@mcp.tool()
def duckduckgo_search(
query: str,
max_results: int = 5,
safesearch: str = "moderate",
output_format: str = "json"
) -> list | str:
"""Search DuckDuckGo for the given query."""
@mcp.tool()
def jina_fetch(url: str, format: str = "markdown", max_length: int | None = None, with_images: bool = False) -> str | dict:
"""Fetch a URL and convert it using Jina Reader."""
Example usage in an MCP client:
# This is handled automatically by the MCP client
results = duckduckgo_search("Python programming", max_results=3)
content = jina_fetch("https://example.com", format="markdown")
# Get LLM-friendly text output
text_results = duckduckgo_search("Python programming", output_format="text")
API
Tool 1: Search
- Tool Name:
duckduckgo_search - Description: Search the web using DuckDuckGo (powered by the
ddgslibrary)
Parameters
query(string, required): The search querymax_results(integer, optional, default: 5): Maximum number of search results to returnsafesearch(string, optional, default: "moderate"): Safe search setting ("on", "moderate", or "off")output_format(string, optional, default: "json"): Output format - "json" for structured data, "text" for LLM-friendly formatted string
Response
JSON format (default): A list of dictionaries:
[
{
"title": "Result title",
"url": "https://example.com",
"snippet": "Text snippet from the search result"
}
]
Text format: An LLM-friendly formatted string:
Found 3 search results:
1. Result title
URL: https://example.com
Summary: Text snippet from the search result
2. Another result
URL: https://example2.com
Summary: Another snippet
Tool 2: Fetch
- Tool Name:
jina_fetch - Description: Fetch a URL and convert it to markdown or JSON using Jina Reader
Parameters
url(string, required): The URL to fetch and convertformat(string, optional, default: "markdown"): Output format ("markdown" or "json")max_length(integer, optional): Maximum content length to return (None for no limit)with_images(boolean, optional, default: false): Whether to include image alt text generation
Response
For markdown format: a string containing markdown content
For JSON format: a dictionary with the structure:
{
"url": "https://example.com",
"title": "Page title",
"content": "Markdown content"
}
Notes
- Search uses the
ddgspackage (renamed fromduckduckgo-search). - Fetch uses the Jina Reader API at
https://r.jina.ai/.
Contributing
Contributions are welcome! Here's how you can contribute:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Support
If you encounter any issues or have questions, please open an issue.
License
This project is licensed under the MIT License - see the LICENSE file for details.
