cn-websearch-mcp
Allows web search through Xiaomi MiMo's built-in search backend, returning LLM-synthesized answers with citations.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cn-websearch-mcpsearch the web for recent Chinese AI model releases"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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.jsRunning 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 usageOptions: -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 /quitConfiguration
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 it — cn-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:
order(config file) orWEBSEARCH_ORDER(env) — an explicit list, highest priority first:["stepfun", "zhipu"].priorityper provider — a number, higher goes earlier. Ties are broken alphabetically so the result is deterministic.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=10On the command line, --providers narrows a single call without changing the configured priority.
Settings
Config file | Environment | Default | Meaning |
|
|
|
|
|
| alphabetical | Explicit provider priority list |
|
|
| Default result count when a tool call omits |
|
|
| Budget per attempt; a retry gets a fresh budget, so one provider's worst case is ~2× |
|
|
| Cap on providers per call (chain length / fan-out) |
|
|
| Merge duplicate URLs when aggregating |
— |
| — | 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 |
| Notes |
|
| Kimi-specific: rounds of the web-search loop before the final answer |
|
| |
|
| Omitted unless set |
|
|
|
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
web_search
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.
fallbackwalks them in priority order;aggregatequeries them in parallel.Per attempt: one wall-clock budget (
timeoutMs); hung requests are aborted and recorded astimeout.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_searchreturns a structured error containing the full attempt list.
Provider support matrix
Provider | Channel used | Structured results | Full text |
StepFun |
| ✅ | ✅ ( |
Zhipu GLM |
| ✅ | summary |
MiMo | OpenAI chat completions + | citations | ✗ (LLM answer in |
Kimi | chat "web-search formula" 4-step loop | reference URLs | ✗ (LLM answer in |
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 tsxConventions
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_VERSIONinsrc/server-info.tsare the single source of truth for the server identity;test/server-info.test.tsasserts they matchpackage.jsonon every test run.Layering is one-directional:
types/errors/config-file/normalizeat the bottom, thenconfig/http, thenorchestrator/probe, thenproviders, thenruntime/tools/cli.madge --circularis clean.
License
Available Tools
2 toolsprovider_statusA
Read-only status: effective strategy and settings, plus which providers are enabled, have API keys and are part of the active search chain.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
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.
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.
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.
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.
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.
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.
web_searchA
Search the web through multiple Chinese LLM providers (any of: Kimi, MiMo, StepFun, Zhipu GLM), depending on which ones you configured. Two strategies: 'fallback' tries providers in your configured priority order and returns the first success; 'aggregate' queries several providers in parallel and merges the results (deduplicated by URL, each item tagged with its source provider). Per-attempt timeout, one retry on transient failures. Returns normalized results { title, url, snippet, content?, published_date?, source? } plus _meta with the answering provider(s), total latency and a per-attempt audit trail.
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | Desired number of results (clamped per provider limits) | |
| query | Yes | The search query | |
| strategy | No | 'fallback' = first provider that answers wins; 'aggregate' = query several providers and merge. Defaults to the configured strategy. | fallback |
| providers | No | Optional subset of providers to use for this call, in priority order. Only providers that are enabled and have an API key can be selected. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden, and it excels: it discloses per-attempt timeout, one retry on transient failures, the merging/dedup behavior, source tagging, and the _meta audit trail with provider(s), latency, and per-attempt details. This is far beyond typical descriptions and leaves little about execution behavior hidden.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but well-structured, front-loading the core purpose before the strategy details. Every clause contributes useful context—providers, strategies, retries, result shape, and metadata—without redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given there is no output schema, the description appropriately documents the normalized result shape { title, url, snippet, content?, published_date?, source? } and the _meta structure. It covers provider selection, strategy behavior, timeout, retry, and output format, making the tool fully understandable for an agent even without inspecting schema definitions.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaningful semantics beyond the schema: it clarifies what fallback versus aggregate actually do, that results are deduplicated by URL, and that each result is tagged with its source provider. These details enrich the strategy and providers parameters beyond their terse schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource, 'Search the web,' and immediately distinguishes this tool from the sibling provider_status by focusing on web search rather than status inspection. It also identifies the provider ecosystem (Kimi, MiMo, StepFun, Zhipu GLM), making the tool's scope unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear strategic context: fallback is for trying providers in priority order until one succeeds, while aggregate is for parallel queries with merged results. It also explains that provider availability depends on configuration and API keys. It does not explicitly name provider_status as the alternative, so no exclusion guidance, but the intended usage is clear.
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.
2 tool updates
v0.2.0- First observed
provider_status - First observed
web_search
TDQS
Scored across 2 tools
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.
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.
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.
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
Related MCP Connectors
Scrape, crawl and search the web for AI agents via MCP.
Web search, scraping, RAG answers with citations, and translation as MCP tools.
Web MCP: scrape/crawl sites, web search, brand assets, app stores, YouTube, Reddit, Hacker News.
Jina AI Reader/Search MCP — turn any URL into clean LLM-ready markdown, plus web search.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceWraps 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-
- AlicenseNot gradedqualityDmaintenanceA plug-and-play MCP toolkit providing AI agents with web search (Chinese sources prioritized), file operations, and shell command execution capabilities.2MIT
- FlicenseAqualityBmaintenanceA 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-
- AlicenseNot gradedqualityBmaintenanceMCP server for multi-engine web search and web page fetching, supporting parallel search, content extraction, and optional LLM-powered search summarization and deep search.4MIT