dsh-searxng-web
Archivedmaxwell-feng/dsh-searxng-web
DeepSeek Harness plugin: back the native web_search / web_fetch tools with your self-hosted SearXNG instance — keyless, private, no third-party search vendor.
This repository is archived — it is read-only and no longer maintained. Review the code carefully before installing.
$ dsh plugin add dsh-searxng-webInstall
dsh has no central install command — add this plugin’s entry (documented in its README below) to your profile or patch config, then restart.
How installs work7
stars
2
forks
TypeScript
Language
MIT
License
2026-08-22
Created
2026-09-13
Last push
README
dsh-searxng-web
English | 简体中文
DeepSeek Harness plugin
that backs the native web_search / web_fetch tools with your own
self-hosted SearXNG instance — keyless, private,
no third-party search vendor.
model ── web_search ──▶ ctx.web ──▶ searxng-web provider ──▶ your SearXNG ──▶ engines
model ── web_fetch ──▶ ctx.web ──▶ searxng-web-fetch ──▶ target page (SSRF-guarded)
Why
- dsh ships
web_searchpointed at the DeepSeek cloud search, and mounts no fetch provider at all. If you run SearXNG for privacy or offline use, your queries still leak to a vendor — until this bundle is installed. - Unlike an MCP server integration, this rides dsh's own provider seam: the
model keeps using the short native tool names (
web_search,web_fetch), every agent and subagent inherits it, and nothing extra runs alongside dsh.
Requirements
- Node.js ≥ 22
- DeepSeek Harness
dshinstalled (verified on0.1.5-rc.2, latest release) - A reachable SearXNG instance with JSON output enabled
(
settings.yml→search.formats: [html, json]), verified by:
Documentation
-
curl 'http://YOUR_SEARXNG:8080/search?q=test&format=json'
Install
From npm (recommended)
dsh plugin --profile web add dsh-searxng-web
(Replace web with your profile, e.g. tui.) Published from CI with
Sigstore provenance; the package ships a prebuilt lib/, so nothing needs
to be compiled or allowlisted on install.
or from the repository / a tarball:
dsh plugin --profile web add ./dsh-searxng-web # source checkout
dsh plugin --profile web add ./dsh-searxng-web-1.0.0.tgz
dsh plugin --profile web add github:maxwell-feng/dsh-searxng-web
# or pin a commit:
dsh plugin --profile web add github:maxwell-feng/dsh-searxng-web#<sha>
Git installs fetch sources: the repository commits the compiled
lib/output, so git installs load without waiting on a registry — thepreparescript (npm run build) rebuildslib/from source after install. pnpm refuses to run a git dependency'sprepareuntil it is allowlisted; if the firstaddfails, copy the exact package key pnpm printed into the profile'spnpm-workspace.yamland re-run theadd. See the Installation Guide.
Upgrading
dsh plugin --profile web add dsh-searxng-web@latest
# or from git, to pick up changes before they reach npm:
dsh plugin --profile web add github:maxwell-feng/dsh-searxng-web
0.2.x configurations keep working unchanged — every field added since is
optional with identical defaults. Since 0.3.0 configuration is validated at
load time (Schemastery schema), a mistyped key fails the boot with an
actionable error instead of being silently ignored. 0.4.0 adds the optional
baseUrls failover list; single-baseUrl setups are unaffected. 0.5.0
adapts to deepseek-harness 0.1.2-alpha.1 (fiber-scoped provider
disposers, post-redirect url reporting) — no config changes required.
0.5.3 adapts to deepseek-harness 0.1.2-alpha.2 — the seam and config
rows are unchanged, only the dependency pins move.
0.5.4 adapts to deepseek-harness 0.1.2-alpha.3 — packages/web moved
only its version pins in that release, so again no config changes required.
0.5.5 verifies against 0.1.2-alpha.4 (latest master): seam unchanged,
no config migration.
0.6.0 adapts to deepseek-harness 0.1.5-alpha.1: seam unchanged, adds a
standard prepare build script and the standalone
CONFIG / UPDATE / UNINSTALL doc suite — no config changes required.
0.7.0 verifies against deepseek-harness 0.1.5-rc.1: the ctx.web
provider seam (packages/web/web/src) is source-identical, vendored
@deepseek-ai/cordis 4.0.2 / @deepseek-ai/schemastery 3.18.2
unchanged — no code or config migration required. Node floor raised to
>=22 (harness floor is ^22.19). Adds INSTALL / USAGE guides and
rewrites CONFIG against the actual schema.
0.8.0 verifies against deepseek-harness 0.1.5-rc.2: adds manifestVersion: 1
under package.json.dsh conforming to @deepseek-ai/dsh-package-manifest
and declares "engines.dsh": "^0.1.5-rc.2".
1.0.0 refactors the codebase into pure TypeScript (zero JavaScript tracked),
running tests natively via Node --experimental-strip-types.
Installing does three things (via the bundled patch layer):
- inserts the
searxng-webplugin row; - points
ctx.webat its search/fetch providers; - re-enables
web_fetch(tool-web.fetch).
Then boot as usual:
dsh --profile web
Usage
New sessions now answer "search xxx" through your instance — no tool-name changes:
web_search→ctx.web→searxng-web→ your SearXNG → configured enginesweb_fetch→ctx.web→searxng-web-fetch→ target page (SSRF-guarded, HTML→text)
Verify any time:
dsh --profile web --dump-config | grep -A5 searxng
# or inside a session: call web_search "test" and inspect sources[].url
GUI: Settings → Web Search shows provider readiness.
Pointing at your instance
The default base URL is http://127.0.0.1:8080. Override it (and anything
else) in your profile's cordis.patch.yml — the user layer applies after
bundle layers:
- id: searxng-web
config:
baseUrl: 'http://10.42.1.159:8080'
timeoutMs: 15000 # per-search budget, ms
fetchTimeoutMs: 30000 # per-fetch budget, ms
fetchMaxChars: 200000 # cap on web_fetch output characters
ssrfGuard: true # refuse private/loopback fetch targets
search: # forwarded to SearXNG on every query (all optional)
language: '' # e.g. 'zh-CN', 'en'
safesearch: 0 # 0 off, 1 moderate, 2 strict
# categories: 'general' # 'news', 'it,science', ...
# engines: '' # 'google,bing,ddg', ...
# timeRange: '' # 'day' | 'week' | 'month' | 'year'
Patch rows replace config wholesale (no deep merge) — restate keys you want to keep when overriding.
Triple-stack endpoints with automatic failover (0.4.0+)
Home instances often live behind several doors at once — a public IPv4, a
public IPv6 and a LAN address. baseUrls takes an ordered list and fails
over automatically:
- id: searxng-web
config:
baseUrls:
- 'http://203.0.113.10:8081/s/<KEY>' # public IPv4
- 'http://[2409:8a55:…]:8081/s/<KEY>' # public IPv6
- 'http://192.168.10.144:8081/s/<KEY>' # LAN (same door, same key)
timeoutMs: 15000
Semantics:
- Sticky: attempts always start at the last endpoint that succeeded, so a healthy door is never re-probed after an earlier entry had a hiccup.
- Fail fast on the wire only: connection refused / unreachable / timeout / DNS failure advance to the next endpoint. Any HTTP answer (200, 403, 502…) proves that door is alive and its status is surfaced as-is — no silent masking of auth problems.
- One full pass over the list per call; if every endpoint is unreachable you
get a single
networkerror. baseUrlswins when both it andbaseUrlare set;baseUrlalone keeps working exactly as before.
Configuration reference
| Key | Default | Description |
|---|---|---|
baseUrl |
http://127.0.0.1:8080 |
SearXNG instance URL |
baseUrls |
(unset) | Ordered endpoint list with sticky automatic failover (0.4.0+); takes precedence over baseUrl when non-empty — see "Triple-stack endpoints" above |
timeoutMs |
15000 |
Per-search attempt budget (ms) |
fetchTimeoutMs |
30000 |
Per-fetch attempt budget (ms) |
fetchMaxChars |
200000 |
Max characters returned by web_fetch |
ssrfGuard |
true |
Refuse private/loopback/link-local/CGNAT fetch targets |
search.language |
(unset) | SearXNG language param |
search.safesearch |
0 |
SearXNG safesearch param |
search.categories |
(unset) | SearXNG categories param |
search.engines |
(unset) | SearXNG engines param |
search.timeRange |
(unset) | SearXNG time_range param |
headers |
(unset) | Extra HTTP headers attached to SearXNG requests only (e.g. X-API-Key gates) — never sent to web_fetch targets |
basicAuth.username / basicAuth.password |
(unset) | Basic-auth credentials for instances behind an authenticating reverse proxy (caddy basic_auth, nginx auth_basic) |
API keys & authenticated reverse proxies
Three supported ways to put a gate in front of the instance. Credentials
configured here ride only on requests to your SearXNG instance;
web_fetch targets (model-chosen third-party pages) always stay
credential-free.
-
Header gate (recommended for API consumers):
config: baseUrl: 'http://searx.internal:8080' headers: X-API-Key: 'your-key'Pair it with a caddy check, e.g.
caddy-l4/forward_author a small middleware that compares the header. -
Basic-auth reverse proxy (caddy
basic_auth, nginxauth_basic):config: baseUrl: 'http://searx.internal:8080' basicAuth: username: 'searxng' password: 'hunter2'Setting both
basicAuthand a user-suppliedheaders.Authorizationfails at load time with an actionable error. -
Path-prefix key (no plugin config needed): if your reverse proxy strips a secret prefix before proxying, just include it in
baseUrl, e.g.baseUrl: 'http://host:8081/s/<KEY>'. Works because the search adapter appends/search?...to whatever base you give it.
Node's
fetchrefuses URLs that embed credentials (http://user:pass@…), which is why auth lives in dedicated config fields instead ofbaseUrl.
Behavior notes & limits
- Search: maps SearXNG results to
{url, title?, snippet?, publishedAt?}and surfaces the SearXNGanswerline when present. - Fetch: GET with a browser-ish User-Agent; HTML is reduced to readable
text; output capped at
fetchMaxChars(truncatedflag set). - SSRF guard: validates the initial target only — redirects are followed without re-validation (v1 limitation). The guard also blocks non-http(s) protocols and unresolvable hosts. Disable only on closed deployments.
- Proxy: uses Node's global
fetch, which ignores system proxies and proxy env vars by default — SearXNG traffic always goes direct. Provider APIs behind a proxy are unaffected because this plugin talks only to your instance and fetched pages. - 403 from SearXNG: JSON output is disabled on the instance — see Requirements above.
Migrating from an MCP-based SearXNG integration
If you previously wired SearXNG through an MCP server (e.g.
mcp-searxng via a
dsh-mcp-client row), remove that integration when you install this plugin:
- The model would otherwise see two overlapping search tools (native
web_searchandmcp__searxng__searxng_web_search) plus several extra schemas — ambiguous tool selection and ~1–2k tokens of per-request overhead for no search-quality gain (both hit the same instance). - To remove: delete the
dsh-mcp-clientinsert row from your profile'scordis.patch.yml(HMR unregisters the tools immediately) and optionallynpm uninstall -g mcp-searxng.
What you give up: the MCP reader's PDF extraction and section filtering.
The native web_fetch covers plain HTML/text pages; if you later need PDF
reading again, re-adding the MCP row takes minutes.
Uninstall
dsh plugin --profile web remove dsh-searxng-web
Removes both the dependency and the bundle layer. ctx.web falls back to
the base composition (DeepSeek search, no fetch provider).
Development
The plugin is written in TypeScript (src/index.ts); the compiled
lib/index.js is committed so installs never need a build.
npm install # dev dependencies (typescript, @types/node, cordis types)
npm run build # compile src/ → lib/
npm test # build + self-contained offline test suite (mock SearXNG)
Release process (maintainers)
Bump version in package.json, add a CHANGELOG.md entry, then:
git commit -am "release: vX.Y.Z"
git tag vX.Y.Z
git push --follow-tags
GitHub Actions runs the standalone test suite and publishes to npm via OIDC
trusted publishing (Sigstore provenance) — the same pipeline as
dsh-windows-ocr.
License
More in Web & Browser
last30days-skill-cn
by jesseovo
AI agent skill that searches China's eight major platforms for the last 30 days of content and compiles a well-sourced research report.
browser4
by platonai
Browser4 — an AI-native browser engine for autonomous agents, intelligent extraction, and large-scale web automation.
modsearch
by liustack
Web/X 搜索与抓取桥:为纯文本 coding agent 提供结构化 JSON 证据(search/fetch/citations),引擎可选 Antigravity CLI(免 key)/带 key 引擎/X(Grok Build 登录态)。
anysearch-dsh
by anysearch-team
AnySearch web search provider and advanced search tools for DeepSeek Harness (DSH)
