Agent Web Search
One web-search tool for AI agents, backed by multiple independent providers.
English | 简体中文
Deploy a remote MCP
Works with Codex CLI, Claude Code, OpenCode, Hermes, ordinary shell scripts, Python applications, and remote Streamable HTTP MCP clients.
Providers · Quick start · CLI · Remote MCP · Tool interface · Python API · Configuration · Integrations · Troubleshooting · Architecture · Development
Agent Web Search exposes one provider-neutral web_search tool. It dispatches
the enabled providers concurrently, normalizes their responses into one schema,
keeps partial failures isolated, and lets the calling agent choose which
enabled providers to use for each request.
Agent / MCP client
│
▼
web_search
│
▼
SearchEngine ──┬── DDGS
├── Exa
├── Parallel
├── ARK
├── Brave
├── Gemini
├── Grok
├── Perplexity
├── Tavily
└── You.com
Why Agent Web Search
- Concurrent, independent providers. All selected providers run at the same time, and one provider's failure never discards another provider's results.
- Zero-key start. The default providers — DDGS, Exa, and Parallel — work without any API key.
- One interface everywhere. MCP (stdio and HTTP), the CLI, the Python API, and the Hermes plugin share the same search engine, tool schema, and response model.
- Focused responses. Every provider response contains only a generated
answerwhen available and normalizedresults. - No telemetry, no shared secrets. Provider keys stay in server-side environment variables; there is no shared API-key service.
Providers
Free, keyless defaults: DDGS, Exa, and Parallel all work without an API key. Exa and Parallel automatically use their free MCP transports until a paid API key is provided.
| Provider | Search backend | API key | Enabled by default |
|---|---|---|---|
| DDGS | DuckDuckGo search | Free · no key required | Yes |
| Exa | Paid Search API or free MCP fallback | Free without key · optional EXA_API_KEY |
Yes |
| Parallel | Free MCP or paid LLM-optimized search | Free without key · optional PARALLEL_API_KEY |
Yes |
| ARK (Recommended) | Volcengine ARK Responses API + web_search |
ARK_API_KEY |
No |
| Brave | Brave Search API | BRAVE_SEARCH_API_KEY |
No |
| Gemini | Google Search grounding | GEMINI_API_KEY |
No |
| Grok | xAI web search and X Search | XAI_API_KEY |
No |
| Perplexity | Native structured Search API | PERPLEXITY_API_KEY |
No |
| Tavily | Tavily Search API | TAVILY_API_KEY |
No |
| You.com | Unified web and news search | YDC_API_KEY |
No |
The provider architecture is intentionally open: another search-capable backend can be added without changing the MCP, Hermes, CLI, or Python-facing interfaces.
Quick start
Requirements: Python 3.10+. No API key is needed; the default providers are free and keyless.
Install from PyPI with whichever package runner you already use:
# Standard Python installation
python -m pip install agent-web-search-mcp
# Isolated persistent installation
pipx install agent-web-search-mcp
# Run without a persistent installation
uvx agent-web-search-mcp
The PyPI package agent-web-search-mcp installs two commands —
agent-web-search (CLI) and agent-web-search-mcp (MCP server) — and imports
as the Python module agent_web_search. uvx runs either command without a
persistent installation.
Search right away:
agent-web-search "What changed in the latest OpenAI Codex CLI?"
Or run the CLI through uvx without installing it:
uvx --from agent-web-search-mcp agent-web-search \
"What changed in the latest OpenAI Codex CLI?"
Start the stdio MCP server for an MCP client:
agent-web-search-mcp
To use uvx directly from an MCP client without installing the package first,
configure the client to run uvx agent-web-search-mcp. For example:
{
"mcpServers": {
"agent-web-search": {
"command": "uvx",
"args": ["agent-web-search-mcp"]
}
}
}
Install the latest development version from GitHub
pipx install 'git+https://github.com/JerryLiu369/agent-web-search.git'
[!IMPORTANT] Do not place API keys in shell history, source code, Git commits, screenshots, or checked-in MCP configuration. Export them from a secret manager or a local environment file that is not committed.
CLI
agent-web-search QUERY runs one search and prints a single JSON document to
stdout.
| Option | Values | Default | Purpose |
|---|---|---|---|
--provider |
provider name, repeatable | all enabled | Restrict this request to specific enabled providers |
--max-results |
1–20 | 10 |
Desired maximum number of results |
--max-keyword |
1–10 | 3 |
Desired maximum number of search queries or keywords |
--time-range |
d, w, m, y |
— | Past day, week, month, or year |
--grok-search-mode |
web_search, x_search, both |
web_search |
Only meaningful when Grok is enabled |
# Use every startup-enabled provider.
agent-web-search "What changed in the latest OpenAI Codex CLI?"
# Limit results and publication time.
agent-web-search "GPU kernel generation papers" --time-range m --max-results 5
# Select a provider subset for this request.
agent-web-search "latest AI news" --provider ark --provider ddgs
Remote MCP over HTTPS
The same agent-web-search-mcp command supports both MCP transports. It keeps
stdio as the zero-argument default and enables stateless Streamable HTTP with a
transport switch:
# Generate a deployment token once.
python -c "import secrets; print(secrets.token_urlsafe(32))"
export AGENT_WEB_SEARCH_AUTH_TOKEN="replace-with-the-generated-token"
agent-web-search-mcp --transport http
The HTTP server exposes POST /mcp and public GET /healthz. /mcp requires
the deployment Bearer Token by default and never creates an MCP-Session-Id.
Remote MCP client example:
{
"mcpServers": {
"agent-web-search": {
"url": "https://your-deployment.example/mcp",
"headers": {
"Authorization": "Bearer your-deployment-token"
}
}
}
}
Every public deployment must set AGENT_WEB_SEARCH_AUTH_TOKEN to at least 32
characters. Provider keys remain optional server-side environment variables.
Generic Docker deployment:
docker build -t agent-web-search .
docker run --rm -p 8000:8000 \
-e AGENT_WEB_SEARCH_AUTH_TOKEN="replace-with-a-32-character-token" \
agent-web-search
Tool interface
The MCP server and Hermes plugin register one tool named web_search.
| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
query |
string | Yes | — | Complete natural-language search question |
max_results |
integer, 1–20 | No | 10 |
Desired maximum number of results |
max_keyword |
integer, 1–10 | No | 3 |
Desired maximum number of search queries or keywords |
time_range |
d, w, m, y |
No | — | Past day, week, month, or year |
providers |
string array | No | All enabled | Narrow the request to enabled providers |
grok_search_mode |
web_search, x_search, both |
No | web_search |
Available only when Grok is enabled |
Example call:
{
"query": "GPU kernel generation papers from the past month",
"max_results": 5,
"time_range": "m",
"providers": ["ddgs", "exa"]
}
Provider selection has two levels:
AGENT_WEB_SEARCH_PROVIDERSdefines the provider set when the process starts.- The request-level
providersargument may narrow that set, but cannot enable a provider that was disabled at startup.
Response format
Each selected provider that succeeds appears under providers; failed
providers are omitted:
{
"query": "GPU kernel generation papers from the past month",
"providers": {
"ddgs": {
"answer": "",
"results": [
{
"title": "Example result",
"url": "https://example.com/paper",
"description": "Excerpt of the matching page",
"provider": "ddgs",
"published_at": "2026-08-02"
}
]
}
}
}
| Field | Meaning |
|---|---|
answer |
Provider-generated prose answer, when the backend produces one |
results |
Result rows: title, url, description, provider, plus optional published_at and author |
If every selected provider fails, the MCP tool returns an error with the stable
code all_providers_failed and per-provider diagnostics:
{
"error": {
"code": "all_providers_failed",
"message": "All enabled search providers failed. Check provider configuration, credentials, quotas, and network access.",
"provider_errors": {
"ddgs": "RuntimeError: rate limited"
}
},
"query": "GPU kernel generation papers from the past month"
}
Python API
The CLI, MCP servers, and Hermes plugin are thin wrappers around
agent_web_search.SearchEngine, which is the public Python API.
SearchRequest accepts the same fields as the MCP tool arguments:
from agent_web_search import SearchEngine, SearchRequest
engine = SearchEngine() # reads AGENT_WEB_SEARCH_* variables at construction
response = engine.search(
SearchRequest(query="latest MCP spec changes", max_results=5, time_range="m")
)
for name, provider in response.providers.items():
print(f"{name}: searched={provider.searched}, results={len(provider.results)}")
if response.all_providers_failed:
print(response.failed_provider_errors)
Configuration
Configuration is read from environment variables when the CLI, MCP server, or Hermes plugin starts. Restart the process after changing provider settings. See .env.example for a commented template of every variable.
General settings
| Variable | Default | Purpose |
|---|---|---|
AGENT_WEB_SEARCH_PROVIDERS |
ddgs,exa,parallel |
Comma-separated startup-enabled provider set |
AGENT_WEB_SEARCH_TIMEOUT |
60 |
Per-provider timeout in seconds |
Example:
export AGENT_WEB_SEARCH_PROVIDERS="ddgs,exa,brave"
export AGENT_WEB_SEARCH_TIMEOUT="30"
$env:AGENT_WEB_SEARCH_PROVIDERS = "ddgs,exa,brave"
$env:AGENT_WEB_SEARCH_TIMEOUT = "30"
HTTP transport settings
| Variable | Default | Purpose |
|---|---|---|
AGENT_WEB_SEARCH_MCP_TRANSPORT |
stdio |
stdio or http; --transport may override it |
AGENT_WEB_SEARCH_HTTP_HOST |
0.0.0.0 |
HTTP bind host for container deployments |
AGENT_WEB_SEARCH_HTTP_PORT |
PORT or 8000 |
HTTP bind port; explicit value overrides platform PORT |
AGENT_WEB_SEARCH_AUTH_TOKEN |
— | Required HTTP Bearer Token, at least 32 characters |
AGENT_WEB_SEARCH_ALLOW_ANONYMOUS |
false |
Explicitly disables HTTP auth for trusted/demo environments |
AGENT_WEB_SEARCH_HTTP_ALLOWED_HOSTS |
— | Optional comma-separated Host allowlist |
AGENT_WEB_SEARCH_HTTP_ALLOWED_ORIGINS |
— | Optional comma-separated Origin allowlist; requires allowed hosts |
AGENT_WEB_SEARCH_HTTP_LOG_LEVEL |
info |
Uvicorn log level for the container server |
HTTP settings remain environment-only; the deployment files do not introduce a second application configuration format.
Provider settings
Default providers are listed first; optional providers then follow alphabetical order.
1. DDGS
DDGS uses DuckDuckGo and requires no API key or provider-specific environment
variables. The ddgs Python dependency is installed with the package.
2. Exa
Exa supports both paid and keyless modes.
| Variable | Required | Purpose |
|---|---|---|
EXA_API_KEY |
No | Uses the paid Search API when present |
EXA_MCP_URL |
No | Overrides the free MCP endpoint when no API key is set |
Without EXA_API_KEY, Exa falls back to its free MCP endpoint on a best-effort
basis. The paid API generally provides higher quota and reliability.
3. Parallel
Parallel returns information-dense excerpts ranked for LLM context. One
parallel provider automatically selects its transport:
- Without a key, it uses Parallel's free Search MCP.
- With
PARALLEL_API_KEY, it uses the paid Search REST API.
Both transports map excerpts into the common result description, so the
calling agent does not need to distinguish parallel-free from parallel.
| Variable | Required | Purpose |
|---|---|---|
PARALLEL_API_KEY |
No | Enables the paid API; omit it to use the free MCP |
Parallel is enabled by default and its key is optional.
4. ARK (Recommended)
Volcengine ARK uses model-backed search grounding through the Responses API.
Add ark to AGENT_WEB_SEARCH_PROVIDERS after providing the key.
| Variable | Required | Purpose |
|---|---|---|
ARK_API_KEY |
Yes | One key, or multiple comma/newline-separated keys |
AGENT_WEB_SEARCH_ARK_MODELS |
No | Comma/newline-separated ARK model IDs |
One model stays fixed; multiple models are selected round-robin for successive requests. When multiple ARK keys are configured, a key is selected per request.
Optional Volcengine collaboration rewards information
Agent Web Search does not require participation in a rewards program. ARK users may optionally review the official Volcengine Collaboration Rewards Program. Quota, supported models, validity periods, and data-authorization terms can change. Check the official terms before opting in. Participation is not required to use Agent Web Search.
5. Brave
| Variable | Required | Purpose |
|---|---|---|
BRAVE_SEARCH_API_KEY |
Yes | Brave Web Search API credential |
Add brave to AGENT_WEB_SEARCH_PROVIDERS after providing the key.
6. Gemini
| Variable | Required | Purpose |
|---|---|---|
GEMINI_API_KEY |
Yes | Google AI API credential |
AGENT_WEB_SEARCH_GEMINI_MODELS |
No | Comma/newline-separated Gemini model IDs |
Gemini maps common result and time controls into best-effort prompt constraints. One configured model stays fixed; multiple models are selected round-robin for successive requests.
7. Grok
| Variable | Required | Purpose |
|---|---|---|
XAI_API_KEY |
Yes | xAI API credential |
AGENT_WEB_SEARCH_GROK_MODELS |
No | Comma/newline-separated Grok model IDs |
One configured model stays fixed; multiple models are selected round-robin for successive requests.
When Grok is enabled, the public tool schema adds grok_search_mode:
web_searchsearches the web.x_searchsearches X with native date filters when available.bothexposes both server-side tools in one request and lets Grok choose; it does not issue two independent model requests.
8. Perplexity
This provider uses Perplexity's native structured Search API. It returns result rows rather than a Sonar-generated prose answer; OpenRouter compatibility is intentionally outside this provider's scope.
| Variable | Required | Purpose |
|---|---|---|
PERPLEXITY_API_KEY |
Yes | Perplexity Search API credential |
Add perplexity to AGENT_WEB_SEARCH_PROVIDERS after providing the key.
9. Tavily
| Variable | Required | Purpose |
|---|---|---|
TAVILY_API_KEY |
Yes | Tavily Search API credential |
Add tavily to AGENT_WEB_SEARCH_PROVIDERS after providing the key.
10. You.com
You.com returns unified web and news sections. Agent Web Search merges both,
deduplicates URLs, and applies max_results to the combined result list.
| Variable | Required | Purpose |
|---|---|---|
YDC_API_KEY |
Yes | You.com Search API credential |
Add you to AGENT_WEB_SEARCH_PROVIDERS after providing the key.
Common search controls
Each provider maps the shared controls to its native API when possible and ignores unsupported controls.
| Provider | max_results |
max_keyword |
time_range |
|---|---|---|---|
| DDGS | Native max_results |
Ignored | Native timelimit |
| Exa | Native result count | Ignored | Native publish date |
| Parallel | Native max_results |
Ignored | Ignored |
| ARK | Native limit |
Native | Prompt constraint |
| Brave | Native count |
Ignored | Native freshness |
| Gemini | Prompt constraint | Prompt constraint | Prompt constraint |
| Grok | Prompt constraint | Prompt constraint | Prompt; X Search also uses native dates |
| Perplexity | Native max_results |
Ignored | Native recency filter |
| Tavily | Native max_results |
Ignored | Native time_range |
| You.com | Native count, combined cap |
Ignored | Native freshness |
Prompt-based controls are best-effort and are not strict guarantees.
Integrations
Codex CLI
codex mcp add agent-web-search -- agent-web-search-mcp
codex mcp list
Claude Code
claude mcp add agent-web-search -- agent-web-search-mcp
Or add a project .mcp.json:
{
"mcpServers": {
"agent-web-search": {
"command": "agent-web-search-mcp",
"args": [],
"env": {
"AGENT_WEB_SEARCH_PROVIDERS": "ddgs,exa,parallel"
}
}
}
}
OpenCode
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"agent-web-search": {
"type": "local",
"command": ["agent-web-search-mcp"],
"environment": {
"AGENT_WEB_SEARCH_PROVIDERS": "ddgs,exa,parallel"
},
"enabled": true
}
}
}
Hermes
Install the native plugin directly from GitHub:
pip install 'ddgs>=9.0'
hermes plugins install JerryLiu369/agent-web-search --no-enable
hermes plugins enable agent-web-search --allow-tool-override
The plugin intentionally replaces Hermes' built-in web_search tool, so the
explicit --allow-tool-override grant is required. Start a new Hermes session
after enabling it; restart the gateway when using a messaging channel.
Hermes can also connect through its generic MCP integration instead of the native plugin.
Troubleshooting
all_providers_failed— every selected provider errored. The error carries per-provider diagnostics; check keys, quotas, and network access. Free backends can be rate-limited, so retrying or raisingAGENT_WEB_SEARCH_TIMEOUTmay help.- HTTP 401
invalid_token— theAuthorization: Bearer …header must matchAGENT_WEB_SEARCH_AUTH_TOKEN, which must be at least 32 characters. - A provider is missing from a response — failed providers are omitted
from successful responses. The Python API exposes the reasons in
response.failed_provider_errors. - Provider changes have no effect — provider settings are read once at startup; restart the CLI, MCP server, or Hermes plugin after changing them.
Development
Using uv keeps the development environment
isolated and reproducible:
git clone https://github.com/JerryLiu369/agent-web-search.git
cd agent-web-search
uv venv
uv pip install -e '.[dev]'
uv run pytest -q
uv run ruff check .
Standard venv + pip alternative
python -m venv .venv
# Linux/macOS: source .venv/bin/activate
# Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install -e '.[dev]'
pytest -q
ruff check .
ARCHITECTURE.md is the design source of truth, and
AGENTS.md lists the non-negotiable invariants. Read both before
changing transports, configuration, authentication, deployment, providers, or
tool schemas, keep stdio and HTTP behavior identical, and keep pytest and
ruff green in the same change.
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_web_search_mcp-0.3.0.tar.gz.
File metadata
- Download URL: agent_web_search_mcp-0.3.0.tar.gz
- Upload date:
- Size: 54.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d9e017135dbf080cc53df24fd818fc9bb3e2e2900ae3c37fe0b237df75429fb8
|
|
| MD5 |
a1fbddecd7cbb2d6611fc33065b315d8
|
|
| BLAKE2b-256 |
846d4735183813e6fbceb88d58670b0348328fd6429c839bbed15e17df821424
|
Provenance
The following attestation bundles were made for agent_web_search_mcp-0.3.0.tar.gz:
Publisher:
publish.yml on JerryLiu369/agent-web-search
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_web_search_mcp-0.3.0.tar.gz -
Subject digest:
d9e017135dbf080cc53df24fd818fc9bb3e2e2900ae3c37fe0b237df75429fb8 - Sigstore transparency entry: 2596345116
- Sigstore integration time:
-
Permalink:
JerryLiu369/agent-web-search@554e72f034cedbcb0bea2a49c72eb2c3ef05e685 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/JerryLiu369
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@554e72f034cedbcb0bea2a49c72eb2c3ef05e685 -
Trigger Event:
release
-
Statement type:
File details
Details for the file agent_web_search_mcp-0.3.0-py3-none-any.whl.
File metadata
- Download URL: agent_web_search_mcp-0.3.0-py3-none-any.whl
- Upload date:
- Size: 38.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58bdfa2c10936b26a3030f909f2a227974a938a498a9663608493b57ec81aa80
|
|
| MD5 |
b2e51807977bf70c77aa2f5aa0808980
|
|
| BLAKE2b-256 |
577dadfe793b26054adb238b5e3fe714b7a58ad6a1a76a28ae5e5eb9ce8b557e
|
Provenance
The following attestation bundles were made for agent_web_search_mcp-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on JerryLiu369/agent-web-search
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_web_search_mcp-0.3.0-py3-none-any.whl -
Subject digest:
58bdfa2c10936b26a3030f909f2a227974a938a498a9663608493b57ec81aa80 - Sigstore transparency entry: 2596345447
- Sigstore integration time:
-
Permalink:
JerryLiu369/agent-web-search@554e72f034cedbcb0bea2a49c72eb2c3ef05e685 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/JerryLiu369
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@554e72f034cedbcb0bea2a49c72eb2c3ef05e685 -
Trigger Event:
release
-
Statement type: