Skip to main content
Glama
vickean

DeepSeek Search MCP server

by vickean
README.md
# DeepSeek Search MCP server

A local [MCP](https://modelcontextprotocol.io/) server that exposes
DeepSeek's in-house **Search** and **Fetch** APIs as agent tools over stdio.

- `web_search` → `POST https://api.deepseek.com/v1/tools/search`
- `web_fetch` → `POST https://api.deepseek.com/v1/tools/fetch`

It uses only the official `@modelcontextprotocol/sdk` and `zod`. The API key is
read from the environment and is never written into any file in this directory.

---

## Tools

### `web_search`

Search the web with DeepSeek's in-house search engine. Returns ranked results
with title, URL, publication date, authority tier, a relevance score, a short
snippet, a long model-ready summary, and (optionally) full page content.

| Arg | Type | Required | Notes |
| --- | --- | --- | --- |
| `query` | string | yes | 1–128 chars. Operators supported (see below). |
| `count` | integer | no | 1–50, default 10. **Does not affect the price.** |
| `need_content` | boolean | no | Include full page text per result. Default `false`. |
| `ori_question` | string | no | The user's original question, to improve query understanding. |
| `localization` | string | no | An IP address used to localize results. |

Query operators (combine freely):

```text
site:github.com            restrict to a site (join several with OR)
-site:example.com          exclude a site
"exact phrase"             match an exact phrase
-term                      exclude pages containing a term
-"exact phrase"            exclude an exact phrase
lang:zh,en                 restrict to language codes
after:2025-01-01           published after a date
before:2026-06-01          published before a date
```

Example:

```text
DeepSeek site:github.com OR site:huggingface.co lang:en after:2025
```

### `web_fetch`

Fetch a single web page and return its title and content as Markdown.

| Arg | Type | Required | Notes |
| --- | --- | --- | --- |
| `url` | string | yes | HTTP or HTTPS URL. |

---

## Setup

### 1. API key

Get a key at <https://platform.deepseek.com> and make sure the account has a
positive balance.

Export it where OpenCode's background **service** starts, not just an
interactive shell — the service reads the environment at startup:

```bash
export DEEPSEEK_API_KEY=sk-your-key
```

If the service autostarts from a context that does not inherit your shell
profile, add the export there too (shell profile, launcher, or service unit).

Optional override of the API base URL:

```bash
export DEEPSEEK_BASE_URL=https://api.deepseek.com
```

### 2. OpenCode configuration

The server is registered in `~/.config/opencode/opencode.json` under
`mcp.servers`:

```jsonc
{
  "mcp": {
    "servers": {
      "deepseek-search": {
        "type": "local",
        "command": ["node", "/absolute/path/to/deepseek-search/index.js"],
        "environment": {
          "DEEPSEEK_API_KEY": "{env:DEEPSEEK_API_KEY}"
        },
        "disabled": false
      }
    }
  }
}
```

`{env:DEEPSEEK_API_KEY}` is substituted from OpenCode's process environment at
launch; the secret is never stored in the config file.

### 3. Headless services (no inherited shell environment)

`{env:DEEPSEEK_API_KEY}` is resolved from the environment of the process that
starts OpenCode's background **service**. When that service is autostarted by a
launcher, a login manager, or a service unit that does not source your shell
profile, the variable is missing and every call fails with
`DEEPSEEK_API_KEY is not set`.

For that case, keep the key in a private file outside this repository and let a
launcher script export it before the server starts. The secret still never
appears in `opencode.json`, in the command line, or in any tracked file.

```bash
# 1. The key file — plain KEY=value, no export, no quotes.
umask 077
printf 'DEEPSEEK_API_KEY=sk-your-key\n' > ~/.config/opencode/mcp/deepseek-search.env
chmod 600 ~/.config/opencode/mcp/deepseek-search.env
```

```bash
# 2. The launcher — sources the key file, then execs the server.
cat > ~/.config/opencode/mcp/run-deepseek-search.sh <<'SH'
#!/bin/sh
set -e
MCP_DIR="$HOME/.config/opencode/mcp"
set -a
. "$MCP_DIR/deepseek-search.env"
set +a
exec node "$MCP_DIR/deepseek-search/index.js"
SH
chmod 700 ~/.config/opencode/mcp/run-deepseek-search.sh
```

The service may not have `node` on its `PATH` (version managers such as nvm
usually only export it into interactive shells). If `exec node` fails with
`node: not found`, replace `node` with the absolute path to the binary, for
example `/Users/you/.nvm/versions/node/v22.21.1/bin/node`.

Point the server at the launcher:

```bash
opencode mcp add deepseek-search --global -- ~/.config/opencode/mcp/run-deepseek-search.sh
```

or, by hand:

```jsonc
{
  "mcp": {
    "servers": {
      "deepseek-search": {
        "type": "local",
        "command": ["/Users/you/.config/opencode/mcp/run-deepseek-search.sh"]
      }
    }
  }
}
```

To swap back to the environment-variable route later, delete the
`environment` block from the server entry and point `command` at `index.js`
again.

### 4. Dependencies and restart

```bash
cd ~/.config/opencode/mcp/deepseek-search
npm install
opencode service restart
```

Verify the connection:

```bash
opencode mcp list
# ✓ deepseek-search  connected
```

---

## Usage in OpenCode

Ask in plain language ("search the web for…", "fetch and summarize this URL")
and the agent picks the tools automatically. The tools appear to the model as:

```text
deepseek-search_web_search
deepseek-search_web_fetch
```

Under Code Mode they are grouped by server name. The hyphen is preserved, so
index the group with bracket notation:

```js
const out = await tools["deepseek-search"].web_search({ query: "latest Rust release", count: 5 })
```

---

## Cost and limits

| API | Price | Rate limit |
| --- | --- | --- |
| Search | $0.75 / 1,000 **successful** requests | 5 QPS per account |
| Fetch | $0.75 / 1,000 **successful** requests | 5 QPS per account |

- Billed per successful request, **not** per result or per token. Failed
  requests, empty result sets, and timeouts are free.
- `count` is free: request up to 50 results — with `need_content: true` you get
  up to 50 full pages for the price of one request.
- Search and Fetch have independent quotas.

> Direct API calls are billed from the start. The "free until Nov 1, 2026"
> promotion applies only to server-side tool calls made through DeepSeek
> Harness, Claude Code, or Codex.

---

## Troubleshooting

**`DEEPSEEK_API_KEY is not set`** — the variable is not visible to the server
process. Export it in the environment that starts OpenCode's service, then
`opencode service restart`. If the service does not inherit your shell
profile, use the launcher script from [Headless
services](#3-headless-services-no-inherited-shell-environment) instead.

**`DeepSeek API error (401 …)`** — invalid or revoked key.

**`DeepSeek API error (402 …)`** — insufficient balance; top up the account.

**`DeepSeek API error (429 …)`** — the 5 QPS account limit was exceeded; retry
after a short wait.

**Fetch returns escaped punctuation** (e.g. `\,` `\.`) — DeepSeek returns page
text as-is; this is a property of the source page, not the server.

**Server not connected** — run `opencode mcp list`; check the config path in
`opencode.json` is absolute and that `npm install` was run here.

---

## Files

| File | Purpose |
| --- | --- |
| `index.js` | The MCP server (stdio transport, two tools). |
| `package.json` | Declares the SDK and zod dependencies. |
| `node_modules/` | Installed dependencies. |

The key file and launcher script used by the headless setup live outside this
directory, so this repository stays free of secrets.

## Reference

- Search & Fetch guide: <https://api-docs.deepseek.com/guides/search>
- Search API reference: <https://api-docs.deepseek.com/api/search>
- OpenCode MCP config: <https://opencode.ai/v2/docs/mcp-servers>

Maintenance

ActivityMaintained
ResponsivenessNo issues