dsh-searxng-web
已归档maxwell-feng/dsh-searxng-web
DeepSeek Harness 插件:用自托管 SearXNG 实例支撑原生 web_search/web_fetch,无需 Key、隐私可控。
该仓库已归档——只读且不再维护,安装前请仔细审查代码。
$ dsh plugin add dsh-searxng-web7
星标
2
Fork
TypeScript
语言
MIT
许可证
2026-08-22
创建于
2026-09-13
最近推送
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
更多「网页与浏览器」插件
last30days-skill-cn
作者 jesseovo
last30days-cn 是一个 AI Agent 技能(Skill),能够自动搜索中国互联网 8 大主流平台最近 30 天的内容,综合分析后生成有据可查的研究报告。
browser4
作者 platonai
面向自主智能体与大规模网页自动化的 AI 原生浏览器引擎,支持智能内容抽取。
modsearch
作者 liustack
🥇 The strongest free web search plugin for DeepSeek Harness, and the search bridge for every model without native web access. Free, no signup, no API key. Ask the web or X, get structured JSON evidence. | 🥇 全网最强的 DeepSeek Harness 免费联网搜索插件,免费免注册免 API key。为不能联网的模型补上搜索,问网页或 X,拿回结构化 JSON 证据(搜索、抓取、引用)。
anysearch-dsh
作者 anysearch-team
为 DeepSeek Harness 提供的 AnySearch 网页搜索提供方与高级搜索工具。
