Skip to main content
Glama
zztdandan

DeepSeek × Exa Search Combine MCP

by zztdandan

DeepSeek × Exa Search Combine MCP

CI npm license

One stdio MCP server that queries DeepSeek and Exa at the same time and hands your agent a single deduplicated result list — instead of two overlapping ones it has to reconcile itself.

Configure both API keys, or just one. If only one key exists, "both" quietly narrows to that provider instead of failing.

  • Zero dependencies. Node built-ins only (fetch, readline). Nothing to audit, nothing to break.

  • One process, two engines. search fans out in parallel; pages found by both are merged into one entry labelled with every source.

  • Independent failure. A rate-limited or broken provider never removes the other provider's results.

  • Configurable fetch preference. Exa first by default, swap the order with one env var.


Why this exists

Both vendors ship a search MCP. Neither combines them:

Package

Limitation

exa-mcp-server

Exa only

deepseek-mcp-server

No standalone search tool — web_search is a flag inside create_response, honoured only by deepseek-v4-pro

DeepSeek's dedicated Search & Fetch API (/v1/tools/search, /v1/tools/fetch, opened 2026-10-17) is a separate JSON API from its chat endpoints, so nothing was using it as a first-class search backend. This server does, and merges what it returns with Exa.


Related MCP server: Web Search Router

Install

# run without installing
npx -y deepseek-exa-search-combine-mcp

# or install globally
npm i -g deepseek-exa-search-combine-mcp
dxsc status

Requires Node.js 20+ (global fetch).


Configure

Variable

Required

Default

Notes

EXA_API_KEY

one of these

—

https://dashboard.exa.ai/api-keys

DEEPSEEK_API_KEY

one of these

—

https://platform.deepseek.com/api_keys

DEFAULT_SEARCH_PROVIDER

no

both

both | exa | deepseek — used when a tool call omits provider

FETCH_PROVIDER_ORDER

no

exa,deepseek

Fallback order for fetch

SEARCH_HTTP_TIMEOUT_MS

no

60000

Per-request deadline

EXA_BASE_URL

no

https://api.exa.ai

Override for proxies/gateways

DEEPSEEK_BASE_URL

no

https://api.deepseek.com

Override for proxies/gateways

MERGE_DEDUPE

no

true

Set to false to disable cross-provider URL merging

At least one of EXA_API_KEY / DEEPSEEK_API_KEY must be set — the server refuses to start with neither, because a search server with zero backends can only fail later and less clearly.

Client configuration

{
  "mcpServers": {
    "search": {
      "command": "npx",
      "args": ["-y", "deepseek-exa-search-combine-mcp"],
      "env": {
        "EXA_API_KEY": "your-exa-key",
        "DEEPSEEK_API_KEY": "your-deepseek-key"
      }
    }
  }
}

The block above works unchanged for Claude Desktop (claude_desktop_config.json), Cursor (~/.cursor/mcp.json) and most other clients.

Codex CLI:

codex mcp add search \
  --env EXA_API_KEY=your-exa-key \
  --env DEEPSEEK_API_KEY=your-deepseek-key \
  -- npx -y deepseek-exa-search-combine-mcp

Using a local checkout instead of npx avoids any launcher ambiguity on Windows — point command straight at the binary:

{
  "command": "node",
  "args": ["/absolute/path/to/deepseek-exa-search-combine-mcp/bin/dxsc.mjs"],
  "env": { "EXA_API_KEY": "…", "DEEPSEEK_API_KEY": "…" }
}

Tools

Queries every configured provider in parallel, merges and deduplicates.

Parameter

Type

Default

Applies to

query (required)

string

—

both

provider

both | exa | deepseek

both

—

count

integer 1–100

8

Exa ≤ 100, DeepSeek ≤ 50 (clamped per provider)

need_content

boolean

false

both — also return page body

max_chars

integer 200–20000

4000

both — per-page text cap

include_domains

string[]

—

Exa

exclude_domains

string[]

—

Exa

start_published_date

ISO 8601

—

Exa

end_published_date

ISO 8601

—

Exa

category

