heventure-search-mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited heventure-search-mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A free MCP (Model Context Protocol) web search server with no API key required for core search.
Set these before starting the server to enable paid search engines:
| Variable | Required By | Free Tier | Get Key |
|---|---|---|---|
SERPAPI_KEY | serpapi engine | 100 req/month | serpapi.com |
TAVILY_API_KEY | tavily engine | 1000 req/month | tavily.com |
Note: Free engines (DuckDuckGo, Bing, Google) work without any API key. Without these env vars,serpapi/tavilyengines will silently fail.
Example:
export SERPAPI_KEY="your_key"
export TAVILY_API_KEY="your_key"Load this MCP server when any of the following conditions apply:
web-search as an MCP tool in Claude Desktop, Hermes Agent, Cursor, or similarget_webpage_content tool extracts text from URLsDo NOT load when:
web_search is already working and the user has no preference for MCP toolsfirecrawl-self-hosted skill instead)uvx heventure-search-mcppip install heventure-search-mcp
heventure-search-mcppip install git+https://github.com/HughesCuit/heventure-search-mcp.git
python -m server{
"mcpServers": {
"web-search": {
"command": "uvx",
"args": ["heventure-search-mcp"]
}
}
}{
"mcpServers": {
"web-search": {
"command": "python",
"args": ["-m", "server"]
}
}
}web_searchSearch the web with multiple engines.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | yes | — | Search query |
max_results | integer | no | 10 | Max results (1–20) |
search_engine | string | no | "both" | Engine: "duckduckgo" / "bing" / "google" (free) / "serpapi" (needs SERPAPI_KEY) / "tavily" (needs TAVILY_API_KEY) / "both" (free engines only) |
#### search_engine="both" behavior
When set to "both" (the default), the server:
asyncio.gatherSERPAPI_KEY, TAVILY_API_KEY) are setFor single-engine mode (e.g. "duckduckgo"), only that engine runs and results are returned as-is (no truncation).
get_webpage_contentFetch text content from a URL.
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | yes | Target webpage URL |
| Engine | Free | API Key | Notes |
|---|---|---|---|
| DuckDuckGo | ✅ | No | Default engine, great privacy |
| Bing | ✅ | No | Rich results, good for news |
| ✅ | No | Scraping-based, may hit rate limits | |
| SerpAPI | ❌ | Yes | Google API results, 100 free/month |
| Tavily | ❌ | Yes | AI-optimized, 1000 free/month |
The server detects CAPTCHA/challenge pages and gracefully degrades:
| Engine | Detection Method | Behavior |
|---|---|---|
| Bing | Scans HTML for challenge, solve the challenge, captcha (case-insensitive) | Returns empty results with warning log |
Scans HTML for captcha (case-insensitive) | Skips that domain, tries next domain variant (.com → .com.hk → .co.jp) |
CAPTCHA detection is a best-effort heuristic — it may not catch all challenge formats.
| Engine | Timeout | Notes |
|---|---|---|
| DuckDuckGo (API + HTML) | 10s | Per-request total timeout |
| Bing | 10s | Per-request total timeout, fallback to cn.bing.com on failure |
| 10s | Per-request total timeout, tries 3 domains in sequence | |
| SerpAPI | 30s | API call with JSON response |
| Tavily | 30s | API call with JSON response |
get_webpage_content | 10s | Single page fetch |
| Shared aiohttp session | 30s | Global fallback for any request without explicit timeout |
Two retry mechanisms exist, both with identical defaults:
| Method | Used By | Retries | Delay | Retryable Errors |
|---|---|---|---|---|
_safe_get_with_retry | Bing, Google | 1 (total 2 attempts) | 1.0s | TimeoutError, ClientError, ConnectionError, OSError |
_request_with_retry | DuckDuckGo (API + HTML) | 1 (total 2 attempts) | 1.0s | TimeoutError, ClientError, ConnectionError, OSError |
Paid engines (SerpAPI, Tavily) do NOT retry — they rely on their own API reliability.
| Scenario | Behavior |
|---|---|
| SSRF protection | Blocks private/loopback/link-local/reserved IPs. DNS rebinding: resolves hostname and checks resolved IPs before connecting. |
| Redirect loops | Tracks visited URLs, breaks on cycles. Bing-specific: strips mkt parameter and normalizes bing.com/cn.bing.com → www.bing.com. Max 5 redirects. |
| Unicode decode errors | Falls back to raw bytes.decode('utf-8', errors='replace') |
| Non-HTML content | get_webpage_content rejects PDF, images, etc. (checks Content-Type: text/html) |
| Empty response | Google skips pages shorter than 500 chars |
| Cache | 300s TTL, max 100 entries, LRU eviction. Avoids re-fetching within TTL window. |
| DuckDuckGo API fallback | If JSON API fails or returns empty, falls back to HTML scraping (html.duckduckgo.com) |
MIT
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.