fast-web-search-mcp 0.1.0
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.
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +581 -0
- package/dist/index.js +2540 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-07-13
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- MCP server with stdio transport
|
|
10
|
+
- `web_search` tool with DuckDuckGo + Bing fallback
|
|
11
|
+
- `news_search` tool for recent news articles
|
|
12
|
+
- `fetch_url` tool with SSRF protection and Readability extraction
|
|
13
|
+
- `search_and_fetch` combined research workflow
|
|
14
|
+
- `diagnostics` tool (disabled by default)
|
|
15
|
+
- DuckDuckGo HTML provider adapter
|
|
16
|
+
- Bing HTML provider adapter
|
|
17
|
+
- Wikipedia REST API provider
|
|
18
|
+
- SearXNG optional provider
|
|
19
|
+
- In-memory LRU cache with TTL
|
|
20
|
+
- Request coalescing for concurrent identical searches
|
|
21
|
+
- Per-provider rate limiting with exponential backoff
|
|
22
|
+
- Result deduplication and ranking
|
|
23
|
+
- Domain include/exclude filters
|
|
24
|
+
- URL canonicalization with tracking parameter removal
|
|
25
|
+
- Content extraction pipeline (Readability → fallback → Markdown)
|
|
26
|
+
- SSRF protection blocking private networks
|
|
27
|
+
- Structured error codes
|
|
28
|
+
- Environment-based configuration
|
|
29
|
+
- Comprehensive test suite (177 tests)
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 fast-web-search-mcp contributors
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">fast-web-search-mcp</h1>
|
|
3
|
+
<p align="center">
|
|
4
|
+
A production-ready Model Context Protocol server for free web search, news search, and webpage content extraction.
|
|
5
|
+
</p>
|
|
6
|
+
<p align="center">
|
|
7
|
+
<a href="#features">Features</a> ·
|
|
8
|
+
<a href="#quick-start">Quick Start</a> ·
|
|
9
|
+
<a href="#integration">Integration</a> ·
|
|
10
|
+
<a href="#configuration">Configuration</a> ·
|
|
11
|
+
<a href="#security">Security</a> ·
|
|
12
|
+
<a href="#documentation">Docs</a>
|
|
13
|
+
</p>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<img src="https://img.shields.io/badge/version-0.1.0-blue" alt="Version">
|
|
18
|
+
<img src="https://img.shields.io/badge/node-%3E%3D22-brightgreen" alt="Node.js">
|
|
19
|
+
<img src="https://img.shields.io/badge/license-MIT-green" alt="License">
|
|
20
|
+
<img src="https://img.shields.io/badge/tests-177%20passing-brightgreen" alt="Tests">
|
|
21
|
+
<img src="https://img.shields.io/badge/MCP-1.29.0-orange" alt="MCP SDK">
|
|
22
|
+
<img src="https://img.shields.io/badge/typescript-6.0-blue" alt="TypeScript">
|
|
23
|
+
<img src="https://img.shields.io/badge/build-passing-brightgreen" alt="Build">
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Why fast-web-search-mcp?
|
|
29
|
+
|
|
30
|
+
Most MCP search servers require paid API keys, Docker containers, or headless browsers. **fast-web-search-mcp** provides free, fast, local web search with zero external dependencies beyond Node.js.
|
|
31
|
+
|
|
32
|
+
| Capability | fast-web-search-mcp | Paid APIs | Headless Browser |
|
|
33
|
+
|------------|:-------------------:|:---------:|:----------------:|
|
|
34
|
+
| Free to use | ✅ | ❌ | ✅ |
|
|
35
|
+
| No API key | ✅ | ❌ | ✅ |
|
|
36
|
+
| No Docker | ✅ | ✅ | ❌ |
|
|
37
|
+
| Sub-second response | ✅ | ✅ | ❌ |
|
|
38
|
+
| SSRF protection | ✅ | N/A | ❌ |
|
|
39
|
+
| Result caching | ✅ | ❌ | ❌ |
|
|
40
|
+
| Multiple providers | ✅ | ❌ | ❌ |
|
|
41
|
+
| Works on Windows | ✅ | ✅ | ⚠️ |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- **Web Search** — DuckDuckGo primary with Bing fallback and Wikipedia reference lookup
|
|
48
|
+
- **News Search** — Date-sensitive news results with publication metadata
|
|
49
|
+
- **Page Fetching** — Readability extraction with Markdown or plain text output
|
|
50
|
+
- **Combined Research** — Search, rank, and fetch top results in one call
|
|
51
|
+
- **Intelligent Caching** — In-memory LRU cache with configurable TTL
|
|
52
|
+
- **Request Coalescing** — Deduplicates concurrent identical searches
|
|
53
|
+
- **Rate Limiting** — Per-provider throttling with exponential backoff
|
|
54
|
+
- **Result Deduplication** — URL canonicalization and title similarity matching
|
|
55
|
+
- **SSRF Protection** — Blocks private IPs, localhost, cloud metadata endpoints
|
|
56
|
+
- **Provider Fallback** — Automatic failover when a provider is unavailable
|
|
57
|
+
- **Zero Runtime Dependencies** — No Python, no Docker, no browser engine
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
### Install
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Global install (recommended)
|
|
67
|
+
npm install -g fast-web-search-mcp
|
|
68
|
+
|
|
69
|
+
# Or run directly without installing
|
|
70
|
+
npx -y fast-web-search-mcp
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Requirements
|
|
74
|
+
|
|
75
|
+
| Dependency | Version |
|
|
76
|
+
|------------|---------|
|
|
77
|
+
| Node.js | ≥ 22.0 |
|
|
78
|
+
| npm | ≥ 10.0 |
|
|
79
|
+
|
|
80
|
+
### Verify Installation
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Confirm the binary is available
|
|
84
|
+
fast-web-search-mcp --version
|
|
85
|
+
|
|
86
|
+
# Or run directly
|
|
87
|
+
npx fast-web-search-mcp --version
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Integration
|
|
93
|
+
|
|
94
|
+
Add `fast-web-search-mcp` to your AI coding assistant. Select your platform below:
|
|
95
|
+
|
|
96
|
+
<details>
|
|
97
|
+
<summary><strong>Claude Code</strong> (Anthropic CLI)</summary>
|
|
98
|
+
|
|
99
|
+
**Project scope** — add to `.claude/settings.json` in your project root:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"mcpServers": {
|
|
104
|
+
"fast-web-search": {
|
|
105
|
+
"command": "fast-web-search-mcp",
|
|
106
|
+
"env": {
|
|
107
|
+
"FWSMCP_LOG_LEVEL": "warn",
|
|
108
|
+
"FWSMCP_REDACT_QUERIES": "true"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**User scope** — add to `~/.claude/settings.json` for global availability:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"mcpServers": {
|
|
120
|
+
"fast-web-search": {
|
|
121
|
+
"command": "fast-web-search-mcp",
|
|
122
|
+
"env": {
|
|
123
|
+
"FWSMCP_DEFAULT_REGION": "us-en",
|
|
124
|
+
"FWSMCP_DEFAULT_LANGUAGE": "en",
|
|
125
|
+
"FWSMCP_REDACT_QUERIES": "true"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Or use the CLI:**
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
claude mcp add fast-web-search -- fast-web-search-mcp
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
> **Windows users:** Wrap the command with `cmd /c`:
|
|
139
|
+
> ```bash
|
|
140
|
+
> claude mcp add fast-web-search -- cmd /c fast-web-search-mcp
|
|
141
|
+
> ```
|
|
142
|
+
|
|
143
|
+
</details>
|
|
144
|
+
|
|
145
|
+
<details>
|
|
146
|
+
<summary><strong>Claude Desktop</strong> (Anthropic GUI)</summary>
|
|
147
|
+
|
|
148
|
+
Add to your configuration file:
|
|
149
|
+
|
|
150
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
151
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"mcpServers": {
|
|
156
|
+
"fast-web-search": {
|
|
157
|
+
"command": "fast-web-search-mcp",
|
|
158
|
+
"env": {
|
|
159
|
+
"FWSMCP_LOG_LEVEL": "warn",
|
|
160
|
+
"FWSMCP_DEFAULT_REGION": "us-en",
|
|
161
|
+
"FWSMCP_DEFAULT_LANGUAGE": "en"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Restart Claude Desktop after saving.
|
|
169
|
+
|
|
170
|
+
</details>
|
|
171
|
+
|
|
172
|
+
<details>
|
|
173
|
+
<summary><strong>OpenAI Codex CLI</strong></summary>
|
|
174
|
+
|
|
175
|
+
Add to `~/.codex/config.toml` (global) or `.codex/config.toml` (project):
|
|
176
|
+
|
|
177
|
+
```toml
|
|
178
|
+
[mcp_servers.fast-web-search]
|
|
179
|
+
command = "fast-web-search-mcp"
|
|
180
|
+
env = { FWSMCP_LOG_LEVEL = "warn", FWSMCP_REDACT_QUERIES = "true" }
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Or use the CLI:**
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
codex mcp add fast-web-search -- fast-web-search-mcp
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
</details>
|
|
190
|
+
|
|
191
|
+
<details>
|
|
192
|
+
<summary><strong>OpenCode</strong></summary>
|
|
193
|
+
|
|
194
|
+
Add to `~/.config/opencode/opencode.json`:
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"mcp": {
|
|
199
|
+
"fast-web-search": {
|
|
200
|
+
"type": "local",
|
|
201
|
+
"command": ["fast-web-search-mcp"],
|
|
202
|
+
"enabled": true,
|
|
203
|
+
"environment": {
|
|
204
|
+
"FWSMCP_DEFAULT_REGION": "us-en",
|
|
205
|
+
"FWSMCP_DEFAULT_LANGUAGE": "en",
|
|
206
|
+
"FWSMCP_REDACT_QUERIES": "true",
|
|
207
|
+
"FWSMCP_SAFE_SEARCH": "moderate"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
</details>
|
|
215
|
+
|
|
216
|
+
<details>
|
|
217
|
+
<summary><strong>Antigravity</strong> (Google IDE / CLI)</summary>
|
|
218
|
+
|
|
219
|
+
**Antigravity IDE:**
|
|
220
|
+
|
|
221
|
+
1. Click **...** in the agent side panel → **MCP Servers** → **Manage MCP Servers** → **View raw config**
|
|
222
|
+
2. Add the server to the opened `mcp_config.json` file
|
|
223
|
+
|
|
224
|
+
**Antigravity CLI:**
|
|
225
|
+
|
|
226
|
+
Type `/mcp` in the prompt panel to open the interactive MCP Manager.
|
|
227
|
+
|
|
228
|
+
**Configuration file:**
|
|
229
|
+
|
|
230
|
+
- **Global:** `~/.gemini/config/mcp_config.json`
|
|
231
|
+
- **Project:** `.agents/mcp_config.json`
|
|
232
|
+
|
|
233
|
+
```json
|
|
234
|
+
{
|
|
235
|
+
"mcpServers": {
|
|
236
|
+
"fast-web-search": {
|
|
237
|
+
"command": "fast-web-search-mcp",
|
|
238
|
+
"args": [],
|
|
239
|
+
"env": {
|
|
240
|
+
"FWSMCP_LOG_LEVEL": "warn",
|
|
241
|
+
"FWSMCP_REDACT_QUERIES": "true"
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
</details>
|
|
249
|
+
|
|
250
|
+
<details>
|
|
251
|
+
<summary><strong>Cursor</strong></summary>
|
|
252
|
+
|
|
253
|
+
Add to `~/.cursor/mcp.json`:
|
|
254
|
+
|
|
255
|
+
```json
|
|
256
|
+
{
|
|
257
|
+
"mcpServers": {
|
|
258
|
+
"fast-web-search": {
|
|
259
|
+
"command": "fast-web-search-mcp",
|
|
260
|
+
"env": {
|
|
261
|
+
"FWSMCP_LOG_LEVEL": "warn"
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
</details>
|
|
269
|
+
|
|
270
|
+
<details>
|
|
271
|
+
<summary><strong>VS Code / GitHub Copilot</strong></summary>
|
|
272
|
+
|
|
273
|
+
Add to `.vscode/mcp.json` in your workspace:
|
|
274
|
+
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
277
|
+
"servers": {
|
|
278
|
+
"fast-web-search": {
|
|
279
|
+
"command": "fast-web-search-mcp",
|
|
280
|
+
"env": {
|
|
281
|
+
"FWSMCP_LOG_LEVEL": "warn"
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
</details>
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## MCP Tools
|
|
293
|
+
|
|
294
|
+
| Tool | Description | Use Case |
|
|
295
|
+
|------|-------------|----------|
|
|
296
|
+
| `web_search` | Search the general web via DuckDuckGo + Bing fallback | General research, fact-finding |
|
|
297
|
+
| `news_search` | Search for recent news articles with publication dates | Current events, monitoring |
|
|
298
|
+
| `fetch_url` | Fetch a URL and extract clean Markdown or plain text | Article reading, documentation |
|
|
299
|
+
| `search_and_fetch` | Combined search + fetch workflow with character budget | Deep research, analysis |
|
|
300
|
+
| `diagnostics` | Return non-sensitive server diagnostics | Troubleshooting (disabled by default) |
|
|
301
|
+
|
|
302
|
+
### Tool Parameters
|
|
303
|
+
|
|
304
|
+
<details>
|
|
305
|
+
<summary><strong>web_search</strong></summary>
|
|
306
|
+
|
|
307
|
+
| Parameter | Type | Default | Description |
|
|
308
|
+
|-----------|------|---------|-------------|
|
|
309
|
+
| `query` | string | *required* | Search query (1-500 characters) |
|
|
310
|
+
| `max_results` | integer | 10 | Maximum results to return (1-25) |
|
|
311
|
+
| `strategy` | string | `"fallback"` | Provider strategy: `fallback` or `merge` |
|
|
312
|
+
| `region` | string | `"us-en"` | Region code for localized results |
|
|
313
|
+
| `language` | string | `"en"` | Language code |
|
|
314
|
+
| `time_range` | string | `"any"` | Time filter: `day`, `week`, `month`, `year`, `any` |
|
|
315
|
+
| `safe_search` | string | `"moderate"` | Content filter: `off`, `moderate`, `strict` |
|
|
316
|
+
| `include_domains` | array | — | Restrict results to these domains |
|
|
317
|
+
| `exclude_domains` | array | — | Exclude results from these domains |
|
|
318
|
+
| `deduplicate` | boolean | `true` | Remove duplicate results by URL |
|
|
319
|
+
| `timeout_ms` | integer | — | Operation timeout (1000-60000 ms) |
|
|
320
|
+
|
|
321
|
+
</details>
|
|
322
|
+
|
|
323
|
+
<details>
|
|
324
|
+
<summary><strong>news_search</strong></summary>
|
|
325
|
+
|
|
326
|
+
| Parameter | Type | Default | Description |
|
|
327
|
+
|-----------|------|---------|-------------|
|
|
328
|
+
| `query` | string | *required* | News search query (1-500 characters) |
|
|
329
|
+
| `max_results` | integer | 10 | Maximum results (1-25) |
|
|
330
|
+
| `time_range` | string | `"week"` | Time filter: `day`, `week`, `month` |
|
|
331
|
+
| `region` | string | `"us-en"` | Region code |
|
|
332
|
+
| `language` | string | `"en"` | Language code |
|
|
333
|
+
| `include_domains` | array | — | Restrict to these domains |
|
|
334
|
+
| `exclude_domains` | array | — | Exclude these domains |
|
|
335
|
+
|
|
336
|
+
</details>
|
|
337
|
+
|
|
338
|
+
<details>
|
|
339
|
+
<summary><strong>fetch_url</strong></summary>
|
|
340
|
+
|
|
341
|
+
| Parameter | Type | Default | Description |
|
|
342
|
+
|-----------|------|---------|-------------|
|
|
343
|
+
| `url` | string | *required* | HTTP/HTTPS URL to fetch |
|
|
344
|
+
| `output` | string | `"markdown"` | Output format: `markdown` or `text` |
|
|
345
|
+
| `max_characters` | integer | 20000 | Maximum characters (100-100000) |
|
|
346
|
+
| `include_metadata` | boolean | `true` | Include page metadata |
|
|
347
|
+
| `include_links` | boolean | `false` | Include extracted links |
|
|
348
|
+
| `timeout_ms` | integer | — | Fetch timeout (1000-60000 ms) |
|
|
349
|
+
|
|
350
|
+
</details>
|
|
351
|
+
|
|
352
|
+
<details>
|
|
353
|
+
<summary><strong>search_and_fetch</strong></summary>
|
|
354
|
+
|
|
355
|
+
| Parameter | Type | Default | Description |
|
|
356
|
+
|-----------|------|---------|-------------|
|
|
357
|
+
| `query` | string | *required* | Search query (1-500 characters) |
|
|
358
|
+
| `search_results` | integer | 8 | Number of results to consider (1-20) |
|
|
359
|
+
| `fetch_results` | integer | 3 | Number of pages to fetch (1-5) |
|
|
360
|
+
| `max_characters_per_page` | integer | 20000 | Character limit per page |
|
|
361
|
+
| `total_character_budget` | integer | 100000 | Total character budget |
|
|
362
|
+
| `timeout_ms` | integer | — | Total timeout (5000-120000 ms) |
|
|
363
|
+
|
|
364
|
+
</details>
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Configuration
|
|
369
|
+
|
|
370
|
+
All configuration is environment-based. No config files required.
|
|
371
|
+
|
|
372
|
+
| Variable | Default | Description |
|
|
373
|
+
|----------|---------|-------------|
|
|
374
|
+
| `FWSMCP_LOG_LEVEL` | `warn` | Log verbosity: `debug`, `info`, `warn`, `error` |
|
|
375
|
+
| `FWSMCP_LOG_FORMAT` | `text` | Log format: `text` or `json` |
|
|
376
|
+
| `FWSMCP_REDACT_QUERIES` | `true` | Redact search queries in logs |
|
|
377
|
+
| `FWSMCP_DEFAULT_REGION` | `us-en` | Default region for searches |
|
|
378
|
+
| `FWSMCP_DEFAULT_LANGUAGE` | `en` | Default language for searches |
|
|
379
|
+
| `FWSMCP_SAFE_SEARCH` | `moderate` | Safe search level: `off`, `moderate`, `strict` |
|
|
380
|
+
| `FWSMCP_PROVIDERS` | `duckduckgo,bing,wikipedia` | Comma-separated provider list |
|
|
381
|
+
| `FWSMCP_PROVIDER_STRATEGY` | `fallback` | Strategy: `fallback` (sequential) or `merge` (parallel) |
|
|
382
|
+
| `FWSMCP_SEARCH_TIMEOUT_MS` | `20000` | Search operation timeout (ms) |
|
|
383
|
+
| `FWSMCP_PROVIDER_TIMEOUT_MS` | `10000` | Per-provider timeout (ms) |
|
|
384
|
+
| `FWSMCP_FETCH_TIMEOUT_MS` | `15000` | Page fetch timeout (ms) |
|
|
385
|
+
| `FWSMCP_RESEARCH_TIMEOUT_MS` | `45000` | search_and_fetch total timeout (ms) |
|
|
386
|
+
| `FWSMCP_MAX_SEARCH_RESULTS` | `25` | Maximum results per search |
|
|
387
|
+
| `FWSMCP_MAX_FETCH_CHARACTERS` | `100000` | Maximum characters per fetch |
|
|
388
|
+
| `FWSMCP_CACHE_ENABLED` | `true` | Enable in-memory result cache |
|
|
389
|
+
| `FWSMCP_CACHE_MAX_ENTRIES` | `250` | Maximum cache entries |
|
|
390
|
+
| `FWSMCP_SEARCH_CACHE_TTL_MS` | `900000` | Search cache TTL (15 min) |
|
|
391
|
+
| `FWSMCP_NEWS_CACHE_TTL_MS` | `300000` | News cache TTL (5 min) |
|
|
392
|
+
| `FWSMCP_PAGE_CACHE_TTL_MS` | `1800000` | Page cache TTL (30 min) |
|
|
393
|
+
| `FWSMCP_SEARXNG_URL` | — | Optional SearXNG instance URL |
|
|
394
|
+
| `FWSMCP_DIAGNOSTICS_ENABLED` | `false` | Enable diagnostics tool |
|
|
395
|
+
| `FWSMCP_GLOBAL_EXCLUDE_DOMAINS` | — | Comma-separated domains to always exclude |
|
|
396
|
+
| `FWSMCP_CONFIG_FILE` | — | Path to optional JSON config file |
|
|
397
|
+
|
|
398
|
+
### Optional JSON Configuration
|
|
399
|
+
|
|
400
|
+
For complex setups, point `FWSMCP_CONFIG_FILE` to a JSON file:
|
|
401
|
+
|
|
402
|
+
```json
|
|
403
|
+
{
|
|
404
|
+
"defaults": {
|
|
405
|
+
"region": "us-en",
|
|
406
|
+
"language": "en",
|
|
407
|
+
"safeSearch": "moderate"
|
|
408
|
+
},
|
|
409
|
+
"providers": {
|
|
410
|
+
"order": ["duckduckgo", "bing", "wikipedia"],
|
|
411
|
+
"strategy": "fallback"
|
|
412
|
+
},
|
|
413
|
+
"cache": {
|
|
414
|
+
"enabled": true,
|
|
415
|
+
"maxEntries": 250,
|
|
416
|
+
"searchTtlMs": 900000
|
|
417
|
+
},
|
|
418
|
+
"limits": {
|
|
419
|
+
"maxSearchResults": 25,
|
|
420
|
+
"maxFetchCharacters": 100000
|
|
421
|
+
},
|
|
422
|
+
"privacy": {
|
|
423
|
+
"redactQueriesInLogs": true
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
> **Priority:** Environment variables > JSON config file > defaults.
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Architecture
|
|
433
|
+
|
|
434
|
+
```
|
|
435
|
+
┌─────────────────────────────────────────────────────────┐
|
|
436
|
+
│ MCP Client │
|
|
437
|
+
│ (Claude Code / Codex / OpenCode) │
|
|
438
|
+
└─────────────────────┬───────────────────────────────────┘
|
|
439
|
+
│ stdio (JSON-RPC)
|
|
440
|
+
▼
|
|
441
|
+
┌─────────────────────────────────────────────────────────┐
|
|
442
|
+
│ fast-web-search-mcp │
|
|
443
|
+
│ │
|
|
444
|
+
│ ┌─────────┐ ┌──────────┐ ┌───────────┐ ┌────────┐ │
|
|
445
|
+
│ │ Tools │ │ Cache │ │ Coalescer │ │ Limiter│ │
|
|
446
|
+
│ │ 5 tools │ │ LRU+TTL │ │ Dedup │ │ Per- │ │
|
|
447
|
+
│ │ │ │ │ │ inflight │ │ provider│ │
|
|
448
|
+
│ └────┬─────┘ └──────────┘ └───────────┘ └────────┘ │
|
|
449
|
+
│ │ │
|
|
450
|
+
│ ▼ │
|
|
451
|
+
│ ┌─────────────────────────────────────────────────┐ │
|
|
452
|
+
│ │ Orchestrator Pipeline │ │
|
|
453
|
+
│ │ Validate → Cache → Coalesce → Select → Execute │ │
|
|
454
|
+
│ │ → Normalize → Filter → Dedup → Rank → Return │ │
|
|
455
|
+
│ └─────────────────────┬───────────────────────────┘ │
|
|
456
|
+
│ │ │
|
|
457
|
+
│ ┌────────────────┼────────────────┐ │
|
|
458
|
+
│ ▼ ▼ ▼ │
|
|
459
|
+
│ ┌─────────┐ ┌──────────┐ ┌────────────┐ │
|
|
460
|
+
│ │ DuckDuck │ │ Bing │ │ Wikipedia │ │
|
|
461
|
+
│ │ Go │ │ │ │ REST API │ │
|
|
462
|
+
│ │ (HTML) │ │ (HTML) │ │ │ │
|
|
463
|
+
│ └─────────┘ └──────────┘ └────────────┘ │
|
|
464
|
+
│ │ │ │
|
|
465
|
+
│ ▼ ▼ │
|
|
466
|
+
│ ┌─────────────────────────────────────────────────┐ │
|
|
467
|
+
│ │ HTTP Client (Node fetch) │ │
|
|
468
|
+
│ │ Timeout · Body Limit · Redirect · SSRF Block │ │
|
|
469
|
+
│ └─────────────────────────────────────────────────┘ │
|
|
470
|
+
└─────────────────────────────────────────────────────────┘
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Security
|
|
476
|
+
|
|
477
|
+
### Protections
|
|
478
|
+
|
|
479
|
+
| Threat | Mitigation |
|
|
480
|
+
|--------|------------|
|
|
481
|
+
| SSRF / private network access | Blocks localhost, RFC1918, link-local, cloud metadata IPs |
|
|
482
|
+
| Credential leakage | Rejects URLs with embedded username/password |
|
|
483
|
+
| Query exposure | Logs redact queries by default (`FWSMCP_REDACT_QUERIES=true`) |
|
|
484
|
+
| Prompt injection via fetched content | Includes untrusted content warning in all fetch results |
|
|
485
|
+
| Uncontrolled resource consumption | Body size limits, timeout enforcement, character budgets |
|
|
486
|
+
| Process isolation | stdio transport only — no network listener, no HTTP endpoint |
|
|
487
|
+
|
|
488
|
+
### Disabled by Default
|
|
489
|
+
|
|
490
|
+
- **Diagnostics tool** — must be explicitly enabled via `FWSMCP_DIAGNOSTICS_ENABLED=true`
|
|
491
|
+
- **SearXNG integration** — requires explicit `FWSMCP_SEARXNG_URL` configuration
|
|
492
|
+
|
|
493
|
+
See [docs/SECURITY.md](docs/SECURITY.md) for the full threat model.
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## Development
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
git clone https://github.com/your-org/fast-web-search-mcp.git
|
|
501
|
+
cd fast-web-search-mcp
|
|
502
|
+
npm ci
|
|
503
|
+
npm run build
|
|
504
|
+
npm test
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Available Scripts
|
|
508
|
+
|
|
509
|
+
| Script | Description |
|
|
510
|
+
|--------|-------------|
|
|
511
|
+
| `npm run build` | Production build with tsup |
|
|
512
|
+
| `npm run dev` | Development mode with tsx |
|
|
513
|
+
| `npm test` | Run full test suite (177 tests) |
|
|
514
|
+
| `npm run test:unit` | Unit tests only |
|
|
515
|
+
| `npm run test:security` | Security tests only |
|
|
516
|
+
| `npm run typecheck` | TypeScript type checking |
|
|
517
|
+
| `npm run lint` | ESLint |
|
|
518
|
+
| `npm run format` | Prettier formatting |
|
|
519
|
+
|
|
520
|
+
### Project Structure
|
|
521
|
+
|
|
522
|
+
```
|
|
523
|
+
fast-web-search-mcp/
|
|
524
|
+
├── src/
|
|
525
|
+
│ ├── cache/ # LRU cache, cache key generation
|
|
526
|
+
│ ├── config/ # Defaults, env parsing, config loader
|
|
527
|
+
│ ├── fetch/ # URL validation, content extraction, Markdown
|
|
528
|
+
│ ├── http/ # HTTP client, errors, headers
|
|
529
|
+
│ ├── observability/ # Structured stderr logger
|
|
530
|
+
│ ├── providers/ # DuckDuckGo, Bing, Wikipedia, SearXNG
|
|
531
|
+
│ ├── schemas/ # Zod validation schemas
|
|
532
|
+
│ ├── search/ # Orchestrator, coalescer, rate limiter, dedup
|
|
533
|
+
│ ├── server/ # MCP server factory, tool registration
|
|
534
|
+
│ ├── tools/ # 5 MCP tool implementations
|
|
535
|
+
│ ├── utils/ # Domain, text, date, async utilities
|
|
536
|
+
│ └── index.ts # Entry point
|
|
537
|
+
├── test/
|
|
538
|
+
│ ├── fixtures/ # HTML fixtures for parser tests
|
|
539
|
+
│ └── unit/ # Unit tests (177 tests)
|
|
540
|
+
├── docs/ # Documentation and ADRs
|
|
541
|
+
└── examples/ # Config examples
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
546
|
+
## Documentation
|
|
547
|
+
|
|
548
|
+
| Document | Description |
|
|
549
|
+
|----------|-------------|
|
|
550
|
+
| [Configuration Reference](docs/CONFIGURATION.md) | All environment variables and options |
|
|
551
|
+
| [Provider Guide](docs/PROVIDERS.md) | Provider details, strategy, and SearXNG setup |
|
|
552
|
+
| [Security Model](docs/SECURITY.md) | Threat model and protections |
|
|
553
|
+
| [Troubleshooting](docs/TROUBLESHOOTING.md) | Common issues and debugging |
|
|
554
|
+
| [OpenCode Integration](docs/OPENCODE.md) | OpenCode-specific setup guide |
|
|
555
|
+
| [Changelog](CHANGELOG.md) | Version history |
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
## Roadmap
|
|
560
|
+
|
|
561
|
+
- [ ] SQLite persistent cache
|
|
562
|
+
- [ ] Brave Search provider
|
|
563
|
+
- [ ] Image search support
|
|
564
|
+
- [ ] Streamable HTTP transport
|
|
565
|
+
- [ ] Result scoring customization
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
## Contributing
|
|
570
|
+
|
|
571
|
+
1. Fork the repository
|
|
572
|
+
2. Create a feature branch (`git checkout -b feature/amazing`)
|
|
573
|
+
3. Commit changes (`git commit -m 'feat: add amazing feature'`)
|
|
574
|
+
4. Push to branch (`git push origin feature/amazing`)
|
|
575
|
+
5. Open a Pull Request
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
## License
|
|
580
|
+
|
|
581
|
+
MIT License. See [LICENSE](LICENSE) for details.
|