company | publication | news | personal site | financial report | people

—

Exa

type

auto | lite | deep-lite | deep | instant | fast

auto

Exa

ori_question

string ≤128 chars

—

DeepSeek — original user question

localization

string

—

DeepSeek — IP used to localize results

DeepSeek query operators pass through: site:github.com, -site:example.com, "exact phrase", -word, lang:zh,en, after:2025, before:2026-06-01.

fetch

Pulls full page content, trying providers in order until one returns real text.

Parameter

Type

Default

url

string

—

urls

string[]

—

provider

both | exa | deepseek

configured FETCH_PROVIDER_ORDER

max_chars

integer 200–20000

6000

both means "follow the fallback order", not "call both and compare": the first provider that returns non-empty content wins per URL, so a successful Exa fetch never spends DeepSeek credits.

status

Reports which keys are configured, the default search behaviour and the effective fetch chain. No network calls, no cost.


What "combine" actually means

When both engines return the same page, you get one entry with sources: ["exa", "deepseek"], not two near-duplicates. URLs are compared after:

  • lowercasing the host and dropping the fragment,

  • removing tracking parameters (utm_*, ref, fbclid, gclid, mc_cid, _hsenc, …),

  • collapsing duplicate slashes and stripping the trailing slash.

The first occurrence keeps its position, so provider ranking is preserved. Missing fields are filled from the other provider instead of being discarded, and each provider's own snippet is kept when the two phrase things differently. Set MERGE_DEDUPE=false to get the raw concatenation instead.


CLI

The same code path is reachable without an MCP client, which makes debugging a one-liner:

dxsc status
dxsc search "rust async runtime comparison" --count 5
dxsc search "site:arxiv.org diffusion models" --provider deepseek --count 10
dxsc search "transformer" --content --json
dxsc fetch https://example.com/article --max-chars 8000

Run dxsc --help for every flag. --json prints the structured result instead of Markdown.


Cost

Nothing is cached — two identical calls cost twice.

Provider

Billing

Exa

Per request; roughly $0.007 for a small search. need_content and count both raise it.

DeepSeek

$0.75 / 1,000 successful requests (~$0.00075 each). Failed requests and empty result sets are not billed.

fetch costs one request per provider per URL that actually gets tried, so a working Exa fetch costs one Exa call and zero DeepSeek calls.


Troubleshooting

Symptom

Cause

No API keys configured on start

Neither EXA_API_KEY nor DEEPSEEK_API_KEY reached the process

Provider "deepseek" is not configured

You passed provider: "deepseek" with only an Exa key. Omit provider to auto-narrow

… failed: HTTP 429 (retryable) in Notes

Provider rate limit; the other provider's results are still returned

Nothing loads in the client on Windows

The launcher could not spawn npx. Set command to an absolute node path

Exit code is 1 from the CLI when nothing could be retrieved at all; a partial success exits 0.


Development

npm test        # 77 tests, node:test, no dependencies
npm run check   # syntax check every module

Layout:

bin/dxsc.mjs              entry point (MCP by default, CLI for everything else)
src/config.mjs            env parsing + provider resolution
src/http.mjs              single POST helper, error normalisation
src/providers/            exa.mjs, deepseek.mjs, registry + fan-out
src/merge.mjs             cross-provider dedupe and field merging
src/render.mjs            Markdown output
src/tools.mjs             tool schemas + implementations
src/server.mjs            JSON-RPC dispatch (transport agnostic)
src/transports/stdio.mjs  newline-delimited JSON-RPC over stdio
test/                     unit + protocol tests against a fetch double

The dispatcher is transport-agnostic and takes an injectable fetchImpl, so tests exercise the real protocol and the real provider mapping without network access or a child process.

License

MIT

Available Tools

3 tools
fetchCombined page fetchA

Fetch full page content for one or more URLs. Providers are tried in the configured fallback order (Exa first by default, then DeepSeek) and the first one that returns real content wins per URL. Pass provider="exa" or "deepseek" to pin a single backend.

