Skip to main content
Glama

cn-websearch-mcp

One MCP tool, several Chinese LLM search backends. A Model Context Protocol server that unifies the official built-in web search of Kimi (Moonshot), Xiaomi MiMo, Zhipu GLM, and StepFun behind a single web_search tool — with configurable provider priority, automatic fallback, multi-source aggregation, per-attempt timeout, and one retry on transient failures.

What it does

Each provider ships web search in a different wire format: Kimi needs a 4-step chat "formula" loop with server-side fiber execution, MiMo expects a web_search tool on OpenAI chat completions, Zhipu runs a standalone Search REST API, and StepFun exposes a dedicated /v1/search endpoint. This server normalizes all of them into one schema and gives you two strategies:

  • fallback (default) — try providers in your priority order, return the first success. Cheap, low latency.

  • aggregate — query several providers in parallel, merge the results, dedupe by URL and tag each item with its source provider. Wider coverage.

fallback:   kimi ──✓ 1.2s → return          aggregate:  kimi  ─┐
            stepfun (only if kimi failed)               stepfun ─┼─→ merge + dedupe → return
            zhipu   (only if the above failed)          zhipu   ─┘

Related MCP server: mcp-toolkit

Install

Requires Node >= 18. From a checkout:

npm install
npm run build     # tsc → dist/

npx cn-websearch-mcp also works once the package is published to npm (it is not yet).

Provide at least one provider API key — via environment variables, a .env file, or a JSON config file (see Configuration). Providers without a key are skipped automatically.

Use it as an MCP server

Point your MCP client at the built entry point. Keys go in the client's env block — the server reads .env relative to its working directory, which is not necessarily your project.

{
  "mcpServers": {
    "cn-websearch": {
      "command": "node",
      "args": ["/absolute/path/to/cn-websearch-mcp/dist/index.js"],
      "env": {
        "STEPFUN_API_KEY": "sk-...",
        "WEBSEARCH_STRATEGY": "aggregate"
      }
    }
  }
}

Claude Code:

claude mcp add cn-websearch -e STEPFUN_API_KEY=sk-... -- node /absolute/path/to/cn-websearch-mcp/dist/index.js

Running the binary with no arguments starts the stdio MCP server, so existing MCP client configurations keep working.

Use it in a terminal

The same binary is a CLI, so you can search and test without wiring up a client.

cn-websearch-mcp                       # start the MCP stdio server (default)
cn-websearch-mcp search "query text"   # one-shot search
cn-websearch-mcp search --strategy aggregate --count 12 "query text"
cn-websearch-mcp status                # effective settings + provider status
cn-websearch-mcp test                  # probe every ready provider once
cn-websearch-mcp repl                  # interactive session
cn-websearch-mcp help                  # full usage

Options: -n/--count <1-50>, --strategy fallback|aggregate, --providers a,b (restrict this call), --no-dedupe, -q/--query (query for test), --json (raw output for scripting), -h, -v.

Exit codes: 0 success, 1 runtime failure (search failed / nothing configured), 2 usage error — so scripts and CI can branch on them.

In the interactive session, bare text is a search and / commands control the session:

cn-websearch> 最近一周国内发布的大模型
cn-websearch> /strategy aggregate      # switch this session to multi-source
cn-websearch> /aggregate rust async    # one-off multi-source search
cn-websearch> /count 12
cn-websearch> /providers stepfun,zhipu # restrict this session
cn-websearch> /test stepfun            # probe one provider
cn-websearch> /status  /config  /json on  /help  /quit

Configuration

Configuration is merged in this order — later layers win:

built-in defaults → JSON config file → environment variables

Environment variables win because MCP clients can generally only pass env.

Config file

Put cn-websearch.config.json in the working directory; it is picked up automatically. Or point at it explicitly with WEBSEARCH_CONFIG=/path/to/file.json.

See cn-websearch.config.example.json for every supported key. A minimal example:

{
  "strategy": "aggregate",
  "providers": {
    "stepfun": { "apiKey": "sk-...", "priority": 10 },
    "zhipu": { "priority": 5, "options": { "searchEngine": "search_pro" } },
    "kimi": { "enabled": false }
  }
}

If you put API keys in this file, do not commit itcn-websearch.config.json is git-ignored by default for that reason (use git add -f if you keep a keyless, shareable config there).

Choosing provider priority

