DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Web Search Ext — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
W

@fno2010/dsh-web-search-ext

Web Search Ext

Multi-backend web_search and web_fetch providers for the DeepSeek Harness web seam (ctx.web): Exa (REST with key, anonymous hosted MCP without) and Firecrawl (v2 search/scrape API) today, extensible to more backends (SearXNG, ...), with automatic failover when one backend rate-limits, result verific

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add @fno2010/dsh-web-search-ext@0.3.0
READMECompatibilityVersions

Description

Multi-backend web_search and web_fetch providers for the DeepSeek Harness web seam (ctx.web): Exa (REST with key, anonymous hosted MCP without) and Firecrawl (v2 search/scrape API) today, extensible to more backends (SearXNG, ...), with automatic failover when one backend rate-limits, result verification (liveness/content), and a keyless web_fetch path

Compatibility and provenance

Web Search Ext is published as @fno2010/dsh-web-search-ext and currently resolves to version 0.3.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
npm
Registry updated
9/20/2026

Versions

0.3.1stable
8/29/2026
0.3.0stable
8/26/2026
0.2.0stable
8/22/2026
Show 3 more versionsCollapse versions
0.1.2stable
8/21/2026
0.1.1stable
8/21/2026
0.1.0stable
8/21/2026

Related plugins

Loading related plugins…

Latest
0.3.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
136.3 kB
Files
10
Surface
web
License
MIT
Source
npm
GitHub
★ 3
Weekly downloads
60
Last push
9/11/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in search-research.

Browser Skill Dsh Plugin@wxg-prc-cpg/browser-skill-dsh-pluginDeepSeek Harness tool plugin that exposes BrowserSkill browser automation (browser_* tools) to the modelWeknora@wxg-prc-cpg/dsh-weknoraWeKnora knowledge retrieval tools for DeepSeek Harness (dsh): semantic search, document reading and RAG/agent answers over your own knowledge bases.Free Searchdsh-free-searchFree web search for DeepSeek Harness: 13 engines (Bing/DuckDuckGo/AnySearch/SearXNG/Exa/Tavily/Keenable/Firecrawl keyless; Parallel/Perplexity/SerpBase/DeepSeek with key) + time filtering + platform search + web_fetch, with web settings UI.Find Plugindsh-find-pluginFind DeepSeek Harness plugins inside the agent — live GitHub dsh-plugin topic search, ranked by stars.

README

dsh-web-search-ext

English | 中文

Multi-backend web_search and web_fetch provider for DeepSeek Harness (DSH). Works with no API keys at all; add keys to unlock higher limits. Registered into the web capability seam (ctx.web) under one stable provider id (web-search-ext).

Why

The built-in web_search tool is backend-pluggable; the in-box default provider (deepseek-official) requires a DeepSeek API key. This plugin is a key-free-capable alternative: it works out of the box via Exa's anonymous MCP endpoint, and fails over automatically when one backend saturates. It also registers a keyless web_fetch provider, and verifies what it hands to the model (dead links, changed pages, which backend actually answered — all visible in the result).

Features

  • Two backends today: Exa (REST with key, anonymous hosted MCP without) and Firecrawl (v2 search + scrape API, keyed or keyless)
  • Keyless web_fetch: fetch a URL through Firecrawl scrape, falling back to Exa's anonymous MCP web_fetch_exa; no API key required, output capped by fetchMaxChars
  • Automatic failover: on any backend failure (429, 401/402/403, 5xx, network, malformed body) the search — and the fetch — falls through to the next backend in order
  • Per-backend 429 cooldown: a saturated backend is skipped on subsequent calls; the cooldown honors the window the backend itself reports (Retry-After header or retry_after_seconds in the body), clamped by maxCooldownSec; when all backends fail, the error lists every failure including cooldown state
  • Result verification (L0 liveness, on by default): every returned source is probed locally and each snippet tagged [alive] / [dead 404] / [blocked] / [timeout] / [unreachable] / [skipped] — no result is ever dropped; experimental L1 content check via verifyLevel: "content" adds [verified] / [verified·changed] / [unverified] (page live but no snippet to compare)
  • Provenance receipt: web_search results carry a one-line receipt (web-search-ext: <backend> · <elapsed>s · <n> results · liveness: …), naming the backend that actually served the result and surfacing limitations (e.g. keyless Exa cannot honor a freshness window) instead of hiding them
  • Freshness window: freshness: 24h | 7d | 30d is sent on the wire where the backend supports it (Exa startPublishedDate, Firecrawl tbs); the keyless Exa MCP path says so in the receipt
  • Optional keys with per-backend precedence: settings literal → credentials service → launch environment variable
  • Settings card on the Web: Settings → Plugins → Plugin configuration exposes the five core config fields and both API keys, with key state auto-discovered from the credentials layers (the 0.3.0 verification/freshness fields are settings.yaml-only for now; the card gains them in 0.3.1)
  • No install-time scripts: plain ESM JavaScript, no build step, no postinstall/prepare
  • Extensible: adding a backend is one search function + one plan entry + config fields — see CONTRIBUTING

Backends

BackendSearchFetch
ExaWith key: REST POST https://api.exa.ai/search (higher limits, highlight snippets). Without: anonymous hosted MCP POST https://mcp.exa.ai/mcp (JSON-RPC 2.0, documented public fallback, rate-limited → HTTP 429)Keyless: hosted MCP web_fetch_exa tool (fallback path)
FirecrawlPOST https://api.firecrawl.dev/v2/search (Bearer with key; keyless requests when firecrawlKeyless: true — unofficial, may be rate-limited or removed)POST {base}/scrape (keyed or keyless; preferred fetch path — markdown + metadata)

