Hermes SearXNG MCP Server
Specialized content extraction for arXiv papers, returning LLM-ready Markdown content.
Specialized content extraction for GitHub Issues, converting issue pages into LLM-ready Markdown.
Provides web search and content retrieval through a self-hosted SearXNG instance, aggregating results from 70+ engines with support for categories, language, time filters, and full content extraction.
Specialized content extraction for Server Fault Q&A pages into Markdown.
Specialized content extraction for Stack Exchange network Q&A pages into Markdown.
Specialized content extraction for Stack Overflow questions and answers into Markdown.
Specialized content extraction for Super User Q&A pages into Markdown.
Specialized content extraction for Wikipedia articles, returning cleaned Markdown content.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Hermes SearXNG MCP Server Search the web for the latest breakthroughs in AI safety"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Hermes SearXNG MCP Server
Clean, production-ready MCP server for self-hosted SearXNG Designed for Hermes Agent, compatible with Claude Code, OpenClaw, and other MCP clients
Overview
This MCP server provides web search and content retrieval capabilities using a self-hosted SearXNG instance. It's designed to be a drop-in replacement for paid web search APIs, offering:
Privacy-preserving: Self-hosted, no data sent to third parties
Cost-free: No API keys, no rate limits
Flexible: 70+ search engines aggregated through SearXNG
MCP-compliant: Works with any MCP client (Hermes, Claude Desktop, OpenClaw, etc.)
Content extraction: Automatic Markdown extraction from search results
Related MCP server: SearXNG MCP Server
Features
Web Search (web_search)
Search across 70+ search engines via SearXNG
Support for multiple categories (general, news, images, videos, IT, science, etc.)
Language filtering
Time-based filtering (day, week, month, year)
Optional full content fetching for results
Content Retrieval (get_content)
Extract LLM-ready Markdown from any URL
Specialized handlers for:
GitHub Issues
Stack Exchange (Stack Overflow, Server Fault, Super User, etc.)
Wikipedia
arXiv
Universal fallback using Trafilatura + BeautifulSoup
Handles paywalls and anti-bot measures (best-effort)
News Search (search_news)
Convenience wrapper optimized for news articles
Default time filtering (last week)
Aggregates from news-focused search engines
Security & Production Features
SSRF Protection: Blocks private IPs, localhost, cloud metadata endpoints (169.254.169.254)
Input Validation: All tool parameters validated (query length, categories, language codes, time ranges)
Response Size Limits: Configurable max content size (default: 5MB) with streaming
Connection Pooling: Shared HTTP client with keep-alive connections and graceful shutdown
In-Memory Caching: 5-minute TTL cache for search results (100 entries max)
Docker Support: Multi-stage Dockerfile with docker-compose (includes SearXNG sidecar)
CI/CD: GitHub Actions workflow (Python 3.10/3.11/3.12, lint, typecheck, test)
Installation
From Source
# Clone the repository
git clone https://github.com/EmericLaberge/hermes-searxng-mcp.git
cd hermes-searxng-mcp
# Install in development mode
pip install -e .From PyPI (when published)
pip install hermes-searxng-mcp-serverConfiguration
SearXNG Instance
You need a running SearXNG instance. If you don't have one:
# Using Docker
docker run -d -p 8888:8080 \
-v $(pwd)/searxng:/etc/searxng \
searxng/searxng:latest
# Or follow the official guide:
# https://docs.searxng.org/admin/installation.htmlMake sure JSON output is enabled in your SearXNG settings.yml:
search:
formats:
- html
- json # Required!Environment Variables
Variable | Required | Default | Description |
| Yes | - | URL of your SearXNG instance (e.g., |
| No | 30 | Request timeout in seconds |
| No | Chrome UA | Custom User-Agent header |
| No | {} | JSON object with custom HTTP headers |
| No | 5242880 | Maximum content size in bytes (default: 5MB) |
| No | stdio | Transport type: |
| No | 0.0.0.0 | HTTP host (only for HTTP transport) |
| No | 8000 | HTTP port (only for HTTP transport) |
Proxy Support
The server supports proxy configuration through standard environment variables. Proxy handling is implemented natively by httpx via its trust_env feature (enabled by default).
Standard proxy variables:
Variable | Description |
| Proxy URL for HTTP requests (e.g., |
| Proxy URL for HTTPS requests (e.g., |
| Comma-separated list of hosts to bypass the proxy |
NO_PROXY patterns supported:
Exact host match:
localhost,searxng.localDomain suffix:
.example.com(matchesexample.com,www.example.com)Wildcard:
*(bypasses all hosts)Port-based:
localhost:8888
Proxy authentication:
Include credentials in the proxy URL:
export HTTP_PROXY="http://user:pass@proxy:8080"
export HTTPS_PROXY="http://user:pass@proxy:8080"TLS certificates:
For corporate proxies that inspect SSL traffic, configure custom CA certificates:
export SSL_CERT_FILE=/path/to/ca-bundle.crt
# or
export REQUESTS_CA_BUNDLE=/path/to/ca-bundle.crtNote: The proxy is used for outbound connections from the MCP server to SearXNG and fetched URLs. The SearXNG instance itself should be configured separately if it also needs proxy access.
Usage
With Hermes Agent
# Add the MCP server
hermes mcp add searxng \
--command python3 \
--args -m hermes_searxng_mcp.server
# Restart Hermes to load the server
hermes gateway restartThen in Hermes, just ask naturally:
You: Search for the latest news about AI
Hermes: [Uses search_news tool automatically]
You: Find documentation on FastAPI
Hermes: [Uses web_search tool automatically]
You: What's the content of https://example.com?
Hermes: [Uses get_content tool automatically]With Claude Desktop
Add to ~/.config/Claude/claude_desktop_config.json:
{
"mcpServers": {
"searxng": {
"command": "python3",
"args": ["-m", "hermes_searxng_mcp.server"],
"env": {
"SEARXNG_BASE_URL": "http://localhost:8888"
}
}
}
}Restart Claude Desktop.
With OpenClaw
Add to your OpenClaw MCP configuration:
mcp_servers:
searxng:
command: python3
args: ["-m", "hermes_searxng_mcp.server"]
env:
SEARXNG_BASE_URL: "http://localhost:8888"Standalone Testing
# Set environment variable
export SEARXNG_BASE_URL="http://localhost:8888"
# Run the server
python -m hermes_searxng_mcp.server
# In another terminal, test with MCP client
# or use curl for manual testing of SearXNG
curl "http://localhost:8888/search?q=test&format=json"With Docker
# Build and run with SearXNG sidecar
docker compose up -d
# Or build manually
docker build -t hermes-searxng-mcp .
docker run -e SEARXNG_BASE_URL=http://searxng:8080 hermes-searxng-mcpHTTP Transport
For remote access, set SEARXNG_TRANSPORT=http:
export SEARXNG_TRANSPORT=http
export SEARXNG_HOST=0.0.0.0
export SEARXNG_PORT=8000
python -m hermes_searxng_mcp.serverTest with curl:
curl http://localhost:8000/mcpTools Reference
web_search
Search the web and return results.
Parameters:
query(string, required): Search querynum_results(int, optional): Number of results (default: 5, max: 50)categories(string, optional): Category -general,news,images,videos,it,science,files,musiclanguage(string, optional): Language code (default:"en")time_range(string, optional): Time filter -day,week,month,yearinclude_content(bool, optional): Fetch full page content (default:false)
Returns:
{
"results": [
{
"title": "Result Title",
"url": "https://example.com",
"snippet": "Search snippet from SearXNG...",
"content": "# Full Markdown content...",
"engine": ["google", "bing"]
}
]
}get_content
Fetch a URL and extract Markdown content.
Parameters:
url(string, required): URL to fetch
Returns:
{
"url": "https://example.com",
"content": "# Extracted Markdown content..."
}search_news
Search recent news articles (convenience wrapper).
Parameters:
query(string, required): News topicnum_results(int, optional): Number of articles (default: 10)time_range(string, optional): Time filter (default:"week")language(string, optional): Language code (default:"en")
Returns: Same as web_search
Development
Setup
# Clone repository
git clone https://github.com/EmericLaberge/hermes-searxng-mcp.git
cd hermes-searxng-mcp
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install in development mode with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run linting
ruff check .
ruff format .Project Structure
hermes-searxng-mcp/
├── src/hermes_searxng_mcp/
│ ├── __init__.py # Package init
│ ├── server.py # MCP server, tools, and input validation
│ ├── searxng.py # SearXNG search with caching
│ ├── content_extractor.py # Content extraction with size limits
│ ├── http_client.py # Shared HTTP client (connection pooling)
│ ├── ssrf_protection.py # SSRF URL validation
│ ├── cache.py # In-memory TTL cache
│ └── models.py # Pydantic models
├── tests/ # Test suite (41 tests)
├── .github/workflows/ci.yml # CI/CD pipeline
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Docker Compose with SearXNG
├── pyproject.toml # Project configuration
├── README.md # This file
└── LICENSE # MIT licenseAdding New Features
Add specialized content handler: Extend
content_extractor.pywith new patternsAdd new search categories: Update
searxng.pyto support more SearXNG categoriesAdd new MCP tools: Add
@mcp.tool()decorators inserver.py
Troubleshooting
"SEARXNG_BASE_URL is not set"
Set the environment variable:
export SEARXNG_BASE_URL="http://localhost:8888""SearXNG returned 403 Forbidden"
JSON output is disabled in SearXNG. Enable it in settings.yml:
search:
formats:
- html
- json # Add this lineThen restart SearXNG.
"Could not fetch content"
This is normal for:
Paywalled content (NYT, WSJ, etc.)
Protected content (requires login)
Unsupported content types (PDFs, videos)
Bot detection (some sites block automated requests)
Tools not appearing in Hermes
# Check MCP server is running
hermes mcp list
# Test connection
hermes mcp test searxng
# Restart Hermes
hermes gateway restartSlow performance
Reduce
num_resultsparameterSet
include_content=False(default)Check SearXNG instance performance
Reduce
SEARXNG_TIMEOUT_SECONDSif network is slow
Comparison with Alternatives
Feature | Hermes SearXNG MCP | Serper/Tavily | Built-in Web Search |
Self-hosted | ✅ Yes | ❌ No | ❌ No |
Privacy | ✅ No data leaves | ❌ Sends to third-party | ❌ Sends to third-party |
Cost | ✅ Free | ❌ Paid | ❌ Paid (often) |
Rate Limits | ✅ None | ⚠️ Limited | ⚠️ Limited |
Search Engines | ✅ 70+ via SearXNG | ⚠️ Google only | ⚠️ Varies |
Content Extraction | ✅ Yes | ❌ No | ⚠️ Varies |
News Search | ✅ Yes | ✅ Yes | ⚠️ Varies |
MCP Compliant | ✅ Yes | ✅ Yes | ✅ Yes |
Docker Support | ✅ Yes | ❌ No | ❌ No |
SSRF Protection | ✅ Yes | ❌ No | ❌ No |
In-Memory Cache | ✅ Yes | ❌ No | ❌ No |
CI/CD | ✅ GitHub Actions | ⚠️ Varies | ⚠️ Varies |
Architecture
The server follows a clean, modular architecture:
┌─────────────────────────────────────────────────┐
│ MCP Client (Hermes) │
└───────────────────┬─────────────────────────────┘
│ MCP Protocol (stdio)
┌───────────────────▼─────────────────────────────┐
│ FastMCP Server Layer │
│ ┌──────────────────────────────────────────┐ │
│ │ @mcp.tool() Decorators │ │
│ │ - web_search() │ │
│ │ - get_content() │ │
│ │ - search_news() │ │
│ └──────────────────────────────────────────┘ │
└───────────────────┬─────────────────────────────┘
│
┌───────────┼───────────┐
│ │ │
┌───────▼──────┐ ┌─▼────────┐ ┌▼──────────────┐
│ SearXNG │ │ Content │ │ Models │
│ Search │ │ Extractor│ │ (Pydantic) │
│ + Cache │ │ + SSRF │ │ │
│ + Validation│ │ + Limits │ │ │
└──────────────┘ └──────────┘ └────────────────┘
│
▼
┌──────────────────────┐
│ SearXNG Instance │
│ (HTTP + JSON API) │
└──────────────────────┘Contributing
Contributions are welcome! Please:
Fork the repository
Create a feature branch
Make your changes
Add tests if applicable
Submit a pull request
License
MIT License - see LICENSE file for details.
Acknowledgments
Inspired by kindly-web-search-mcp-server
Built with FastMCP
Powered by SearXNG
Content extraction via Trafilatura and BeautifulSoup
Support
Issues: GitHub Issues
Discussions: GitHub Discussions
SearXNG Docs: https://docs.searxng.org/
MCP Protocol: https://modelcontextprotocol.io/
Available Tools
3 toolsget_contentA
Fetch a URL and extract LLM-ready Markdown content.
Use this when you already have a specific URL and want to read its content.
If you need to discover URLs first, use web_search() instead.
Args:
url: URL to fetch and extract content from.
Returns:
Dictionary with:
- url: The requested URL
- content: Extracted Markdown content
Example:
>>> await get_content("https://example.com")
{
"url": "https://example.com",
"content": "# Example DomainThis domain is for use in illustrative examples..." }
Notes:
- Specialized handlers for GitHub Issues, Stack Exchange, Wikipedia, and arXiv.
- Falls back to Trafilatura and BeautifulSoup for general websites.
- Content extraction is best-effort and may fail for paywalled or protected content.
- Some content types (PDFs, videos) may not be supported.
Raises:
ContentExtractionError: If fetching or extraction fails.
Inputs: url (required). Returns: object
search_newsA
Search recent news articles using SearXNG.
This is a convenience wrapper around web_search() optimized for news.
Args: query: News topic or event to search for. num_results: Number of articles to return (default: 10). time_range: Time filter (day, week, month, year). Defaults to "week". language: Language code for results (default: "en").
Returns: Dictionary with "results" list of news articles.
Example: >>> await search_news("artificial intelligence breakthrough", num_results=5) { "results": [ { "title": "Major AI Breakthrough Announced", "url": "https://example.com/ai-breakthrough", "snippet": "Researchers announce...", "content": "", "engine": ["google"] } ] }
Inputs: query (required), language, time_range, num_results. Returns: object
web_searchA
Search the web using SearXNG and return results.
This is the primary web search tool. Use it when you need to:
Find information on the web
Research a topic
Look up documentation
Debug errors (search for exact error messages)
Find GitHub issues or Stack Overflow threads
Args: query: Search query. Use specific keywords and quotes for exact phrases. num_results: Number of results to return (default: 5, max: 50). categories: Search category (general, news, images, videos, it, science, files, music). language: Language code (en, fr, es, de, etc.). time_range: Time filter (day, week, month, year) or None for no filter. include_content: If True, fetch and extract full page content for each result. This is slower but provides complete content without follow-up calls.
Returns: Dictionary with "results" list, where each result has: - title: Result title - url: Result URL - snippet: Search snippet from SearXNG - content: Full page content (if include_content=True, otherwise empty string) - engine: List of search engines that returned this result
Example: >>> await web_search("python async await", num_results=3) { "results": [ { "title": "Python Asyncio - Real Python", "url": "https://realpython.com/async-io-python/", "snippet": "Learn how to use Python's asyncio...", "content": "# Python Asyncio...", "engine": ["google", "bing"] } ] }
Notes: - Requires SEARXNG_BASE_URL environment variable to be set. - Content extraction is best-effort and may fail for paywalled or protected content. - For large num_results with include_content=True, this can be slow due to parallel fetching.
Inputs: query (required), language, categories, time_range, +2 more. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 3 tools
web_search and get_content are clearly distinct: one discovers URLs, the other fetches a known URL. search_news overlaps with web_search since it is a news-specific wrapper, but the descriptions clearly frame it as a convenience for news queries, so an agent can usually disambiguate.
All tool names follow the same lowercase snake_case verb_noun pattern: web_search, get_content, and search_news. There are no vague verbs or mixed naming conventions.
At 3 tools, the set is close to the ideal size and covers the core search-and-fetch workflow. search_news is somewhat redundant with web_search(categories='news'), so it does not fully earn its place, but the overall count is still reasonable.
The main workflow of discovering results and extracting page content is covered well. Minor gaps exist, such as pagination/offset for browsing deeper result sets, but agents can work around these via num_results and the supported categories.
Related MCP Connectors
Web search, URL content extraction to Markdown, site mapping, and recursive web crawler.
Web search, Google SERP, page extraction to markdown and cited answers for AI agents.
Web search and any page as LLM-ready Markdown for AI agents. Free keyless tier, no signup.
Search the web, fetch any URL and map a site as clean, LLM-ready Markdown.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to perform privacy-respecting web searches through SearXNG, with support for multiple search engines, categories, and advanced filtering options.203 npm27MIT
- AlicenseAqualityDmaintenanceEnables web search, image search, and news search through a self-hosted SearXNG instance. Provides privacy-focused meta-search capabilities aggregating results from multiple search engines.3203 npm1MIT
- AlicenseAqualityDmaintenanceEnables private web search and webpage content extraction using a local SearxNG instance, prioritizing user privacy and autonomy.22MIT
- FlicenseNot gradedqualityDmaintenanceEnables web search and content scraping from multiple engines via a local SearXNG instance, allowing AI assistants to retrieve and extract web content.1-