用 dsh-search-mcp 把 DeepSeek Harness 内置搜索换成 MCP 搜索服务

前言

DeepSeek Harness(dsh)把联网能力拆成两层:模型侧始终看到名为 web_search 的工具,真正发请求的是挂在 ctx.web 上的搜索 provider。默认那一层是内置的 web-search-deepseek,走 DeepSeek 官方搜索接口,需要能解析 DEEPSEEK_API_KEY,而且每次搜索都会消耗一次模型调用。

这在只用官方账号时没问题。一旦聊天走了别的网关、搜索额度想单独结算,或者手头已经有 Tavily、Brave、Exa 这类搜索 MCP,默认后端就会变成约束:工具名改不了,provider 却绑在官方搜索上。官方仓库的讨论里也有人碰到过类似情况——会话模型换了,web_search 仍打原来的 DeepSeek 搜索端点。

dsh-search-mcp 做的是替换这一层 provider,而不是再注册一套 mcp__tavily__* 之类的新工具。模型还是调用 web_search,界面展示不变,请求改走你在 Web 设置页配好的搜索 MCP 服务器。本文按社区目录页、GitHub 仓库 README、package.json / cordis.patch.yml 源码,以及 DeepSeek Harness 官方的 Web 能力说明核对后整理。

这是什么

dsh-search-mcp 是由 gxpppp 维护的社区插件,许可证 MIT,主要语言 JavaScript,当前 package.json 版本为 0.1.0。GitHub 仓库截至 2026 年 8 月 18 日为 10 星;社区目录页当时显示 7 星,以仓库页面为准。

它在目录里归在「界面增强」,原因是插件会向 Web 设置页注入 search-mcp 配置卡片,并且 package.json 里声明了 dsh.client.platformweb。真正替换的能力是搜索 provider:启用期间把 web.searchProvider 切到 search-mcp,同时禁用内置的 web-search-deepseek。卸载后这一层 bundle 消失,内置搜索按原样恢复。

需要先分清两件事。DeepSeek Harness 官方的口号是「一切皆插件」,模型、工具、会话、UI 都可以在配置层替换,不必改核心源码。社区插件目录 deepseek-harness-plugin.com 是独立站点,和 DeepSeek / 幻方没有官方从属关系,不能当成官方应用商店。

核心功能

工具名不变,后端整段换掉

插件通过 ctx.web.registerSearchProvider() 注册 id 固定为 search-mcp 的 provider。返回形状与内置 provider 一致({ sources, truncated, content? }),由原生 web_search 工具负责格式化。因此模型侧工具名、参数和展示都不必改,执行通道换成 MCP。

安装时由包内的 cordis.patch.yml 自动做三件事:

- insert:
    - id: search-mcp
- id: web
  config:
    searchProvider: search-mcp
- id: web-search-deepseek
  disabled: true

README 写明:这一层加在 dsh-base / dsh-web-app 之后、用户自己的 cordis.patch.yml 之前;删掉插件后整层消失,内置搜索还原。

范围只覆盖搜索。web_fetch 保持 dsh 默认关闭,插件不会顺手打开网页抓取。

一套设置页切换多家搜索 MCP

打开 Web 界面 → 设置 → Plugins → search-mcp,维护 servers 列表。仓库为这些 kind 写了预设:

kind 默认端点 / 启动方式 鉴权 默认工具名
tavily https://mcp.tavily.com/mcp/ query tavilyApiKey tavily_search
brave https://mcp.brave.com/mcp/ query braveApiKey brave_web_search
exa https://mcp.exa.ai/mcp header x-api-key web_search_exa
perplexity https://mcp.perplexity.ai/mcp/ query pplx_api_key pplx_search
duckduckgo npx -y duckduckgo-mcp-server(stdio) 无需 key ddg_web_search
custom 自己填 自己选 自己填

传输方式支持 http(streamable-http,默认)和 stdio(本机命令,DuckDuckGo 走这条)。全局字段包括 defaultServermaxResults(默认 8)、searchTimeoutMs(默认 30000)。单条服务器还可以覆盖自己的 maxResults

设置写入 $DSH_HOME/settings.yamlsearch-mcp: 段,优先于行配置。provider 每次搜索重新读快照,改完立即生效,不必为改配置再重启。

默认 bundle 会插入一条 Tavily 服务器:defaultServertavilyapiKeyEnvTAVILY_API_KEY。也就是说,装上插件并不等于搜索立刻可用,还要把对应 key 配好,或改成免 key 的 DuckDuckGo。

密钥不进仓库,结果按 URL 归一化

密钥解析顺序在 README 和 lib/index.js 里一致:字面量 apiKey → dsh 凭证服务(apiKeyEnv,例如 $DSH_HOME/.credentials.yaml)→ 启动环境变量。设置页里 apiKey 按密码框显示、落盘脱敏;仓库的 cordis.patch.yml 明确写了不提交任何 API key。

MCP 客户端用 @modelcontextprotocol/sdk。每次搜索新建连接(http 或 stdio),结束时关闭;调用方的取消信号与 searchTimeoutMs 超时竞速,中止时抛 WEB_ABORTED。结果侧会递归扫描 MCP 返回的 JSON,凡带 url 的对象当作 source(title / snippet / 发布日期取常见字段名),answer 当作摘要,不绑死某一家厂商的字段名。

安装与启用

社区目录页给出的安装命令是:

dsh plugin add github:gxpppp/dsh-search-mcp

dsh CLI 会从 GitHub 解析插件并装进当前配置。插件声明运行在 web 平台,README 里的本地开发示例也是装进 web profile。如果当前默认 profile 不是 web,可以按 README 写成:

