# Directory Structure
```
├── .dockerignore
├── .env
├── .gitignore
├── .python-version
├── ddgs.py
├── docker-compose.yml
├── Dockerfile
├── pyproject.toml
├── README.md
└── uv.lock
```
# Files
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
```
.venv
```
--------------------------------------------------------------------------------
/.python-version:
--------------------------------------------------------------------------------
```
3.11
```
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
```
PORT=8000
NETWORK_MODE=mcp-ddgs_default #or you can use "host"
```
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
# Python-generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info
# Virtual environments
.venv
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
Simple Model Context Protocol server for searching Duck Duck Go, based on [Open-WebUI's built-in Web Search feature](https://github.com/open-webui/open-webui/blob/3f3a5bb0ab8ce3425f317f1e57b084523aa2b2a5/backend/open_webui/retrieval/web/duckduckgo.py) and using SSE transport
```
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
FROM python:3.12-slim-bookworm
COPY --from=ghcr.io/astral-sh/uv:0.6.1 /uv /uvx /bin/
RUN apt update && apt install curl -y
ADD . /app
WORKDIR /app
RUN uv venv --python 3.12 venv
RUN uv sync --frozen
CMD ["uv", "run", "python", "ddgs.py" ]
```
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
```toml
[project]
name = "mcp-ddgs"
version = "0.1.0"
description = "Simple Model Context Protocol server for searching Duck Duck Go"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"duckduckgo-search>=7.4.2",
"httpx>=0.28.1",
"mcp[cli]>=1.2.1",
]
```
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
```yaml
services:
mcp-ddgs:
container_name: mcp-ddgs
restart: unless-stopped
pull_policy: build
image: lowlyocean/mcp-ddgs:latest
build:
context: .
network: host
ports:
- ${PORT}:${PORT}
environment:
FASTMCP_PORT: ${PORT}
extra_hosts:
- "host.docker.internal:host-gateway"
network_mode: ${NETWORK_MODE}
```
--------------------------------------------------------------------------------
/ddgs.py:
--------------------------------------------------------------------------------
```python
from mcp.server.fastmcp import FastMCP
from duckduckgo_search import DDGS
from typing import Annotated
from pydantic import Field
# Initialize FastMCP server
mcp = FastMCP("ddgs")
@mcp.tool()
async def search(query: Annotated[str, Field(description="The query to search for")]) -> list[dict]:
"""
Search using DuckDuckGo's Search API and return the results as a list of dictionaries
"""
# Use the DDGS context manager to create a DDGS object
with DDGS() as ddgs:
# Use the ddgs.text() method to perform the search
ddgs_gen = ddgs.text(
query, safesearch="moderate", max_results=3, backend="auto"
)
# Check if there are search results
if ddgs_gen:
# Convert the search results into a list
search_results = [r for r in ddgs_gen]
# Return the list of search results
return [
{
"link": result["href"],
"title": result.get("title"),
"snippet": result.get("body"),
}
for result in search_results
]
if __name__ == "__main__":
# Initialize and run the server
mcp.run(transport='sse')
```