Preface¶
DeepSeek Harness (dsh) treats web search as a replaceable capability rather than hardcoding it into the agent loop. The model side always calls the same set of web_search / web_fetch functions, and the actual web search work is done by the search provider registered on ctx.web. The official repository already includes @deepseek-ai/dsh-web-search-exa: it uses Exa’s POST /search REST interface, but the provider becomes completely unavailable without an API key.
Many scenarios such as local trials, temporary troubleshooting, and situations where users do not want to apply for an API key first will get stuck at this step. Community maintainer TonyDua created @tonydua/dsh-web-search-exa (repository name dsh-web-search-exa): it uses Exa’s hosted anonymous MCP when no API key is present, and automatically switches back to the REST interface once EXA_API_KEY is configured. This article is compiled after cross-checking against the plugin directory page, GitHub README / package.json, DeepSeek Harness official documentation, and Exa MCP instructions.
The core philosophy of DeepSeek Harness is “everything is a plugin”. The DSH Plugin Repository used in this article is an independent community-run website and has no official affiliation with DeepSeek / Horizon Robotics. Do not treat it as an official app store.
What is this¶
dsh-web-search-exa is a tool and capability plugin for DeepSeek Harness, maintained by TonyDua, licensed under MIT, primarily written in JavaScript, and requires Node.js 18 or above. Its GitHub repository is TonyDua/dsh-web-search-exa, and the npm package name is @tonydua/dsh-web-search-exa. Both the directory page and GitHub repository showed 6 stars when checked for this article. The repository was created on 2026-08-14, and it was added to the plugin directory on the same day.
It solves a very specific problem: it registers an Exa search provider to ctx.web, allowing existing model tools, prompt areas, and result cards to use web search without modification. It is not a replacement for the official package, but a zero-configuration variant of it: the official implementation only works with the REST interface requiring an API key; this package adds the anonymous MCP fallback, and its REST behavior when an API key is provided is identical to the official version.
The current version in the repository’s package.json is 0.1.3. The latest release listed on the npm page at the time of this article’s writing is still 0.1.2. The change in 0.1.3 is: the bundle patch no longer redefines the web line already occupied by the official package, avoiding startup failure with duplicate loader entry id: web after running dsh plugin add. Installing from GitHub will get the source code with this fix.
Core Features¶
Defaults to anonymous MCP without API key¶
When apiKey is not configured or the environment variable EXA_API_KEY is not set, searches will use Exa’s hosted MCP at https://mcp.exa.ai/mcp, making JSON-RPC 2.0 calls to web_search_exa without credentials in the request. The source identifier is included in the x-exa-source: dsh-anything header.
Exa’s own MCP page clearly states that connecting to https://mcp.exa.ai/mcp does not require an API key. Anonymous calls are rate-limited; HTTP 429 errors will return with WEB_PROVIDER_ERROR and prompt users to configure an API key.
Automatically switches to REST when API key is configured¶
Once EXA_API_KEY (or the literal apiKey in the configuration) is set, the provider will switch to https://api.exa.ai/search (POST /search, with Authorization: Bearer). The repository notes that this path has higher rate limits, and there are no additional changes to the tool behavior on the model side. The REST retrieval mode searchType defaults to auto, and can also be set to keyword or neural.
Plug-and-play, no changes to model tools required¶
It only registers a WebSearchProvider to ctx.web, does not own the ctx.web key, and does not register model-facing tools on its own. Tool names, parameters, prompts, and result cards are still handled by @deepseek-ai/dsh-tool-web. Returned results will be standardized into seam’s WebSearchSource: url, title, snippet, publishedAt; maxResults is truncated by seam on the return path.
The DeepSeek Harness documentation clearly states the selection rule: when no provider ID is configured and there is only one available search provider at the time, seam will automatically select it. When no API key is present, the official DeepSeek search provider is unavailable, so this plugin can be automatically selected with zero configuration.
Can coexist with the official Exa package¶
The default provider ID is exa, and the Cordis plugin name is web-search-exa, which is the same as the official @deepseek-ai/dsh-web-search-exa. Seam will throw WEB_DUPLICATE_PROVIDER when encountering duplicate IDs, and installing both packages directly into the same profile will cause a startup error without silent overwriting. You can change this package’s providerId to a different value such as exa-anon, then explicitly select it in the web configuration.
Main configuration options¶
| Configuration Key | Default Value | Meaning |
|---|---|---|
providerId |
exa |
Provider ID registered to ctx.web; only needs to be changed when coexisting with the official package |
apiKey |
Not set | Exact API key value for Exa; uses anonymous MCP when empty |
apiKeyEnv |
EXA_API_KEY |
Environment variable name to read when no literal apiKey is provided |
apiURL |
https://api.exa.ai/search |
REST endpoint when using an API key |
mcpURL |
https://mcp.exa.ai/mcp |
Anonymous MCP endpoint |
searchType |
auto |
REST retrieval mode: auto / keyword / neural |
numResults |
Not set | Default number of results when the request does not carry maxResults |
highlightsPerResult |
1 |
Number of highlight sentences requested per result in the REST path |
apiKey is marked with role('secret') and will not appear in describe() responses.
Installation and Activation¶
The installation command given on the plugin directory page is as follows, run it in the DeepSeek Harness terminal:
dsh plugin add github:TonyDua/dsh-web-search-exa
For reproducible installations, pin the commit hash as instructed on the directory page:
dsh plugin add github:TonyDua/dsh-web-search-exa#commit
Replace #commit with the actual commit hash. The repository README also provides installation methods for web profiles and from npm (starting from version 0.1.3 with a dsh.bundle manifest, the bundle patch will insert the provider line):
dsh plugin --profile web add @tonydua/dsh-web-search-exa
After installation, restart dsh web. The directory page notes that the plugin runs with the permissions of the current dsh process, and may execute code during installation; you should inspect the source code repository and license before installing.
Typical Usage¶
When you have no API key and only installed this one search provider, you usually do not need to change any configuration after restarting: the official DeepSeek search is unavailable, and seam will automatically select this plugin. Continue using the original web_search command for the model. Search results will still be rendered into source, summary, and date cards by dsh-tool-web, identical to the display style of DeepSeek search.
If you have configured an API key and want to explicitly use Exa, select the provider in $DSH_HOME/profiles/web/cordis.patch.yml (this file is applied after the bundle patch):
- id: web
name: '@deepseek-ai/dsh-web'
config:
searchProvider: exa
You can also modify this at runtime using environment variables without editing the file:
export DSH_WEB_SEARCH_PROVIDER=exa
For local development directories, you can directly point to the checked-out path as instructed in the README:
dsh plugin --profile web add ../plugins/dsh-web-search-exa
If you want to install both this package and the official @deepseek-ai/dsh-web-search-exa in the same profile, you must change the provider ID. The official package uses a fixed ID of exa, so assign this package a different value such as exa-anon:
- insert:
- id: web-search-exa
name: '@tonydua/dsh-web-search-exa'
config:
providerId: exa-anon
- id: web
name: '@deepseek-ai/dsh-web'
config:
searchProvider: exa-anon
The corresponding environment variable is $DSH_WEB_SEARCH_PROVIDER=exa-anon. A simpler approach is to install only one of the packages per profile and use the default ID.
The current version does not have an editable card in the Web settings page. The web-search-exa (@tonydua/dsh-web-search-exa) will appear in the Settings → Plugins list, and the server has also registered the web-search-exa configuration section, but there is no client card bound to it. The built-in “Web search” card modifies the official web-search-deepseek namespace and has nothing to do with this plugin. To modify configurations, edit cordis.patch.yml or use environment variables, then restart dsh web. The README notes that the next version plans to add UI cards, and this article does not treat it as a delivered feature.
Applicable Scenarios and Notes¶
These scenarios are suitable:
- Locally testing DeepSeek Harness’s web search and not wanting to apply for an Exa API key temporarily
- Already using web_search and only wanting to switch the search backend without modifying tools and prompts
- Needing to compare with the official Exa package, or explicitly switch providers using providerId in the same profile
Notes before use:
1. Anonymous MCP has rate limits. If you encounter 429 errors from frequent searches, configure EXA_API_KEY or apiKey as instructed in the repository, and the provider will switch to the REST interface. Exa’s hosted MCP is an official Exa product and is available for free anonymous use, but the quota is controlled by the provider.
2. This plugin only provides search, not crawling. web_fetch still uses the independent fetch provider (officially documented as dsh-web-fetch-http), do not expect it to read full web pages.
3. Do not install both the official package and this package without modification. Default ID conflicts will directly cause startup failure.
4. No setup UI currently. Changes to searchType, mcpURL, providerId, etc., can only be made via patch files or environment variables.
5. Runtime singleton. The README notes that @deepseek-ai/dsh-tools must resolve to the same physical instance in one profile. This plugin does not depend on it; if other third-party plugins install it as a nested regular dependency, the agent loop may throw Cannot read properties of undefined (reading 'prepare') before the search provider is called. You should first fix that plugin’s dependency declaration.
6. Permissions and license. The plugin runs with the permissions of the current dsh process. Read the repository source code and MIT license before installing. DeepSeek Harness itself is still in developer preview, and the official README notes that there will be breaking compatibility changes.
7. Selection. If you already have an EXA_API_KEY and want to follow the official implementation: use @deepseek-ai/dsh-web-search-exa. If you want zero-configuration trials: use this package.
The access method for anonymous MCP was referenced from can1357/oh-my-pi and @oh-my-pi/exa as noted in the repository README: use REST when there is an API key, and use mcp.exa.ai/mcp when there is not.
Summary¶
dsh-web-search-exa connects Exa to DeepSeek Harness’s ctx.web: it uses the officially hosted anonymous MCP when no API key is present, and automatically upgrades to REST when an API key is provided, with no changes needed to the model-side web_search command. It is a community-maintained zero-configuration variant, not an official package, nor a “certified plugin” in the DeepSeek official store.
Plugin Directory: https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-web-search-exa/
GitHub: https://github.com/TonyDua/dsh-web-search-exa