dsh plugin --profile web add github:gxpppp/dsh-search-mcp

需要可复现安装时,按目录页说明固定 commit 哈希:

dsh plugin add github:gxpppp/dsh-search-mcp#<commit>

<commit> 换成仓库里的具体哈希,不要留空。

本地改源码时,README 的步骤是:先在仓库目录执行 npm install,再用 dsh plugin --profile web add link:<本仓库路径> 以 link 方式挂上,然后重启 dsh web。Web bundle 未启用 HMR,首次安装或改插件代码后必须重启进程;之后只改设置页里的服务器列表,则不必重启。

目录页和仓库都提醒:插件以当前 dsh 进程的权限运行,安装时可能执行代码。装之前应检查源代码仓库和许可证。

配置与验证

在设置页补上服务器和密钥

  1. 启动 dsh web,打开网页界面。
  2. 进入 设置 → Plugins → search-mcp
  3. 确认 servers 里至少有一条记录。默认是 Tavily;也可以改成 Brave / Exa / Perplexity,或加一条 kind: duckduckgo 的 stdio 服务器。
  4. 需要密钥的服务,任选一种方式:
    - 在卡片里直接填 apiKey
    - 或填 apiKeyEnv(如 TAVILY_API_KEY),并在 $DSH_HOME/.credentials.yaml 或启动环境里提供同名凭证。
  5. defaultServer 设成某条 servers[].id,保存。

README 记录的申请入口:Tavily(tavily.com)、Brave Search API(brave.com/search/api;README 写明有免费 2000 次/月额度,具体以 Brave 当前说明为准)、Exa(exa.ai)、Perplexity(perplexity.ai)。DuckDuckGo 这条预设不需要 key,但本机要能执行 npx

如果以前在 cordis.patch.yml 里直接插过 Tavily MCP,README 建议删掉那一段 insert,避免工具目录里再出现 mcp__tavily__*,和 web_search 重复。

确认 provider 已经切过去

README 用 web profile 做组合层检查。PowerShell 示例是:

dsh --profile web --dump-config | Select-String -Pattern "searchProvider|search-mcp|web-search-deepseek"

在 bash 下可以对同一份输出做过滤:

dsh --profile web --dump-config | grep -E "searchProvider|search-mcp|web-search-deepseek"

预期能看到 searchProvider 已是 search-mcp,且 web-search-deepseek 处于 disabled。然后开一个新会话,让智能体调用 web_search(README 的例子是「搜索 MCP 服务器列表」)。返回结果应来自当前 defaultServer 对应的 MCP,而不是内置 DeepSeek 搜索。

卸载

dsh plugin --profile web remove dsh-search-mcp

之后按 README:清掉 settings.yaml 里的 search-mcp: 段(如果改过设置页),重启 dsh web。内置 web-search-deepseek 会随 bundle 层一起恢复。

只在 cordis.patch.yml 里给 search-mcp 行加 disabled: true 并不足够:README 写明,此时内置搜索仍处于被替换状态,要同时还原 webweb-search-deepseek 两行,或者直接卸载插件。

适用场景与注意事项

比较适合这几类用法:

  • 希望保留 web_search 这个模型工具,但搜索流量走 Tavily / Brave / Exa / Perplexity 等专业搜索 API。
  • 已经在用搜索类 MCP,不想再让同一套能力以 mcp__*__* 工具名暴露一份。
  • 需要在设置页里切换多家搜索后端,而不改 dsh 源码。
  • 暂时没有 DeepSeek 官方搜索额度,但有 DuckDuckGo MCP 或其它免 key / 自建搜索 MCP。

使用前注意这些边界:

  1. 这是 Web 插件。 package.json 的 client 注入指向 @deepseek-ai/dsh-client-ui-settings,平台为 web。headless 流程不在仓库说明范围内。
  2. 依赖版本写死在 0.1.0-rc.6。 package.json@deepseek-ai/dsh-webdsh-settingsdsh-credentialsdsh-launch-environment 均为 0.1.0-rc.6,MCP SDK 为 ^1.30.0。dsh 若已升到不兼容的版本,需要自己核对。
  3. 空列表不能搜。 servers 为空会报 configured web provider "search-mcp" is registered but unavailableno search MCP servers configured。缺 key、defaultServer 对不上 id、URL 不通、stdio 的 npx 不在 PATH,都会在搜索时以 WEB_PROVIDER_ERROR 一类错误冒出来。
  4. 只换搜索,不换抓取。 cordis.patch.ymltool-webfetch 维持为 false,并把 searchMaxResults 提到 50,让插件自己的 maxResults 决定实际条数。
  5. 第三方搜索各有条款和费用。 插件本身 MIT、可免费安装;Tavily / Brave / Exa / Perplexity 的配额以各家控制台为准,不要把 README 里的免费额度理解成永久保证。
  6. 权限与来源。 插件与当前 dsh 进程同权,能读凭证、能拉起 stdio 子进程。安装前看仓库源码和 MIT 许可证;需要可复现环境时固定 commit。

小结

dsh-search-mcp 把 dsh 的搜索 provider 从内置 DeepSeek 换成可配置的搜索 MCP,同时保住 web_search 这个工具名。配置集中在 Web 设置页,卸载即可还原。它解决的是「后端想换、模型侧不想改」这一类需求,并不是再做一套并行的搜索工具。

目录页:https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-search-mcp/

GitHub:https://github.com/gxpppp/dsh-search-mcp

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