Two equivalent ways, evaluated in this order:

  1. order (config file) or WEBSEARCH_ORDER (env) — an explicit list, highest priority first: ["stepfun", "zhipu"].

  2. priority per provider — a number, higher goes earlier. Ties are broken alphabetically so the result is deterministic.

  3. Neither set → alphabetical default (kimi, mimo, stepfun, zhipu).

Set in the config file:

{ "providers": { "stepfun": { "priority": 10 }, "zhipu": { "priority": 5 } } }

or by environment:

WEBSEARCH_ORDER=stepfun,zhipu,kimi
STEPFUN_PRIORITY=10

On the command line, --providers narrows a single call without changing the configured priority.

Settings

Config file

Environment

Default

Meaning

strategy

WEBSEARCH_STRATEGY

fallback

fallback = first success wins; aggregate = multi-source merge

order

WEBSEARCH_ORDER

alphabetical

Explicit provider priority list

count

WEBSEARCH_COUNT

8

Default result count when a tool call omits count

timeoutMs

WEBSEARCH_TIMEOUT_MS

30000

Budget per attempt; a retry gets a fresh budget, so one provider's worst case is ~2×

maxProviders

WEBSEARCH_MAX_PROVIDERS

4

Cap on providers per call (chain length / fan-out)

dedupe

WEBSEARCH_DEDUPE

true

Merge duplicate URLs when aggregating

WEBSEARCH_CONFIG

Explicit config file path

Booleans accept true/false, 1/0, yes/no, on/off. Invalid values are ignored with a warning rather than failing.

Per-provider settings

Every provider supports the same generic knobs, in the config file or as <NAME>_<SUFFIX> environment variables:

apiKey (_API_KEY), baseUrl (_BASE_URL), model (_MODEL), enabled (_ENABLED), priority (_PRIORITY), timeoutMs (_TIMEOUT_MS, overrides the global budget for that provider), and options for provider-specific parameters:

Provider

options

Notes

kimi

maxRounds (1-5, default 2), maxTokens (256-32768, default 8192)

Kimi-specific: rounds of the web-search loop before the final answer

mimo

location (country/region/city, default country), maxKeyword (1-10, default 3), forceSearch (default true)

stepfun

category

Omitted unless set

zhipu

searchEngine (default search_std), contentSize (default high)

searchEngine also readable from ZHIPU_SEARCH_ENGINE

Keys are never logged or echoed: error text is scrubbed of credential-looking strings, and status output only reports whether a key is set.

Tools

Input: { "query": string, "count"?: integer, "strategy"?: "fallback"|"aggregate", "providers"?: string[] }.

count defaults to your configured count, strategy to your configured strategy, and providers (when given) must name providers that are enabled and have a key — otherwise the call returns a structured error naming the problem rather than silently ignoring it.

Output: normalized results plus an audit trail. In aggregate mode each item carries source, and _meta.providers lists everyone who answered:

{
  "results": [
    {
      "title": "…",
      "url": "https://…",
      "snippet": "…",
      "content": "optional full text when the provider returns it",
      "published_date": "2026-09-06",
      "source": "stepfun"
    }
  ],
  "_meta": {
    "provider": "stepfun",
    "providers": ["stepfun", "zhipu"],
    "total_latency_ms": 2586,
    "attempts": [
      { "provider": "stepfun", "status": "ok", "latency_ms": 2025 },
      { "provider": "zhipu", "status": "transient_error", "latency_ms": 611, "error": "HttpError: HTTP 429: …" }
    ]
  }
}

provider_status

Read-only: effective strategy and settings, and per provider whether it is enabled, has a key, and is in the active chain.

Fallback & failure semantics

  • Only providers that are enabled and have a key participate. fallback walks them in priority order; aggregate queries them in parallel.

  • Per attempt: one wall-clock budget (timeoutMs); hung requests are aborted and recorded as timeout.

  • Transient failures (network errors, HTTP 5xx, 429, timeout) are retried once, then the next provider is tried.

  • Permanent failures (HTTP 4xx) skip the retry and move on immediately.

  • In aggregate, partial failure is not failure: successful providers' results are returned and the failures stay in _meta.attempts.

  • Every attempt is recorded in _meta.attempts — success, retry, timeout or error.

  • If everyone fails, web_search returns a structured error containing the full attempt list.

Provider support matrix

Provider

