searxng-bearer-mcp
v1.0.0
Published
MCP server exposing a SearXNG web-search tool that authenticates to SearXNG with an Authorization: Bearer token — for SearXNG behind Traefik + forwarded-auth using a passphrase bearer token.
Maintainers
Readme
searxng-bearer-mcp
An MCP server that exposes a SearXNG web-search tool, authenticating to the SearXNG instance with an HTTP Authorization: Bearer <token> header.
This exists because every maintained SearXNG MCP server only supports HTTP Basic auth — none supports a bearer/custom Authorization header. If your SearXNG sits behind Traefik + a forward-auth middleware that gates access with a passphrase bearer token, this server lets an MCP-aware client (Claude Code, etc.) search it using that passphrase.
How this fits with forwarded-auth
This package is the missing link for setups using cbrown350/forwarded-auth — a Traefik forward-auth middleware that protects services with a passphrase bearer token (the ?pf= query param or, since v1.1.3, an Authorization: Bearer <passphrase> header). Without an auth layer that accepts a bearer token this server is not useful; forwarded-auth is the canonical one it was built for.
Two things must be true on your deployment for this server to work:
- SearXNG must return JSON. Enable the JSON output format in SearXNG's
settings.yml:search: formats: [html, json] - Traefik must forward the
Authorizationheader to the auth server. The protected service's middleware label must includeAuthorization:
(Whentraefik.http.middlewares.<name>.forwardauth.authRequestHeaders=cookie,Authorization,cf-connecting-ipauthRequestHeadersis set, Traefik only forwards the listed headers — soAuthorizationmust be listed explicitly, or the bearer token never reaches forwarded-auth.)
See the forwarded-auth README for the full Traefik label reference.
Prerequisites
- Node 20 or later.
- A SearXNG instance with JSON output enabled and (if protected) an auth layer that accepts a bearer token, e.g. forwarded-auth.
Tools provided
This MCP server exposes a single tool:
searxng_search
Search the web via your SearXNG instance and return ranked results with titles, URLs, engines, and short content snippets, plus any direct answers and suggestions. Read-only.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| query | string | yes | The search query (1–200 chars). |
| categories | string | no | Comma-separated SearXNG categories, e.g. general, it, news, science, images, files. |
| language | string | no | Result language code, e.g. en, de, all. |
| time_range | day | week | month | year | no | Restrict results to a time window. |
| pageno | number (1–10) | no | Result page (1-based) for pagination. |
| max_results | number (1–50) | no | Max results returned (default 10). Raise for broader coverage. |
| response_format | markdown | json | no | markdown (default) is human-readable; json is structured. |
Returns
- markdown (default): a numbered list of results (title, URL, engine, snippet), plus direct answers and suggestions.
- json: an object
{ query, count, answers, suggestions, results: [{title, url, content, engine, category, publishedDate}], unresponsive_engines }.
Output is truncated to protect the client's context budget.
Installation
Use from npm (after publish)
No clone or build needed — npx fetches it:
npx -y searxng-bearer-mcpFrom source (development)
git clone https://github.com/cbrown350/searxng-bearer-mcp.git
cd searxng-bearer-mcp
npm install
npm run build # outputs dist/index.jsConfiguration
| Env var | Required | Default | Description |
|---|---|---|---|
| SEARXNG_URL | yes | — | Base URL of your SearXNG instance, e.g. https://searxng.example.com (no trailing slash, no /search). |
| SEARXNG_BEARER_TOKEN | yes | — | Passphrase sent as Authorization: Bearer <token>. |
| SEARXNG_TIMEOUT_MS | no | 15000 | Request timeout in milliseconds. |
Use with Claude Code
This uses the stdio transport (command/args) — not the http/url form. Claude Code launches this server as a subprocess and speaks MCP over stdin/stdout. Do not point an MCP http client at the SearXNG URL directly; SearXNG is a website, not an MCP server.
Via npx (recommended, from the registry)
Add to your Claude Code MCP config (~/.claude.json, or a project .mcp.json):
{
"mcpServers": {
"searxng": {
"command": "npx",
"args": ["-y", "searxng-bearer-mcp"],
"env": {
"SEARXNG_URL": "https://searxng.example.com",
"SEARXNG_BEARER_TOKEN": "my-secret-token"
}
}
}
}Or add it via the CLI:
claude mcp add searxng -s user \
-e SEARXNG_URL=https://searxng.example.com \
-e SEARXNG_BEARER_TOKEN=my-secret-token \
-- npx -y searxng-bearer-mcpVia a local build
{
"mcpServers": {
"searxng": {
"command": "node",
"args": ["/absolute/path/to/searxng-bearer-mcp/dist/index.js"],
"env": {
"SEARXNG_URL": "https://searxng.example.com",
"SEARXNG_BEARER_TOKEN": "my-secret-token"
}
}
}
}After adding it, run claude mcp list (or restart Claude Code) — you should see searxng ✔ Connected with the searxng_search tool.
Security note
SEARXNG_BEARER_TOKEN is stored in plaintext in the MCP config. The passphrase only grants search access (not user management), so it is the right secret to place in a config file — but keep the config file's permissions restricted, and prefer a dedicated low-privilege secret over reusing an admin credential.
Error behavior
- Auth failure / redirect — forwarded-auth bounces the request (307 to the auth-fail URL); this server detects the redirect and returns a clear message pointing at the token and the Traefik
authRequestHeaderslabel. - 401/403 — token rejected.
- 429 — rate limited; wait and retry or narrow the query.
- Non-JSON response — JSON output is disabled on the instance; enable it in
settings.yml. - Timeout — the request exceeded
SEARXNG_TIMEOUT_MS.
Error responses are returned as MCP isError results with actionable text; the token itself is never echoed.
Development
npm run build # tsc -> dist/
npm test # build + vitest (unit + stdio integration)
npm run test:watchThe unit tests mock fetch (no network). The integration test spawns the built server over stdio against an in-process mock SearXNG and asserts the Authorization: Bearer header is actually sent.
Releasing
Releases are tagged v<semver>. Pushing a tag triggers CI to build, test, and create a GitHub Release with auto-generated notes. Publishing to npm is done manually (npm publish) — see CHANGELOG.md.
License
MIT © Clifford B. Brown
