# searxng-mcp

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/aicrafted/searxng-mcp  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/searxng-mcp

## Description
MCP server for SearXNG aggregator — web search across multiple engines via Model Context Protocol

## Claude Desktop Quick Installation
Heuristic fallback — verify the package name and runner against the repository README before running it. Uses `npx` (confidence: low):

```json
"mcpServers": {
  "searxng-mcp": {
    "command": "npx",
    "args": ["-y","searxng-mcp"]
  }
}
```

## Documentation & README

# SearXNG MCP Server

A Model Context Protocol (MCP) server that provides web search capabilities by integrating with a SearXNG instance.

## Features

- **Web Search**: Perform powerful aggregated searches across multiple engines.
- **Discovery**: Programmatically retrieve available categories and engines.
- **Stateless HTTP**: Compatible with any standard JSON-RPC client.
- **Flexible Configuration**: Supports environment variables and command-line arguments.

## Example of compose.yml to run SearXNG with MCP server 

```yaml
services:
  searxng:
    image: searxng/searxng:latest
    ports:
      - "${SEARXNG_PORT:-8080}:8080"
    volumes:
      - "${SEARXNG_VOL_CONFIG:-searxng-config}:/etc/searxng/"
      - "${SEARXNG_VOL_DATA:-searxng-data}:/var/cache/searxng/"
    restart: always

  searxng-mcp:
    image: ghcr.io/aicrafted/searxng-mcp:latest
    restart: unless-stopped
    depends_on:
      # Ensure SearXNG starts before the MCP server
      - searxng
    environment:
      SEARXNG_URL: "${SEARXNG_URL:-http://searxng:8080}"
      MCP_HOST: "${MCP_HOST:-127.0.0.1}"
      MCP_PORT: "${MCP_PORT:-32123}"
      MCP_TRANSPORT: "${MCP_TRANSPORT:-http}"
      MCP_ALLOWED_HOSTS: "${MCP_ALLOWED_HOSTS:-localhost:*,127.0.0.1:*}"
      MCP_ALLOWED_ORIGINS: "${MCP_ALLOWED_ORIGINS:-http://localhost:*,http://127.0.0.1:*}"
      MCP_DISABLE_DNS_REBINDING_PROTECTION: "${MCP_DISABLE_DNS_REBINDING_PROTECTION:-false}"
    ports:
      - "${MCP_PORT:-32123}:${MCP_PORT:-32123}"

volumes:
  searxng-config:
  searxng-data:
```

> **Important:** Enable JSON responses in your SearXNG `settings.yml`, otherwise the MCP server cannot read search results:
>
> ```yaml
> search:
>   formats:
>     - html
>     - json
> ```

### Example `.env`

```env
# SearXNG url should be visible by the MCP server inside docker, so use internal service port here
SEARXNG_URL=http://searxng:8080
# Public SearXNG port
SEARXNG_PORT=8080
# Searxng config and data volumes, start with "./" if You want to bind dir instead using volume
SEARXNG_VOL_CONFIG=searxng-config
SEARXNG_VOL_DATA=searxng-data

# MCP server host, port and transport ("stdio", "sse", "http")
MCP_HOST=127.0.0.1
MCP_PORT=32123
MCP_TRANSPORT=http

# MCP DNS rebinding protection (see https://github.com/modelcontextprotocol/python-sdk/issues/1798 for details)
MCP_ALLOWED_HOSTS=localhost:*,127.0.0.1:*
MCP_ALLOWED_ORIGINS=http://localhost:*,http://127.0.0.1:*
# MCP_DISABLE_DNS_REBINDING_PROTECTION=true
```

## MCP client config

### HTTP transport (recommended)
```JSON
{
  "mcpServers": {
    "searxng": {
      "type": "http",
      "url": "http://localhost:32123/mcp"
    }
  }
}
```

### SSE transport
```JSON
{
  "mcpServers": {
    "searxng": {
      "type": "sse",
      "url": "http://localhost:32123/sse"
    }
  }
}
```

> **Note:** SSE transport uses the `/sse` endpoint, not `/mcp`. HTTP transport uses `/mcp`.


## Prerequisites for run from sources

