agent-web-search-mcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. agent_web_search_mcp-0.1.0/LICENSE +21 -0
  2. agent_web_search_mcp-0.1.0/PKG-INFO +506 -0
  3. agent_web_search_mcp-0.1.0/README.md +469 -0
  4. agent_web_search_mcp-0.1.0/agent_web_search/__init__.py +7 -0
  5. agent_web_search_mcp-0.1.0/agent_web_search/cli.py +33 -0
  6. agent_web_search_mcp-0.1.0/agent_web_search/engine.py +84 -0
  7. agent_web_search_mcp-0.1.0/agent_web_search/mcp.py +77 -0
  8. agent_web_search_mcp-0.1.0/agent_web_search/model_pool.py +39 -0
  9. agent_web_search_mcp-0.1.0/agent_web_search/models.py +112 -0
  10. agent_web_search_mcp-0.1.0/agent_web_search/prompting.py +49 -0
  11. agent_web_search_mcp-0.1.0/agent_web_search/providers/__init__.py +23 -0
  12. agent_web_search_mcp-0.1.0/agent_web_search/providers/ark.py +180 -0
  13. agent_web_search_mcp-0.1.0/agent_web_search/providers/base.py +13 -0
  14. agent_web_search_mcp-0.1.0/agent_web_search/providers/brave.py +74 -0
  15. agent_web_search_mcp-0.1.0/agent_web_search/providers/ddgs.py +45 -0
  16. agent_web_search_mcp-0.1.0/agent_web_search/providers/exa.py +201 -0
  17. agent_web_search_mcp-0.1.0/agent_web_search/providers/gemini.py +119 -0
  18. agent_web_search_mcp-0.1.0/agent_web_search/providers/grok.py +144 -0
  19. agent_web_search_mcp-0.1.0/agent_web_search/providers/parallel.py +260 -0
  20. agent_web_search_mcp-0.1.0/agent_web_search/providers/perplexity.py +73 -0
  21. agent_web_search_mcp-0.1.0/agent_web_search/providers/tavily.py +87 -0
  22. agent_web_search_mcp-0.1.0/agent_web_search/providers/you.py +102 -0
  23. agent_web_search_mcp-0.1.0/agent_web_search/registry.py +79 -0
  24. agent_web_search_mcp-0.1.0/agent_web_search/schema.py +79 -0
  25. agent_web_search_mcp-0.1.0/agent_web_search_mcp.egg-info/PKG-INFO +506 -0
  26. agent_web_search_mcp-0.1.0/agent_web_search_mcp.egg-info/SOURCES.txt +43 -0
  27. agent_web_search_mcp-0.1.0/agent_web_search_mcp.egg-info/dependency_links.txt +1 -0
  28. agent_web_search_mcp-0.1.0/agent_web_search_mcp.egg-info/entry_points.txt +3 -0
  29. agent_web_search_mcp-0.1.0/agent_web_search_mcp.egg-info/requires.txt +14 -0
  30. agent_web_search_mcp-0.1.0/agent_web_search_mcp.egg-info/top_level.txt +1 -0
  31. agent_web_search_mcp-0.1.0/pyproject.toml +51 -0
  32. agent_web_search_mcp-0.1.0/setup.cfg +4 -0
  33. agent_web_search_mcp-0.1.0/tests/test_adapters.py +54 -0
  34. agent_web_search_mcp-0.1.0/tests/test_ark_parse.py +40 -0
  35. agent_web_search_mcp-0.1.0/tests/test_ark_search.py +61 -0
  36. agent_web_search_mcp-0.1.0/tests/test_brave.py +73 -0
  37. agent_web_search_mcp-0.1.0/tests/test_core.py +106 -0
  38. agent_web_search_mcp-0.1.0/tests/test_exa_parse.py +121 -0
  39. agent_web_search_mcp-0.1.0/tests/test_mcp.py +49 -0
  40. agent_web_search_mcp-0.1.0/tests/test_model_pool.py +101 -0
  41. agent_web_search_mcp-0.1.0/tests/test_optional_providers.py +107 -0
  42. agent_web_search_mcp-0.1.0/tests/test_parallel.py +140 -0
  43. agent_web_search_mcp-0.1.0/tests/test_perplexity.py +65 -0
  44. agent_web_search_mcp-0.1.0/tests/test_tavily.py +75 -0
  45. agent_web_search_mcp-0.1.0/tests/test_you.py +82 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jerry Liu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,506 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-web-search-mcp
