mcp-websearch-aggregator
Aggregates search results from DuckDuckGo, Wikidata, and ArXiv into a single markdown response via JSON-RPC endpoint.
README
MCP Websearch Aggregator
Overview
mcp-websearch-aggregator is a Python microservice that exposes a JSON-RPC /mcp endpoint and aggregates search results from DuckDuckGo, Wikidata, and ArXiv into a single markdown response.
This repository follows an enterprise-friendly src/ layout and contains automated tests, configuration via environment variables, and Prometheus-compatible metrics.
Table of Contents
- Quick Start
- Prerequisites
- Repository Layout
- Configuration
- Environment Profiles
- Development
- Testing
- Packaging
- Running
- Deployment
- API Contract
- Troubleshooting
Quick Start
git clone <repo-url>
cd mcp-websearch-aggregator
uv venv
source .venv/bin/activate
uv sync
python main.py
Open http://127.0.0.1:3000 and send JSON-RPC requests to /mcp.
Prerequisites
macOS
This project targets Python 3.14. On macOS, install the required runtime and tooling with Homebrew.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install python@3.14
brew install uv
Verify your installations:
python3.14 --version
uv --version
Recommended local environment
uv venv
source .venv/bin/activate
uv sync
Repository Layout
.
├── README.md
├── pyproject.toml
├── main.py
├── src/
│ └── mcp_websearch_aggregator/
│ ├── config.py
│ ├── logging.py
│ ├── main.py
│ ├── middleware.py
│ ├── metrics.py
│ ├── server.py
│ ├── services/
│ │ ├── arxiv.py
│ │ ├── duckduckgo.py
│ │ └── wikidata.py
│ └── utils/
│ └── formatter.py
└── tests/
├── integration/
└── unit/
Configuration
The service is configured using environment variables. Defaults are provided in src/mcp_websearch_aggregator/config.py.
| Variable | Default | Description |
|---|---|---|
ENVIRONMENT |
dev |
Runtime environment identifier (dev, uat, prod) |
SERVER_HOST |
127.0.0.1 |
Host interface for the HTTP server |
SERVER_PORT |
3000 |
Port for the HTTP server |
LOG_LEVEL |
INFO |
Logging verbosity |
REQUEST_TIMEOUT |
10 |
HTTP request timeout in seconds |
MAX_RESULTS |
1 |
Maximum results fetched per third-party service |
DUCKDUCKGO_API |
https://api.duckduckgo.com |
DuckDuckGo service endpoint |
WIKIDATA_API |
https://www.wikidata.org/w/api.php |
Wikidata service endpoint |
ARXIV_API |
http://export.arxiv.org/api/query |
ArXiv service endpoint |
METRICS_ENABLED |
true |
Enable Prometheus metrics export |
Default environment variables
export ENVIRONMENT=dev
export SERVER_HOST=127.0.0.1
export SERVER_PORT=3000
export LOG_LEVEL=DEBUG
export REQUEST_TIMEOUT=10
export MAX_RESULTS=1
export METRICS_ENABLED=true
Recommended config files
Use a dedicated .env/ folder to organize environment-specific configuration files. This keeps configs organized and scalable as the project grows.
| Profile | Path (from repo root) | Purpose | Key Settings |
|---|---|---|---|
| DEV | .env/dev |
Local development | SERVER_HOST=127.0.0.1, LOG_LEVEL=DEBUG, REQUEST_TIMEOUT=10 |
| UAT | .env/uat |
User acceptance testing | SERVER_HOST=0.0.0.0, LOG_LEVEL=INFO, REQUEST_TIMEOUT=15 |
| PROD | .env/prod |
Production deployment | SERVER_HOST=0.0.0.0, LOG_LEVEL=INFO, REQUEST_TIMEOUT=20 |
Create the folder structure:
mkdir -p .env/dev .env/uat .env/prod
Each file should define the same variables (shown in the Configuration section above). Load a profile before running the app:
source .env/dev
python main.py
For UAT and PROD, keep these profile files secure and out of public source control. Alternatively, inject environment variables through your CI/CD or container runtime instead of using local files.
Because profile files already define environment variables, you do not need to run additional export commands after sourcing them. The shell will load the values into the current session automatically.
For UAT and PROD, keep these profile files in a secure deployment pipeline, not in public source control. Alternatively, inject the same variables through your CI/CD or container runtime instead of using local files.
Environment Profiles
This repository supports explicit environment profiles via the ENVIRONMENT variable. Each profile is a preset of environment variables tailored for a specific deployment context.
| Setting | DEV | UAT | PROD |
|---|---|---|---|
ENVIRONMENT |
dev |
uat |
prod |
SERVER_HOST |
127.0.0.1 |
0.0.0.0 |
0.0.0.0 |
SERVER_PORT |
3000 |
3000 |
3000 |
LOG_LEVEL |
DEBUG |
INFO |
INFO |
REQUEST_TIMEOUT |
10 |
15 |
20 |
MAX_RESULTS |
1 |
1 |
1 |
METRICS_ENABLED |
true |
true |
true |
Development
Install dependencies
uv sync
This reads pyproject.toml and installs all runtime and development dependencies into the active virtual environment.
Recommended workflow
- Create a virtual environment
- Activate the environment
- Install dependencies
- Run the application locally
- Execute tests
Running the app locally
Use the root launcher:
python main.py
Or run the ASGI app directly with Uvicorn:
uvicorn mcp_websearch_aggregator.server:app --host 127.0.0.1 --port 3000 --reload
Debugging
- Inspect service logs on startup and request handling
- Use the
/metricsendpoint for runtime metrics - Increase logging verbosity with
LOG_LEVEL=DEBUG
Testing
Run all tests with Pytest:
uv run pytest -q
Run a specific test file:
uv run pytest tests/unit/test_duckduckgo.py -q
Code Coverage
Measure code coverage with pytest-cov:
uv run pytest --cov=src/mcp_websearch_aggregator --cov-report=term-missing
Generate an HTML coverage report:
uv run pytest --cov=src/mcp_websearch_aggregator --cov-report=html
View the report in your browser:
open htmlcov/index.html
Coverage configuration is defined in .coveragerc. The project enforces a minimum 80% code coverage threshold. Excluded lines are marked with # pragma: no cover.
Coverage metrics:
- Line coverage: % of lines executed
- Branch coverage: % of conditional branches exercised
- Missing lines: source lines not covered by tests
Packaging
Build a source distribution and wheel:
python -m pip install --upgrade build
python -m build
Install the package locally for validation:
python -m pip install dist/mcp_websearch_aggregator-0.1.0-py3-none-any.whl
Running
The service exposes two endpoints:
POST /mcp— JSON-RPC search endpointGET /metrics— Prometheus metrics endpoint
Example run command:
uvicorn mcp_websearch_aggregator.server:app --host 0.0.0.0 --port 3000
Deployment
For production, use an ASGI server with process management and explicit environment configuration.
Deploy to UAT
export ENVIRONMENT=uat
export SERVER_HOST=0.0.0.0
export SERVER_PORT=3000
export LOG_LEVEL=INFO
export REQUEST_TIMEOUT=15
export MAX_RESULTS=1
export METRICS_ENABLED=true
gunicorn -k uvicorn.workers.UvicornWorker mcp_websearch_aggregator.server:app --bind 0.0.0.0:3000
Deploy to PROD
export ENVIRONMENT=prod
export SERVER_HOST=0.0.0.0
export SERVER_PORT=3000
export LOG_LEVEL=INFO
export REQUEST_TIMEOUT=20
export MAX_RESULTS=1
export METRICS_ENABLED=true
gunicorn -k uvicorn.workers.UvicornWorker mcp_websearch_aggregator.server:app --bind 0.0.0.0:3000
Docker / containerized deployment
For container deployment, pass environment variables through your container runtime or orchestration platform.
docker run -e ENVIRONMENT=prod -e SERVER_HOST=0.0.0.0 -e SERVER_PORT=3000 \
-e LOG_LEVEL=INFO -e REQUEST_TIMEOUT=20 -e MAX_RESULTS=1 -e METRICS_ENABLED=true \
your-image-name
API Contract
OpenAPI Documentation
FastAPI automatically generates interactive API documentation with Pydantic models. Access it at:
- Swagger UI:
http://127.0.0.1:3000/docs— interactive API explorer - ReDoc:
http://127.0.0.1:3000/redoc— alternative documentation view
The /docs endpoint allows you to test the /mcp endpoint directly in your browser.
JSON-RPC Endpoint: /mcp
The service implements the JSON-RPC 2.0 specification. It accepts POST requests and returns JSON-RPC responses.
Request format
{
"jsonrpc": "2.0",
"method": "search",
"params": {"query": "machine learning"},
"id": 1
}
Fields:
jsonrpc: always"2.0"method:"search"(other methods return "Method not found" error)params: object withqueryfield (search term)id: unique request identifier for correlation
Success response
{
"jsonrpc": "2.0",
"result": "## DuckDuckGo\n...\n\n## Wikidata\n...\n\n## ArXiv\n...",
"id": 1
}
Fields:
result: markdown-formatted aggregated results from all sources
Error response
{
"jsonrpc": "2.0",
"error": {
"code": -32600,
"message": "Invalid Request"
},
"id": null
}
Common error codes:
-32700: Parse error (malformed JSON)-32600: Invalid Request (missing/invalid fields)-32601: Method not found (unsupported method)-32603: Internal error (server failure)
Pydantic Models
The service uses Pydantic for request/response validation and schema documentation:
SearchParams: query string parameter definitionJSONRPCRequest: complete request envelopeJSONRPCResponse: success response with markdown resultJSONRPCError: error object structureJSONRPCErrorResponse: error response envelope
These models are automatically documented in the OpenAPI schema and visible in the Swagger UI.
Troubleshooting
ModuleNotFoundError: ensuresrc/is onPYTHONPATHor run viapython main.pyConnectionError: verify outbound internet access to DuckDuckGo, Wikidata, and ArXivTimeoutError: increaseREQUEST_TIMEOUT
Notes
- The repository uses
src/package layout for clean import boundaries. - The default JSON-RPC method is
search; other methods returnMethod not found. - Metrics are exported in plaintext for Prometheus scraping.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。