Install

dsh plugin --profile web add @fno2010/dsh-web-search-ext
# or from a local checkout:
dsh plugin --profile web add ./path/to/dsh-web-search-ext

Installing a plugin requires restarting the running dsh web process (the profile bundle list is resolved at boot). Config changes afterwards are hot — no restart.

The bundle patch selects this provider for the web_search tool (web.searchProvider: web-search-ext) and for web_fetch (web.fetchProvider: web-search-ext). The official deepseek-official provider stays registered but unused; the explicit selection also prevents WEB_PROVIDER_AMBIGUOUS.

Configuration

Settings namespace web-search-ext in ~/.dsh/settings.yaml (hot-reloaded):

FieldDefaultDescription
preferredexaBackend to try first: exa | firecrawl
numResults8Default result count when the tool doesn't cap it
maxSnippetChars500Snippet length bound
rateLimitCooldownSec60Fallback 429 cooldown when the backend reports no window; 0 disables
firecrawlKeylesstrueAllow keyless Firecrawl requests (search + fetch)
exaApiKey / firecrawlApiKey—Literal API key per backend
exaApiKeyEnv / firecrawlApiKeyEnvEXA_API_KEY / FIRECRAWL_API_KEYEnv var names for key resolution
exaApiUrl / exaMcpUrl / firecrawlBaseUrlhttps://api.exa.ai/search / https://mcp.exa.ai/mcp / https://api.firecrawl.dev/v2Endpoint overrides
verifyLevellivenessResult verification tier: off | liveness (HEAD every source) | content (experimental: also word-match the snippet against the live page)
livenessTimeoutMs3000Per-URL timeout for L0 HEAD probes
contentCheckBytes10240L1: max bytes read from each page
contentCheckMinBytes200L1: pages shorter than this count as bot-blocks
contentCheckMatchWords5L1: leading snippet words checked against the page
contentCheckTimeoutMs3000L1: timeout per request and body-read phase
web-search-ext:
  preferred: exa
  numResults: 8
  # rateLimitCooldownSec: 60   # all other values are defaults

Or select this provider without the bundle patch: DSH_WEB_SEARCH_PROVIDER=web-search-ext.

Keys (optional but recommended)

Any of these, in order of precedence per backend:

  1. Literal key in the settings section (exaApiKey / firecrawlApiKey)
  2. Credentials service: the EXA_API_KEY / FIRECRAWL_API_KEY entries in ~/.dsh/.credentials.yaml (or a .env file)
  3. Launch environment variable of the same name

Settings UI (Web): this plugin has a card on Settings → Plugins → Plugin configuration that edits the five config fields and both API keys. Key state is auto-discovered from the layers above — the configured/not-configured badges update live when ~/.dsh/.credentials.yaml changes — and a key supplied by the live process environment is rendered read-only, because the host rejects UI writes that an environment value would shadow. (The "Models" page manages LLM provider credentials only.)

No keys at all still works: Exa uses its anonymous MCP endpoint and Firecrawl is tried keyless.

How failover works

Each search (and each fetch) builds an ordered plan from the backends that are available under the current key situation — preferred backend first for search; Firecrawl scrape first for fetch (richer markdown), with the keyless Exa MCP fetch as fallback. The first backend whose request fails is reported as the failure only if every later backend also fails — a 429 additionally starts that backend's cooldown, sized by the window the backend itself reports (Retry-After header, or retry_after_seconds in the response body; clamped by maxCooldownSec), so it is skipped on subsequent calls until the window expires.

web_search results also carry a one-line provenance receipt (web-search-ext: <backend> · <elapsed>s · <n> results · liveness: …): which backend actually answered, and whether the freshness window or verification tier was honored or had to be skipped. Nothing is silently dropped.

Uninstall

dsh plugin --profile web remove @fno2010/dsh-web-search-ext   # then restart dsh web

Security notes

  • The only outbound requests are to the configured Exa and Firecrawl endpoints (plus the local verification probes described below); nothing else is contacted.
  • API keys travel only in the authorization header of their own backend's requests — never in bodies, never to the other backend, never in error messages.
  • No install-time scripts: plain ESM JavaScript, no build step, no postinstall/prepare.
  • Snippets are bounded (maxSnippetChars) and Firecrawl's page-markdown descriptions are stripped of image links before entering model context.
  • Verification probes (L0/L1) only fetch URLs that appear in backend results, with bounded bytes/timeouts; redirects are followed manually and every hop is re-validated against the same SSRF rules (public http(s) only; loopback, private, link-local, and CGNAT ranges are refused — including IPv6 literal and trailing-dot spellings; addresses that cannot be confidently classified are refused, fail closed).
  • The web_fetch provider refuses non-public targets (non-http(s) schemes, loopback, private, link-local) before sending the URL to any scraping backend.

Development

  • Tests: npm test — 39 mocked failover/mapping scenarios plus live keyless smoke calls (smoke is skipped in CI).
  • Adding a backend, branch/PR conventions, and the release process: CONTRIBUTING.md.

License

MIT

freshnessanyRecency window: any | 24h | 7d | 30d (sent on the wire where the backend supports it; keyless Exa MCP cannot filter and says so in the receipt)
maxCooldownSec86400Cap on 429 cooldowns taken from a backend's reported retry_after; 0 = always honor the reported value
fetchMaxChars50000Character cap for web_fetch provider output