3
+ Version: 0.1.0
4
+ Summary: A multi-provider web search layer for AI agents
5
+ Author: Jerry Liu
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/JerryLiu369/agent-web-search
8
+ Project-URL: Repository, https://github.com/JerryLiu369/agent-web-search
9
+ Project-URL: Issues, https://github.com/JerryLiu369/agent-web-search/issues
10
+ Keywords: ai-agents,llm,mcp,web-search
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: ddgs>=9.0
26
+ Requires-Dist: mcp<3,>=2.0
27
+ Provides-Extra: ddgs
28
+ Requires-Dist: ddgs>=9.0; extra == "ddgs"
29
+ Provides-Extra: mcp
30
+ Requires-Dist: mcp<3,>=2.0; extra == "mcp"
31
+ Provides-Extra: dev
32
+ Requires-Dist: build>=1.2; extra == "dev"
33
+ Requires-Dist: pytest>=8; extra == "dev"
34
+ Requires-Dist: ruff>=0.6; extra == "dev"
35
+ Requires-Dist: twine>=5; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ <div align="center">
39
+
40
+ # Agent Web Search
41
+
42
+ **One web-search tool for AI agents, backed by multiple independent providers.**
43
+
44
+ [![Python 3.10+](https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/)
45
+ [![PyPI](https://img.shields.io/pypi/v/agent-web-search-mcp.svg)](https://pypi.org/project/agent-web-search-mcp/)
46
+ [![MCP 2.x](https://img.shields.io/badge/MCP-2.x-6C47FF)](https://modelcontextprotocol.io/)
47
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
48
+
49
+ Works with **Codex CLI**, **Claude Code**, **OpenCode**, **Hermes**, ordinary
50
+ shell scripts, and Python applications.
51
+
52
+ [Providers](#providers) · [Quick start](#quick-start) ·
53
+ [Tool interface](#tool-interface) · [Configuration](#configuration) ·
54
+ [Integrations](#integrations) · [Development](#development)
55
+
56
+ </div>
57
+
58
+ ---
59
+
60
+ Agent Web Search exposes one provider-neutral `web_search` tool. It dispatches
61
+ independent providers concurrently, normalizes their responses, keeps partial
62
+ failures isolated, and lets the calling agent choose which enabled providers to
63
+ use for each request.
64
+
65
+ ```text
66
+ Agent / MCP client
67
+ │
68
+ ▼
69
+ web_search
70
+ │
71
+ ▼
72
+ SearchEngine ──┬── ARK
73
+ ├── DDGS
74
+ ├── Exa
75
+ ├── Brave
76
+ ├── Gemini
77
+ ├── Grok
78
+ ├── Parallel
79
+ ├── Perplexity
80
+ ├── Tavily
81
+ └── You.com
82
+ ```
83
+
84
+ ## Providers
85
+
86
+ | Provider | Search backend | API key | Enabled by default |
87
+ | --- | --- | --- | :---: |
88
+ | **ARK** | Volcengine ARK Responses API + `web_search` | `ARK_API_KEY` | No |
89
+ | **DDGS** | DuckDuckGo search | None | Yes |
90
+ | **Exa** | Paid Search API or free MCP fallback | Optional `EXA_API_KEY` | Yes |
91
+ | **Brave** | Brave Search API | `BRAVE_SEARCH_API_KEY` | No |
92
+ | **Gemini** | Google Search grounding | `GEMINI_API_KEY` | No |
93
+ | **Grok** | xAI web search and X Search | `XAI_API_KEY` | No |
94
+ | **Parallel** | Free MCP or paid LLM-optimized search | Optional `PARALLEL_API_KEY` | Yes |
95
+ | **Perplexity** | Native structured Search API | `PERPLEXITY_API_KEY` | No |
96
+ | **Tavily** | Tavily Search API | `TAVILY_API_KEY` | No |
97
+ | **You.com** | Unified web and news search | `YDC_API_KEY` | No |
98
+
99
+ The provider architecture is intentionally open: another search-capable
100
+ backend can be added without changing the MCP, Hermes, CLI, or Python-facing
101
+ interfaces.
102
+
103
+ ## Quick start
104
+
105
+ Install from PyPI using whichever Python package runner you already have:
106
+
107
+ ```bash
108
+ # Standard Python installation
109
+ python -m pip install agent-web-search-mcp
110
+
111
+ # Isolated persistent installation
112
+ pipx install agent-web-search-mcp
113
+
114
+ # Run without a persistent installation
115
+ uvx agent-web-search-mcp
116
+ ```
117
+
118
+ `pip` and `pipx` install both commands below. `uvx` runs the command named in
119
+ its invocation directly.
120
+
121
+ Run a search without configuring a paid API key after a persistent install:
122
+
123
+ ```bash
124
+ agent-web-search "What changed in the latest OpenAI Codex CLI?"
125
+ ```
126
+
127
+ Or run the CLI through `uvx` without installing it:
128
+
129
+ ```bash
130
+ uvx --from agent-web-search-mcp agent-web-search \
131
+ "What changed in the latest OpenAI Codex CLI?"
132
+ ```
133
+
134
+ Or start the stdio MCP server for an MCP client:
135
+
136
+ ```bash
137
+ agent-web-search-mcp
138
+ ```
139
+
140
+ To use `uvx` directly from an MCP client without installing the package first,
141
+ configure the client to run `uvx agent-web-search-mcp`. For example:
142
+
143
+ ```json
144
+ {
145
+ "mcpServers": {
146
+ "agent-web-search": {
147
+ "command": "uvx",
148
+ "args": ["agent-web-search-mcp"]
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ <details>
155
+ <summary><strong>Install the latest development version from GitHub</strong></summary>
156
+
157
+ ```bash
158
+ pipx install 'git+https://github.com/JerryLiu369/agent-web-search.git'
159
+ ```
160
+
161
+ </details>
162
+
163
+ > [!IMPORTANT]
164
+ > Do not place API keys in shell history, source code, Git commits, screenshots,
165
+ > or checked-in MCP configuration. Export them from a secret manager or a local
166
+ > environment file that is not committed.
167
+
168
+ ## Tool interface
169
+
170
+ The MCP server and Hermes plugin register one tool named `web_search`.
171
+
172
+ | Argument | Type | Required | Default | Description |
173
+ | --- | --- | :---: | --- | --- |
174
+ | `query` | string | Yes | — | Complete natural-language search question |
175
+ | `max_results` | integer, 1–20 | No | `10` | Desired result or citation count |
176
+ | `max_keyword` | integer, 1–10 | No | `3` | Desired maximum number of search queries or keywords |
177
+ | `time_range` | `d`, `w`, `m`, `y` | No | — | Past day, week, month, or year |
178
+ | `providers` | string array | No | All enabled | Narrow the request to enabled providers |
179
+ | `grok_search_mode` | `web_search`, `x_search`, `both` | No | `web_search` | Available only when Grok is enabled |
180
+
181
+ Example call:
182
+
183
+ ```json
184
+ {
185
+ "query": "GPU kernel generation papers from the past month",
186
+ "max_results": 5,
187
+ "time_range": "m",
188
+ "providers": ["ddgs", "exa"]
189
+ }
190
+ ```
191
+
192
+ Provider selection has two levels:
193
+
194
+ 1. `AGENT_WEB_SEARCH_PROVIDERS` defines the provider set when the process starts.
195
+ 2. The request-level `providers` argument may narrow that set, but cannot enable
196
+ a provider that was disabled at startup.
197
+
198
+ Failed providers are omitted from successful responses. If every selected
199
+ provider fails, MCP returns a tool error with the stable code
200
+ `all_providers_failed` and includes per-provider diagnostics.
201
+
202
+ ## Configuration
203
+
204
+ Configuration is read from environment variables when the CLI, MCP server, or
205
+ Hermes plugin starts. Restart the process after changing provider settings.
206
+
207
+ ### General settings
208
+
209
+ | Variable | Default | Purpose |
210
+ | --- | --- | --- |
211
+ | `AGENT_WEB_SEARCH_PROVIDERS` | `ddgs,exa,parallel` | Comma-separated startup-enabled provider set |
212
+ | `AGENT_WEB_SEARCH_TIMEOUT` | `60` | Per-provider timeout in seconds |
213
+
214
+ Example:
215
+
216
+ ```bash
217
+ export AGENT_WEB_SEARCH_PROVIDERS="ddgs,exa,brave"
218
+ export AGENT_WEB_SEARCH_TIMEOUT="30"
219
+ ```
220
+
221
+ ```powershell
222
+ $env:AGENT_WEB_SEARCH_PROVIDERS = "ddgs,exa,brave"
223
+ $env:AGENT_WEB_SEARCH_TIMEOUT = "30"
224
+ ```
225
+
226
+ ### Provider settings
227
+
228
+ #### 1. ARK
229
+
230
+ Volcengine ARK uses model-backed search grounding through the Responses API.
231
+ Add `ark` to `AGENT_WEB_SEARCH_PROVIDERS` after providing the key.
232
+
233
+ | Variable | Required | Purpose |
234
+ | --- | :---: | --- |
235
+ | `ARK_API_KEY` | Yes | One key, or multiple comma/newline-separated keys |
236
+ | `AGENT_WEB_SEARCH_ARK_MODELS` | No | Comma/newline-separated ARK model IDs |
237
+
238
+ One model stays fixed; multiple models are selected round-robin for successive
239
+ requests. When multiple ARK keys are configured, a key is selected per request.
240
+
241
+ <details>
242
+ <summary><strong>Optional Volcengine collaboration rewards information</strong></summary>
243
+
244
+ Agent Web Search does not require participation in a rewards program. ARK users
245
+ may optionally review the official
246
+ [Volcengine Collaboration Rewards Program](https://www.volcengine.com/docs/82379/1391869?lang=zh).
247
+ Quota, supported models, validity periods, and data-authorization terms can
248
+ change. Check the official terms before opting in. Participation is not
249
+ required to use Agent Web Search.
250
+
251
+ </details>
252
+
253
+ #### 2. DDGS
254
+
255
+ DDGS uses DuckDuckGo and requires no API key or provider-specific environment
256
+ variables. The `ddgs` Python dependency is installed with the package.
257
+
258
+ #### 3. Exa
259
+
260
+ Exa supports both paid and keyless modes.
261
+
262
+ | Variable | Required | Purpose |
263
+ | --- | :---: | --- |
264
+ | `EXA_API_KEY` | No | Uses the paid Search API when present |
265
+ | `EXA_MCP_URL` | No | Overrides the free MCP endpoint when no API key is set |
266
+
267
+ Without `EXA_API_KEY`, Exa falls back to its free MCP endpoint on a best-effort
268
+ basis. The paid API generally provides higher quota and reliability.
269
+
270
+ #### 4. Brave
271
+
272
+ | Variable | Required | Purpose |
273
+ | --- | :---: | --- |
274
+ | `BRAVE_SEARCH_API_KEY` | Yes | Brave Web Search API credential |
275
+
276
+ Add `brave` to `AGENT_WEB_SEARCH_PROVIDERS` after providing the key.
277
+
278
+ #### 5. Gemini
279
+
280
+ | Variable | Required | Purpose |
281
+ | --- | :---: | --- |
282
+ | `GEMINI_API_KEY` | Yes | Google AI API credential |
283
+ | `AGENT_WEB_SEARCH_GEMINI_MODELS` | No | Comma/newline-separated Gemini model IDs |
284
+
285
+ Gemini maps common result and time controls into best-effort prompt
286
+ constraints. One configured model stays fixed; multiple models are selected
287
+ round-robin for successive requests.
288
+
289
+ #### 6. Grok
290
+
291
+ | Variable | Required | Purpose |
292
+ | --- | :---: | --- |
293
+ | `XAI_API_KEY` | Yes | xAI API credential |
294
+ | `AGENT_WEB_SEARCH_GROK_MODELS` | No | Comma/newline-separated Grok model IDs |
295
+
296
+ One configured model stays fixed; multiple models are selected round-robin for
297
+ successive requests.
298
+
299
+ When Grok is enabled, the public tool schema adds `grok_search_mode`:
300
+
301
+ - `web_search` searches the web.
302
+ - `x_search` searches X with native date filters when available.
303
+ - `both` exposes both server-side tools in one request and lets Grok choose; it
304
+ does not issue two independent model requests.
305
+
306
+ #### 7. Tavily
307
+
308
+ | Variable | Required | Purpose |
309
+ | --- | :---: | --- |
310
+ | `TAVILY_API_KEY` | Yes | Tavily Search API credential |
311
+
312
+ Add `tavily` to `AGENT_WEB_SEARCH_PROVIDERS` after providing the key.
313
+
314
+ #### 8. Parallel
315
+
316
+ Parallel returns information-dense excerpts ranked for LLM context. One
317
+ `parallel` provider automatically selects its transport:
318
+
319
+ - Without a key, it uses Parallel's free Search MCP.
320
+ - With `PARALLEL_API_KEY`, it uses the paid Search REST API.
321
+
322
+ Both transports map `excerpts` into the common result description, so the
323
+ calling agent does not need to distinguish `parallel-free` from `parallel`.
324
+
325
+ | Variable | Required | Purpose |
326
+ | --- | :---: | --- |
327
+ | `PARALLEL_API_KEY` | No | Enables the paid API; omit it to use the free MCP |
328
+
329
+ Parallel is enabled by default and its key is optional.
330
+
331
+ #### 9. Perplexity
332
+
333
+ This provider uses Perplexity's native structured Search API. It returns result
334
+ rows rather than a Sonar-generated prose answer; OpenRouter compatibility is
335
+ intentionally outside this provider's scope.
336
+
337
+ | Variable | Required | Purpose |
338
+ | --- | :---: | --- |
339
+ | `PERPLEXITY_API_KEY` | Yes | Perplexity Search API credential |
340
+
341
+ Add `perplexity` to `AGENT_WEB_SEARCH_PROVIDERS` after providing the key.
342
+
343
+ #### 10. You.com
344
+
345
+ You.com returns unified web and news sections. Agent Web Search merges both,
346
+ deduplicates URLs, and applies `max_results` to the combined result list.
347
+
348
+ | Variable | Required | Purpose |
349
+ | --- | :---: | --- |
350
+ | `YDC_API_KEY` | Yes | You.com Search API credential |
351
+
352
+ Add `you` to `AGENT_WEB_SEARCH_PROVIDERS` after providing the key.
353
+
354
+ ### Common search controls
355
+
356
+ Each provider maps the shared controls to its native API when possible and
357
+ ignores unsupported controls.
358
+
359
+ | Provider | `max_results` | `max_keyword` | `time_range` |
360
+ | --- | --- | --- | --- |
361
+ | ARK | Native `limit` | Native | Prompt constraint |
362
+ | Brave | Native `count` | Ignored | Native `freshness` |
363
+ | DDGS | Native `max_results` | Ignored | Native `timelimit` |
364
+ | Exa | Native result count | Ignored | Native publish date |
365
+ | Gemini | Prompt constraint | Prompt constraint | Prompt constraint |
366
+ | Grok | Prompt constraint | Prompt constraint | Prompt; X Search also uses native dates |
367
+ | Parallel | Native `max_results` | Ignored | Ignored |
368
+ | Perplexity | Native `max_results` | Ignored | Native recency filter |
369
+ | Tavily | Native `max_results` | Ignored | Native `time_range` |
370
+ | You.com | Native `count`, combined cap | Ignored | Native `freshness` |
371
+
372
+ Prompt-based controls are best-effort and are not strict guarantees.
373
+
374
+ ## Integrations
375
+
376
+ ### Codex CLI
377
+
378
+ ```bash
379
+ codex mcp add agent-web-search -- agent-web-search-mcp
380
+ codex mcp list
381
+ ```
382
+
383
+ ### Claude Code
384
+
385
+ ```bash
386
+ claude mcp add agent-web-search -- agent-web-search-mcp
387
+ ```
388
+
389
+ Or add a project `.mcp.json`:
390
+
391
+ ```json
392
+ {
393
+ "mcpServers": {
394
+ "agent-web-search": {
395
+ "command": "agent-web-search-mcp",
396
+ "args": [],
397
+ "env": {
398
+ "AGENT_WEB_SEARCH_PROVIDERS": "ddgs,exa,parallel"
399
+ }
400
+ }
401
+ }
402
+ }
403
+ ```
404
+
405
+ ### OpenCode
406
+
407
+ ```json
408
+ {
409
+ "$schema": "https://opencode.ai/config.json",
410
+ "mcp": {
411
+ "agent-web-search": {
412
+ "type": "local",
413
+ "command": ["agent-web-search-mcp"],
414
+ "environment": {
415
+ "AGENT_WEB_SEARCH_PROVIDERS": "ddgs,exa,parallel"
416
+ },
417
+ "enabled": true
418
+ }
419
+ }
420
+ }
421
+ ```
422
+
423
+ ### Hermes
424
+
425
+ Install the native plugin directly from GitHub:
426
+
427
+ ```bash
428
+ pip install 'ddgs>=9.0'
429
+ hermes plugins install JerryLiu369/agent-web-search --no-enable
430
+ hermes plugins enable agent-web-search --allow-tool-override
431
+ ```
432
+
433
+ The plugin intentionally replaces Hermes' built-in `web_search` tool, so the
434
+ explicit `--allow-tool-override` grant is required. Start a new Hermes session
435
+ after enabling it; restart the gateway when using a messaging channel.
436
+
437
+ Hermes can also connect through its generic MCP integration instead of the
438
+ native plugin.
439
+
440
+ ## CLI examples
441
+
442
+ ```bash
443
+ # Use every startup-enabled provider.
444
+ agent-web-search "What changed in the latest OpenAI Codex CLI?"
445
+
446
+ # Limit results and publication time.
447
+ agent-web-search "GPU kernel generation papers" --time-range m --max-results 5
448
+
449
+ # Select a provider subset for this request.
450
+ agent-web-search "latest AI news" --provider ark --provider ddgs
451
+ ```
452
+
453
+ ## Design principles
454
+
455
+ - **One core, multiple adapters.** MCP, Hermes, CLI, and Python use the same
456
+ search engine and response models.
457
+ - **Independent providers.** A failed provider does not discard successful
458
+ providers; all-provider failure is surfaced explicitly.
459
+ - **Transparent execution.** Responses expose `searched` and `model` instead of
460
+ treating every HTTP 200 as a completed search.
461
+ - **No shared secrets.** There is no telemetry or shared API-key service.
462
+
463
+ ## Development
464
+
465
+ Using [`uv`](https://docs.astral.sh/uv/) keeps the development environment
466
+ isolated and reproducible:
467
+
468
+ ```bash
469
+ git clone https://github.com/JerryLiu369/agent-web-search.git
470
+ cd agent-web-search
471
+ uv venv
472
+ uv pip install -e '.[dev]'
473
+ uv run pytest -q
474
+ uv run ruff check .
475
+ ```
476
+
477
+ <details>
478
+ <summary><strong>Standard venv + pip alternative</strong></summary>
479
+
480
+ ```bash
481
+ python -m venv .venv
482
+ # Linux/macOS: source .venv/bin/activate
483
+ # Windows PowerShell: .venv\Scripts\Activate.ps1
484
+ python -m pip install -e '.[dev]'
485
+ pytest -q
486
+ ruff check .
487
+ ```
488
+
489
+ </details>
490
+
491
+ ### Releasing to PyPI
492
+
493
+ Releases use PyPI Trusted Publishing, so no long-lived PyPI token is stored in
494
+ GitHub.
495
+
496
+ To publish a release:
497
+
498
+ 1. Update `version` in `pyproject.toml` and merge the change into `main`.
499
+ 2. Create a GitHub Release whose tag exactly matches that version with a `v`
500
+ prefix, for example `v0.1.0`.
501
+ 3. The release workflow builds and checks both distributions, then publishes
502
+ them to PyPI using GitHub's short-lived identity token.
503
+
504
+ ## License
505
+
506
+ [MIT](LICENSE)