Channel used

Structured results

Full text

StepFun

POST /v1/search REST API

✅ (content)

Zhipu GLM

POST /api/paas/v4/web_search standalone API

summary

MiMo

OpenAI chat completions + web_search tool

citations

✗ (LLM answer in _meta.answer)

Kimi

chat "web-search formula" 4-step loop

reference URLs

✗ (LLM answer in _meta.answer)

Note on Kimi/MiMo: these providers return an LLM-synthesized answer plus citations rather than a plain result list. This server surfaces the citations as results and puts the synthesized answer in _meta.answer (labelled per provider when aggregating several).

Development

npm install
npm run build          # tsc → dist/
npm test               # vitest, all HTTP mocked (no keys needed)
npm run test:coverage  # coverage gate: 95% minimum on src/
npm run smoke          # real requests against every ready provider, prints a latency table
npm run cli -- repl    # run the CLI from source via tsx

Conventions

  • Comments and file headers are written in English.

  • Runtime-visible strings stay in English — tool descriptions, CLI output, log lines and error messages — so clients and scripts get stable, greppable output.

  • SERVER_NAME / SERVER_VERSION in src/server-info.ts are the single source of truth for the server identity; test/server-info.test.ts asserts they match package.json on every test run.

  • Layering is one-directional: types / errors / config-file / normalize at the bottom, then config / http, then orchestrator / probe, then providers, then runtime / tools / cli. madge --circular is clean.

License

MIT

Available Tools

2 tools
provider_statusA

Read-only status: effective strategy and settings, plus which providers are enabled, have API keys and are part of the active search chain.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior4/5

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

No annotations are provided, so the description carries the behavioral disclosure burden. It explicitly declares the operation is read-only and enumerates the information included, which is the key behavioral trait for a parameterless status tool. It does not discuss failure behavior or auth, but that is less critical for a read-only status endpoint.

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?

The entire description is one sentence, front-loaded with 'Read-only status' and followed by a compact but precise enumeration of what the status includes. Every clause earns its place; there is no filler.

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 zero-parameter tool, the description sufficiently covers what the agent needs: the operation is read-only, and the list of reported items is explicit. Since there is no output schema, a slightly more detailed return-format hint would improve completeness, but it is not required to call the tool correctly.

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 has zero parameters and 100% schema description coverage, so the schema already fully defines inputs; the baseline is 4. The description adds value by clarifying what the returned status covers, though no parameter-level explanation is needed.

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

Purpose5/5

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

The description names the resource (provider status) and specifies exactly what it reports: effective strategy/settings, enabled providers, API-key presence, and active search chain membership. The 'read-only status' framing clearly distinguishes it from the sibling web_search tool, which performs searches.

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?

Usage is implied rather than stated: the tool is obviously for checking provider/strategy status, and web_search is for searching. However, the description never explicitly says 'use this when you need to inspect configuration' or contrasts it with web_search.

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. 2 tool updatesv0.2.0
    • First observedprovider_status
    • First observedweb_search

TDQS

A4.4/5.0

Scored across 2 tools

Disambiguation5/5

The two tools are clearly distinct: web_search performs searches, while provider_status reads configuration and provider health. There is no overlap or ambiguity between them.

Naming Consistency4/5

Both names are concise, readable, and use snake_case consistently. web_search follows a verb_noun pattern while provider_status is noun-based, but they remain predictable and clearly tied to the server's purpose.

Tool Count3/5

With only two tools, the server sits at the low end of acceptable scope. It feels slightly thin, but the narrow search-focused purpose makes the minimal count defensible.

Completeness5/5

The domain is a stateless web search service, and the two tools fully cover its needs: performing searches and checking provider status/configuration. There are no obvious dead ends or missing lifecycle operations.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Wraps the Kimi Coding Search and Fetch APIs into MCP tools for web searching and content retrieval. It enables LLMs to perform targeted searches and crawl web pages using standardized interfaces.
    1
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    A plug-and-play MCP toolkit providing AI agents with web search (Chinese sources prioritized), file operations, and shell command execution capabilities.
    2
    MIT
  • F
    license
    A
    quality
    B
    maintenance
    A local web search MCP server supporting parallel, API, and model-based search modes, integrating Zhipu Web Search API and online models for real-time information retrieval.
    10
    -
  • A
    license
    Not graded
    quality
    B
    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