Preface¶
DeepSeek Harness (dsh) splits its web search capability into two layers: the model always sees a tool named web_search, while the actual search requests are handled by a search provider mounted under ctx.web. The default layer is the built-in web-search-deepseek, which uses DeepSeek’s official search API, requires parsing the DEEPSEEK_API_KEY, and consumes one model call per search.
This works fine when using only official accounts. Once you route chats through other gateways, want to settle search quota separately, or already have search MCPs like Tavily, Brave, or Exa on hand, the default backend becomes a constraint: the tool name cannot be changed, and the provider is tied to the official search service. Similar issues have been discussed in the official repository’s discussions — when the conversation model is changed, web_search still hits the original DeepSeek search endpoint.
What dsh-search-mcp does is replace this underlying provider, rather than registering a new set of tools like mcp__tavily__*. The model still calls web_search, the interface display remains unchanged, and requests are routed to the search MCP server you configured on the Web settings page. This article is organized after cross-checking with the community directory page, GitHub repository README, package.json/cordis.patch.yml source code, and official DeepSeek Harness web capability documentation.
What is this¶
dsh-search-mcp is a community plugin maintained by gxpppp, licensed under MIT, primarily written in JavaScript, with the current package.json version 0.1.0. As of August 18, 2026, the GitHub repository has 10 stars; the community directory page showed 7 stars at the time, so refer to the repository page for the latest star count.
It is categorized under “Interface Enhancement” in the directory, because the plugin injects a search-mcp configuration card into the Web settings page, and declares dsh.client.platform as web in package.json. The actual replaced capability is the search provider: during activation, it switches web.searchProvider to search-mcp while disabling the built-in web-search-deepseek. After uninstallation, this layer of bundle disappears, and the built-in search reverts to its original state.
You need to clarify two things first. DeepSeek Harness’s official slogan is “Everything is a plugin”: models, tools, sessions, and UI can all be replaced at the configuration layer without modifying the core source code. The community plugin directory deepseek-harness-plugin.com is an independent site and has no official affiliation with DeepSeek / HyperMind, and should not be treated as an official app store.
Core Features¶
Tool name unchanged, backend replaced entirely¶
The plugin registers a provider with a fixed id of search-mcp via ctx.web.registerSearchProvider(). The return shape matches the built-in provider ({ sources, truncated, content? }), and the native web_search tool is responsible for formatting. Therefore, the model-side tool name, parameters, and display do not need to be modified, and the execution channel is switched to MCP.
During installation, the built-in cordis.patch.yml automatically does three things:
- insert:
- id: search-mcp
- id: web
config:
searchProvider: search-mcp
- id: web-search-deepseek
disabled: true
The README states that this layer is added after dsh-base / dsh-web-app and before the user’s own cordis.patch.yml; after deleting the plugin, this entire layer disappears and the built-in search reverts to normal.
The scope only covers search. web_fetch remains disabled by default in dsh, and the plugin will not enable web crawling by default.
One settings page to switch between multiple search MCPS¶
Open the Web interface → Settings → Plugins → search-mcp to maintain the servers list. The repository provides presets for these kind values:
| kind | Default endpoint / startup method | Authentication | Default tool name |
|---|---|---|---|
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) |
No key required | ddg_web_search |
custom |
Fill in yourself | Choose yourself | Fill in yourself |
The transmission method supports http (streamable-http, default) and stdio (local command, used by DuckDuckGo). Global fields include defaultServer, maxResults (default 8), and searchTimeoutMs (default 30000). Individual servers can override their own maxResults.
Settings are written to the search-mcp: section of $DSH_HOME/settings.yaml, which takes precedence over line configuration. The provider reads the snapshot again for each search, so changes take effect immediately without restarting the process after modifying the configuration.
The default bundle inserts a Tavily server: defaultServer is tavily, and apiKeyEnv is TAVILY_API_KEY. This means that installing the plugin does not mean that search is immediately available — you also need to configure the corresponding key, or switch to the key-free DuckDuckGo.
API keys are not stored in the repository, results are normalized by URL¶
The API key resolution order is consistent in the README and lib/index.js: literal apiKey → dsh credential service (apiKeyEnv, e.g. $DSH_HOME/.credentials.yaml) → startup environment variables. The apiKey field in the settings page is displayed as a password box and is desensitized when saved; the repository’s cordis.patch.yml explicitly states that no API keys will be committed.
The MCP client uses @modelcontextprotocol/sdk. A new connection (http or stdio) is created for each search and closed when finished; the caller’s cancellation signal races with the searchTimeoutMs timeout, and an abort will throw a WEB_ABORTED error. On the result side, the plugin will recursively scan the JSON returned by the MCP, treat any object with a url field as a source (taking common field names for title / snippet / publish date), and treat answer as the summary, without hardcoding the field names of a specific vendor.
Installation and Activation¶
The installation command given on the community directory page is:
dsh plugin add github:gxpppp/dsh-search-mcp
The dsh CLI will parse the plugin from GitHub and add it to the current configuration. The plugin declares that it runs on the web platform, and the local development example in the README also installs it into the web profile. If your current default profile is not web, you can follow the README and run:
dsh plugin --profile web add github:gxpppp/dsh-search-mcp
For reproducible installations, fix the commit hash as instructed on the directory page:
dsh plugin add github:gxpppp/dsh-search-mcp#<commit>
Replace <commit> with the specific hash from the repository, do not leave it blank.
When modifying the source code locally, the steps in the README are: first run npm install in the repository directory, then use dsh plugin --profile web add link:<path to this repository> to link it, then restart dsh web. The Web bundle does not have HMR enabled, so you must restart the process after the first installation or after modifying the plugin code; if you only modify the server list in the settings page, you do not need to restart.
Both the directory page and the repository remind users that the plugin runs with the permissions of the current dsh process and may execute code during installation. You should inspect the source repository and license before installing.
Configuration and Verification¶
Add servers and API keys in the settings page¶
- Start
dsh weband open the web interface. - Go to Settings → Plugins → search-mcp.
- Confirm that there is at least one entry in
servers. The default is Tavily; you can also change it to Brave / Exa / Perplexity, or add a stdio server withkind: duckduckgo. - For services that require an API key, choose one of the following methods:
- Fill inapiKeydirectly in the card;
- Or fill inapiKeyEnv(e.g.TAVILY_API_KEY) and provide the corresponding credential in$DSH_HOME/.credentials.yamlor the startup environment. - Set
defaultServerto one of theservers[].idand save.
The application portals recorded in the README are: Tavily (tavily.com), Brave Search API (brave.com/search/api; the README notes a free 2000 requests/month quota, subject to Brave’s current terms), Exa (exa.ai), Perplexity (perplexity.ai). The DuckDuckGo preset does not require a key, but the local machine must be able to run npx.
If you have previously inserted a Tavily MCP directly in cordis.patch.yml, the README recommends deleting that insert section to avoid duplicate web_search tools with mcp__tavily__* appearing in the tool directory.
Confirm that the provider has been switched¶
The README uses the web profile for composite layer checking. The PowerShell example is:
dsh --profile web --dump-config | Select-String -Pattern "searchProvider|search-mcp|web-search-deepseek"
On bash, you can filter the same output with:
dsh --profile web --dump-config | grep -E "searchProvider|search-mcp|web-search-deepseek"
You should expect to see that searchProvider is already search-mcp, and web-search-deepseek is disabled. Then start a new conversation and ask the agent to call web_search (the README example is “Search for the list of MCP servers”). The returned results should come from the MCP corresponding to the current defaultServer, not the built-in DeepSeek search.
Uninstallation¶
dsh plugin --profile web remove dsh-search-mcp
Then follow the README: clear the search-mcp: section in settings.yaml (if you modified the settings page) and restart dsh web. The built-in web-search-deepseek will revert to normal along with the bundle layer.
Simply adding disabled: true to the search-mcp line in cordis.patch.yml is not sufficient: the README notes that the built-in search will still be in a replaced state at that point, and you need to restore both the web and web-search-deepseek lines, or simply uninstall the plugin.
Applicable Scenarios and Notes¶
This plugin is suitable for the following use cases:
- You want to keep the web_search model tool, but route search traffic to professional search APIs such as Tavily / Brave / Exa / Perplexity.
- You are already using search MCPS and do not want the same functionality exposed again under the mcp__*__* tool name.
- You need to switch between multiple search backends on the settings page without modifying dsh source code.
- You do not have a DeepSeek official search quota for the time being, but have a DuckDuckGo MCP or other key-free / self-hosted search MCP.
Pay attention to these boundaries before using:
1. This is a Web plugin. The client injection in package.json points to @deepseek-ai/dsh-client-ui-settings, and the platform is web. Headless workflows are not covered in the repository documentation.
2. Dependency versions are pinned to 0.1.0-rc.6. In package.json, @deepseek-ai/dsh-web, dsh-settings, dsh-credentials, and dsh-launch-environment are all set to 0.1.0-rc.6, and the MCP SDK is set to ^1.30.0. If dsh has been upgraded to an incompatible version, you need to verify compatibility on your own.
3. Empty server list cannot perform searches. If servers is empty, it will report configured web provider "search-mcp" is registered but unavailable or no search MCP servers configured. Missing keys, mismatched defaultServer and id, unreachable URL, or npx not in PATH for stdio mode will all throw errors like WEB_PROVIDER_ERROR during search.
4. Only search is replaced, not crawling. cordis.patch.yml keeps tool-web’s fetch set to false, and raises searchMaxResults to 50, letting the plugin’s own maxResults determine the actual number of results.
5. Third-party search services have their own terms and fees. The plugin itself is MIT licensed and can be installed for free; the quotas for Tavily / Brave / Exa / Perplexity are subject to each vendor’s console, and the free quotas mentioned in the README should not be interpreted as permanent guarantees.
6. Permissions and source. The plugin has the same permissions as the current dsh process, can read credentials, and can spawn stdio child processes. Inspect the repository source code and MIT license before installing; fix the commit hash for reproducible environments.
Summary¶
dsh-search-mcp replaces dsh’s search provider from the built-in DeepSeek search to a configurable search MCP, while preserving the web_search tool name. Configuration is centralized on the Web settings page, and uninstallation will restore the original state. It solves the requirement of “wanting to change the backend without modifying the model side”, and does not create a parallel set of search tools.
Community directory page: https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-search-mcp/
GitHub repository: https://github.com/gxpppp/dsh-search-mcp