- Python 3.10+
- A running [SearXNG](https://github.com/searxng/searxng) instance.

## Installation

1. Clone the repository and navigate to the directory.
2. Install dependencies:
   ```bash
   pip install -r requirements.txt
   ```
3. Set up your `.env` file (optional).

## Configuration

The server reads configuration from command-line arguments and environment variables. Command-line arguments override the corresponding defaults used at startup.

| Variable | Default | Description |
| :--- | :--- | :--- |
| `SEARXNG_URL` | `http://localhost:8080` | URL of the SearXNG instance. |
| `SEARXNG_PORT` | `8080` | Public host port for the SearXNG container in the compose example. |
| `SEARXNG_VOL_CONFIG` | `searxng-config` | Docker volume or host path mounted to `/etc/searxng/` in the compose example. |
| `SEARXNG_VOL_DATA` | `searxng-data` | Docker volume or host path mounted to `/var/cache/searxng/` in the compose example. |
| `MCP_HOST` | `127.0.0.1` | Host to bind for HTTP/SSE transports. Use `0.0.0.0` in Docker when publishing the port. |
| `MCP_PORT` | `8000` | Port to bind for HTTP/SSE transports. |
| `MCP_TRANSPORT` | `stdio` | Transport mode: `stdio`, `http`, or `sse`. |
| `MCP_ALLOWED_HOSTS` | SDK defaults for localhost | Comma-separated allowed `Host` headers for DNS rebinding protection. |
| `MCP_ALLOWED_ORIGINS` | SDK defaults for localhost | Comma-separated allowed `Origin` headers for DNS rebinding protection. |
| `MCP_DISABLE_DNS_REBINDING_PROTECTION` | `false` | Set to `true` to disable the SDK DNS rebinding protection. |

## Usage

Run the server using `uv` or standard python:

```bash
python searxng_mcp.py --transport http --port 32123 --searxng http://searx.lan
```

### Run with Docker

1. **Build the image**:
   ```bash
   docker build -t searxng-mcp .
   ```

2. **Run the container**:
   ```bash
   docker run -d \
     -p 32123:32123 \
     --env-file .env \
     --name searxng-mcp \
     searxng-mcp
   ```

### Transport Options
- `stdio`: Standard input/output (default for some MCP clients).
- `http`: Stateless HTTP (streamable-http).
- `sse`: Server-Sent Events.

### DNS Rebinding Protection

Recent versions of the MCP Python SDK validate `Host` and `Origin` headers for HTTP/SSE transports to protect local servers from DNS rebinding attacks. If you expose the server through Docker, a reverse proxy, or a custom domain and receive `421 Invalid Host Header`, configure the allowlist explicitly:

```env
MCP_ALLOWED_HOSTS=localhost:*,127.0.0.1:*,mcp.example.com:*
MCP_ALLOWED_ORIGINS=http://localhost:*,http://127.0.0.1:*,https://mcp.example.com
```

For trusted local development or when this validation is handled by another infrastructure layer, you can disable the SDK protection:

```env
MCP_DISABLE_DNS_REBINDING_PROTECTION=true
```

Use disabling sparingly; setting `MCP_ALLOWED_HOSTS` and `MCP_ALLOWED_ORIGINS` is the recommended option.

---

# Search Abilities Guide

SearXNG aggregates results from various sources. This guide outlines the capabilities available through the `web_search` tool.

## Search Categories
Categories help refine your search by content type. Use these in the `categories` parameter (comma-separated).

| Category | Description |
| :--- | :--- |
| `general` | Default web search (Google, Brave, DuckDuckGo, etc.) |
| `images` | Image search results |
| `videos` | Video content from YouTube, Vimeo, etc. |
| `news` | Recent news articles |
| `map` | Geographical and map information |
| `it` | IT-related searches (StackOverflow, GitHub, etc.) |
| `science` | Scientific papers and articles (ArXiv, Google Scholar) |
| `files` | Torrent and file searches |
| `social_media` | Posts and profiles from social platforms |

## Supported Engines
SearXNG can query over 130 engines. Configured engines typically include:
- **Web**: Google, Brave, DuckDuckGo, Qwant, Startpage
- **Knowledge**: Wikipedia, Wikidata
- **Development**: GitHub, StackOverflow, PyPI
- **Social**: Reddit, Twitter/X

## Advanced Search Parameters
- **`categories`**: Filter by specific types (e.g., `news,it`).
- **`engines`**: Force specific engines (e.g., `google,wikipedia`).
- **`language`**: Specify search language (e.g., `en`, `es`, `fr`).
- **`pageno`**: Navigate through multiple pages of results.
- **`time_range`**: Filter by date (`day`, `month`, `year`).
- **`safesearch`**: Control content filtering (0=None, 1=Moderate, 2=Strict).

## Programmatic Discovery
Use the `web_search_info` tool to dynamically retrieve the list of enabled categories and engines from your instance.

# Windows Troubleshooting

## localhost not reachable while Docker container is running

**Symptom:** `http://localhost:<port>/` returns connection refused or hits the wrong service,
but `curl` from inside the container works fine.

**Root cause: WSL2 port relay ghost**

WSL2 automatically forwards ports from the Linux VM to the Windows host using `wslrelay.exe`.
When a process inside WSL listens on a port, WSL creates a relay bound to `[::1]:<port>`
(IPv6 loopback) on the Windows side.

When that WSL process stops, `wslrelay.exe` often **does not release the port**. The relay
entry stays alive as a zombie listener on `[::1]:<port>`.

Later, when Docker maps a container to the same host port, it binds correctly to
`0.0.0.0:<port>` — but `[::1]:<port>` is already taken by the stale relay.

On Windows, `localhost` resolves to `::1` (IPv6) first. So browser and curl requests to
`localhost:<port>` hit the dead `wslrelay.exe` entry instead of the Docker container,
resulting in a connection error or unexpected response.

Connecting via the explicit IPv4 address `127.0.0.1:<port>` bypasses the relay and reaches
Docker correctly.

**How to diagnose:**

```powershell
# Check what is listening on the port
netstat -ano | findstr :<port>

# Identify the processes
Get-Process -Id <pid1>,<pid2> | Select-Object Id,Name
```

If you see two entries for the same port — one owned by `com.docker.backend` and another
by `wslrelay` — this is the problem.

**Workarounds:**

| Option | Command | Notes |
|--------|---------|-------|
| Use IPv4 directly | `http://127.0.0.1:<port>/` | Immediate, no restart needed |
| Restart WSL | `wsl --shutdown` | Kills all stale relays; WSL restarts on next use |
| Remap Docker port | Change host port in `docker run -p` or `docker-compose.yml` | Avoids the conflict entirely |

**Permanent fix:**

After `wsl --shutdown`, restart the Docker container. The relay will no longer exist and
`localhost:<port>` will work normally until the same port is reused inside WSL again.

**Prevention:**

If you regularly run services on the same port both in WSL and in Docker, prefer one of:

- Always use Docker for that service, never WSL directly
- Use different ports for WSL dev and Docker prod instances
- Add `127.0.0.1:<port>:<port>` explicit binding in `docker-compose.yml` to force IPv4

---

## Related

- [WSL2 networking documentation](https://learn.microsoft.com/en-us/windows/wsl/networking)
- WSL GitHub issue tracker: search `wslrelay port leak`