NameRequiredDescriptionDefault
urlNoA single URL to fetch.
urlsNoSeveral URLs at once. Exa handles the batch in one request.
providerNoOmit or "both" for the configured fallback order; "exa" / "deepseek" to pin one backend.
max_charsNoPer-page output cap. Default 6000.

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations at all, the description carries the full burden and delivers the key non-obvious behavior: providers are tried in a configured fallback order (Exa then DeepSeek) and the first to return real content wins per URL. That is exactly the kind of execution semantics an agent cannot infer. It omits what happens when every provider fails and whether partial batch failures are surfaced.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences with the core purpose front-loaded and no filler. The third sentence on provider pinning partially duplicates the schema's enum description, a minor redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 4-parameter tool with no annotations and no output schema, the description covers execution order but not the return shape (raw text? markdown? metadata?) or failure behavior. The absence of an output schema means the description should say at least roughly what comes back, and it does not.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all four parameters are already documented, and the description's provider sentence largely restates the enum semantics. It adds the useful 'first one that returns real content wins per URL' framing but does not clarify the url-vs-urls relationship or when to prefer one over the other, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb and resource — 'Fetch full page content' for 'one or more URLs' — which an agent can distinguish from 'search' (discovery) and 'status' (health). It stops short of naming the siblings explicitly, so it lands at clear-but-not-differentiated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains provider selection well (fallback order, pinning with provider='exa'/'deepseek'), which is genuine usage guidance. However it never says when to reach for this tool over 'search' — e.g. after search returns URLs, or when full text rather than snippets is needed — so the when-to-use decision against alternatives is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

statusServer statusA

Report which backends this server can reach, the default search behaviour and the fetch fallback order. Makes no network calls and costs nothing.

NameRequiredDescriptionDefault

No parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden and does meaningful work: it discloses that no network calls are made and the call costs nothing, which is exactly the safety/cost signal an agent needs. It stops short of describing the response shape or any caching/staleness caveats.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero filler, and the content enumeration is front-loaded ahead of the cost note. Nothing here could be cut without losing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless informational tool with no output schema, the description is close to sufficient: it enumerates the three things returned (reachable backends, default search behaviour, fallback order) and disclaims side effects. A slightly fuller note on response format would make it complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4. There is nothing for the description to clarify about inputs, and it correctly adds none.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Report) and resource (reachable backends, default search behaviour, fetch fallback order), which clearly marks this as an informational tool rather than a search or fetch. It doesn't explicitly name the siblings search or fetch, so differentiation is inferred from context rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

By mentioning 'default search behaviour' and 'fetch fallback order' it hints at its relationship to the search and fetch siblings, but it never says when to call it (e.g., before search, or to diagnose failures) and provides no exclusions. Usage is implied rather than instructed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv1.0.0
    • First observedfetch
    • First observedsearch
    • First observedstatus

TDQS

A4.1/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct role: search performs multi-provider web search, fetch retrieves page content for URLs, and status reports backend availability without network calls. There is no meaningful overlap that would cause misselection.

Naming Consistency5/5

The names are short, lowercase, and consistently action-oriented or state-oriented: search, fetch, status. The pattern is predictable and easy for an agent to map to intent.

Tool Count5/5

Three tools are well scoped for a focused search-and-fetch server. Each tool earns its place, and there are no redundant or filler tools.

Completeness4/5

The core lifecycle is covered: search the web, fetch full content, and inspect backend status. Minor gaps exist around provider configuration or richer result management, but the essential surface is complete for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    F
    maintenance
    Aggregated search API service that provides real-time web search capabilities for AI assistants via MCP.
    2
    6 npm
    43
    GPL 3.0
  • F
    license
    Not graded
    quality
    D
    maintenance
    A remote MCP server that routes web search queries across multiple providers (HTTP APIs, external MCP servers, LLM with grounding) with intelligent fallback and quota management.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server for multi-engine web search and web page fetching, supporting parallel search, content extraction, and optional LLM-powered search summarization and deep search.
    4
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables querying multiple search engines and paid search APIs through a local aggregation service, returning deduplicated and RRF-ranked results via a single MCP tool.
    1
    MIT