DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
W

@fno2010/dsh-web-search-ext

Web Search Ext

用于 DeepSeek Harness Web 接口(ctx.web)的多后端 web_search 和 web_fetch 提供程序:目前支持 Exa(带密钥的 REST,以及无需密钥的匿名托管 MCP)和 Firecrawl(v2 搜索/抓取 API),并可扩展至更多后端(SearXNG、……);当某个后端触发速率限制时自动故障转移,支持结果验证

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:fno2010/dsh-web-search-ext#7a2f2a46f55be5dbbcf9136e4823beddaed859b7
README兼容性版本

说明

用于 DeepSeek Harness Web 接口(ctx.web)的多后端 web_search 和 web_fetch 提供程序:目前支持 Exa(带密钥的 REST,以及无需密钥的匿名托管 MCP)和 Firecrawl(v2 搜索/抓取 API),并可扩展至更多后端(SearXNG、……);当某个后端触发速率限制时自动故障转移,支持结果验证(存活性/内容),以及无需密钥的 web_fetch 路径

兼容性与来源证明

Web Search Ext 以 @fno2010/dsh-web-search-ext 发布,当前版本为 0.3.1。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/11/4

版本

0.3.1stable
2026/8/29
0.3.0stable
2026/8/26
0.2.0stable
2026/8/22
查看其余 3 个版本收起版本
0.1.2stable
2026/8/21
0.1.1stable
2026/8/21
0.1.0stable
2026/8/21

相关插件

正在加载相关插件…

最新版
0.3.1
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 2
周下载
352
最近提交
2026/10/21
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 search-research 分类下经过校验的插件。

Free Searchdsh-free-searchDeepSeek Harness 的免费网页搜索:27 个引擎(Bing/DuckDuckGo/AnySearch/SearXNG/Exa/Tavily/Keenable/Firecrawl/Parallel/You.com 无需密钥;通过 MCP 支持 Zhihu 全局/站内搜索,以及 Perplexity/SerpBase/DeepSeek(官方 + 原生工具/搜索)/Baidu/Kimi/Aliyun/Douba)Ab Wechat Scrapedsh-ab-wechat-scrape--- description: "树外 wechat_scrape 工具:获取微信公众号文章,过滤推广区块,并将每篇文章保存为 Markdown 文件,供此机器的 dsh 配置文件维护者使用。" kind: "package-reference" ---Arisdsh-arisARIS research-workflow 技能作为 DeepSeek Harness 捆绑包:包含 82 项技能,以及通过 Codex 进行的跨模型对抗性审查。Ab Market Researchdsh-ab-market-research一个树外 DeepSeek Harness 插件:将 trade_search 工具(多轮扩展方面的查询规划、出版商级别排序、来源多样性、JSON 快照)及其浏览器卡片集成在一个包中。

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 six core config fields — including the verification tier (off / liveness / content, hot-applied from the next search onward) — and both API keys, with key state auto-discovered from the credentials layers (the freshness window remains settings.yaml-only)
  • web_search toolview card on the Web: the web_search row in a conversation takes over the host's built-in web card and adds the provenance receipt line, tone-coded per-source verification badges (alive, verified, dead 404, …), the truncation notice, a per-result drill-down (click a source to see its serving backend, freshness, and verification state), and an in-flight indicator while a search is running (sweep animation + a client-ticked elapsed label — the host ships no in-flight progress channel, so neither the phase nor the serving backend is claimed until the result settles); when the web seam is not pinned to this provider it degrades gracefully (no receipt line claimed, no badges invented, no backend claimed) instead of mislabeling someone else's results
  • Session Health tab on the Web: the settings card's Health tab shows session telemetry served at the host's GET /web-search-ext/health route — uptime, per-backend success/failure counts, last-call timing, active 429 cooldowns, and session search/fetch counts; the payload is counters only (no credentials, URLs, or query text), and the tab shows an explicit unavailable state with a retry when the route is not mounted (CLI/headless profiles)
  • First-install connectivity probe on the Web: the Health tab's Connectivity section probes Exa (keyed REST or anonymous MCP) and Firecrawl (keyed or keyless) — automatically once when the tab first opens with no stored result, and at will via "Test now" — and shows each backend's outcome as a closed code (OK / rate limited / auth rejected / timed out / network error / request failed / not enabled) with its latency. The host runs the probe on demand at POST /web-search-ext/probe and never at apply time, so installs, host restarts, and CI make zero vendor calls; the payload carries plan literals and closed codes only (no vendor messages, URLs, or keys)
  • /search-engine slash command on the Web: switch the preferred backend, see live status (key source, last-call outcome, active 429 cooldown), and run the connectivity test — straight from the composer's / menu, in the host's popup shell. If /search-engine is already taken the command registers under /web-search-engine instead, and the settings card says which name materialized (or that neither was available) — the fallback is surfaced, never silent
  • 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.

The plugin also makes the model-facing web_fetch tool available out of the box. The stock tool is normally registered by the agent-preset layer (tool-web), but every shipped preset ships that row with fetch: false, and the dsh web profile additionally disables the profile-layer tool-web row — so no stock composition registers web_fetch, and the model gets unknown tool "web_fetch" even with a working fetch provider installed. This plugin closes the gap at apply time: when web_fetch is not already registered, it registers the stock tool by reusing @deepseek-ai/dsh-tool-web's own applyWebFetchTool (same schema, prompt, and presentation as the harness). The tool's execution routes through ctx.web.fetch — the seam pinned to this provider — whose fetch path is guarded by a fail-closed SSRF check (public http(s) targets only; the base's reason for disabling the tool). A preset that enables tool-web.fetch registers its own agent-scoped tool, which takes precedence; if the tool is already registered, this plugin's step is a no-op. To keep web_fetch off entirely, uninstall the plugin.

Configuration

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

FieldDefaultDescription
preferredexaBackend to try first: exa | firecrawl
numResults8Result count to request; also a hard cap on results returned (context budget) — a larger maxResults request is clamped to it and the receipt says so
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
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 six config fields (including the verification tier) 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.
  • One search's context is bounded: results are clamped to numResults (when a request's maxResults exceeds it, the receipt carries the (numResults cap) marker — N of M results when the backend also over-delivered) and snippets are bounded to maxSnippetChars; 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 — mocked failover/mapping/verification/fetch scenarios (deterministic, no network) plus live keyless smoke calls (smoke is skipped in CI).
  • Adding a backend, branch/PR conventions, and the release process: CONTRIBUTING.md.

License

MIT

contentCheckTimeoutMs
3000
L1: timeout per request and body-read phase
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