Content
<div align="center">
[English](./docs/README_EN.md) |
Standard MCP Web Search Service for Cherry Studio, Claude Code, and Codex
**Deep Search · 270s Active Budget · Grok Concurrent 2 · Tavily Per Key Concurrent 1**
[](https://github.com/Timmyzzo/WebSearch-MCP/actions/workflows/ci.yml)
[](LICENSE)
[](https://www.python.org/)
[](https://modelcontextprotocol.io/)
</div>
<p align="center">
<a href="#quick-start">Quick Start</a> ·
<a href="#why-choose-websearch-mcp">Core Capabilities</a> ·
<a href="#tool-overview">Tools</a> ·
<a href="#configuration">Configuration</a> ·
<a href="./docs/CLIENT_SETUP.md">Client Setup</a>
</p>
## What is WebSearch MCP
WebSearch MCP combines Grok's AI-powered internet search with Tavily's structured retrieval, web extraction, and site mapping into a standard MCP stdio service. It does not rely on any client's proprietary capabilities and does not modify the local configuration of Cherry Studio, Claude Code, or Codex.
```text
MCP Client ──stdio──► WebSearch MCP
├─ web_search ─► Grok /v1/chat/completions + Optional Tavily Source
├─ get_sources ─► Search Source Cache
├─ web_fetch ─► Tavily Extract
└─ web_map ─► Tavily Map
```
## Why Choose WebSearch MCP
| Capability | Actual Behavior |
| --- | --- |
| Deep-First | Each search covers at least 5 independent perspectives and digs deep into 2 directions, typically resulting in 7-12 retrieval actions. |
| Strong Model Priority | Always uses the user's configured single strongest Grok model; temporary errors default to a maximum of 5 real calls. |
| Single Upstream Protocol | Only calls OpenAI-compatible `/v1/chat/completions`, without enabling Responses or automatic protocol switching. |
| Evidence Integration | Tavily candidate evidence enters Grok's same verification and final synthesis, rather than just caching afterwards. |
| Explainable Reliability | Approximately 270s server-side total budget, Grok process-level concurrency 2, Tavily per Key concurrency 1, circuit breaking, `Retry-After`, and complete flow verification. |
| Stable Compatibility | Standard MCP stdio, fixed tool schema, unified `success` / `partial_success` / `error`. |
Suitable for the following scenarios:
- Let coding assistants retrieve the latest official documentation, releases, issues, and technical information.
- Obtain real-time search answers with traceable sources.
- Extract web content as Markdown or discover document site URL structures.
- Reuse the same tool schema and environment variables across multiple MCP clients.
## Current Status
- P0 repository and testing baseline: completed.
- P1 old crawling service cleanup and modularization: completed.
- P2 Tavily multi-Key reliability: completed.
- P3 Grok single strong model and retry: completed.
- P4 unified return protocol: completed.
- P5 search prompt and search quality refactoring: completed.
- Search timeout and concurrency governance: automated implementation completed; waiting for Cherry Studio 300s outer layer timeout manual verification.
- External project code audit and bounded runtime cache: completed; runtime fixed using Chat Completions.
- Next phase: P6 cross-client real human acceptance.
See the [development roadmap document](./docs/DEVELOPMENT_ROADMAP.md) for complete requirements and acceptance criteria.
## Quick Start
### 1. Prepare Environment
Required:
- Python 3.10+
- [uv](https://docs.astral.sh/uv/getting-started/installation/)
- An OpenAI-compatible Grok API address and Key
- Optional Tavily Key; `web_fetch`, `web_map`, and additional Tavily source require it
### 2. Add MCP Service
The following configuration can be directly copied; replace API addresses, Keys, and models with your actual values. `GROK_API_URL` must be an API root address ending with `/v1`, which only calls `/v1/chat/completions` and `/v1/models`.
#### Cherry Studio (JSON)
```json
{
"mcpServers": {
"grok-search": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/Timmyzzo/WebSearch-MCP",
"grok-search"
],
"env": {
"GROK_API_URL": "https://your-api-endpoint.example/v1",
"GROK_API_KEY": "your-grok-api-key",
"GROK_PRIMARY_MODEL": "grok-4-fast",
"GROK_MODEL_MAX_ATTEMPTS": "5",
"GROK_MAX_CONCURRENCY": "2",
"WEB_SEARCH_TOTAL_TIMEOUT": "270",
"TAVILY_PER_KEY_MAX_CONCURRENCY": "1",
"TAVILY_API_KEYS": "tvly-key-1,tvly-key-2"
}
}
}
}
```
Cherry Studio also needs to set the MCP tool call timeout to `300` seconds.
#### Claude Code / cc (complete JSON)
Save the following object as JSON or use it as a parameter for `claude mcp add-json`:
```json
{
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"git+https://github.com/Timmyzzo/WebSearch-MCP",
"grok-search"
],
"env": {
"GROK_API_URL": "https://your-api-endpoint.example/v1",
"GROK_API_KEY": "your-grok-api-key",
"GROK_PRIMARY_MODEL": "grok-4-fast",
"GROK_MODEL_MAX_ATTEMPTS": "5",
"GROK_MAX_CONCURRENCY": "2",
"WEB_SEARCH_TOTAL_TIMEOUT": "270",
"TAVILY_PER_KEY_MAX_CONCURRENCY": "1",
"TAVILY_API_KEYS": "tvly-key-1,tvly-key-2"
}
}
```
Linux/macOS installation command:
```bash
claude mcp add-json grok-search --scope user "$(cat grok-search.json)"
```
PowerShell installation command:
```powershell
claude mcp add-json grok-search --scope user (Get-Content .\grok-search.json -Raw)
```
#### Codex / cx (official `config.toml` format)
Add the following complete configuration to `~/.codex/config.toml`:
```toml
[mcp_servers.grok-search]
command = "uvx"
args = [
"--from",
"git+https://github.com/Timmyzzo/WebSearch-MCP",
"grok-search",
]
startup_timeout_sec = 30
tool_timeout_sec = 300
[mcp_servers.grok-search.env]
GROK_API_URL = "https://your-api-endpoint.example/v1"
GROK_API_KEY = "your-grok-api-key"
GROK_PRIMARY_MODEL = "grok-4-fast"
GROK_MODEL_MAX_ATTEMPTS = "5"
GROK_MAX_CONCURRENCY = "2"
WEB_SEARCH_TOTAL_TIMEOUT = "270"
TAVILY_PER_KEY_MAX_CONCURRENCY = "1"
TAVILY_API_KEYS = "tvly-key-1,tvly-key-2"
```
See:
- [Client setup guide (English)](./docs/CLIENT_SETUP_EN.md)
### 3. Verification
Confirm that the client can discover the following core tools:
```text
web_search
get_sources
web_fetch
web_map
get_config_info
switch_model
```
It is recommended to call `get_config_info` first to check the desensitized configuration and Grok `/models` connection, and then execute `web_search` once.
## Configuration
| Variable | Required | Default | Description |
| --- | --- | --- | --- |
| `GROK_API_URL` | Yes | - | OpenAI-compatible API root address (usually ending with `/v1`), providing `/chat/completions` and `/models`. |
| `GROK_API_KEY` | Yes | - | Grok API Key. |
| `GROK_PRIMARY_MODEL` | No | see below | The strong model name used for each search, filled by the user. |
| `GROK_MODEL_MAX_ATTEMPTS` | No | `5` | The maximum number of real requests for the current model for recoverable faults, must be a positive integer. |
| `GROK_MAX_CONCURRENCY` | No | `2` | The maximum number of Grok `/chat/completions` requests sent simultaneously by the same MCP process; the safety upper limit is 2. |
| `WEB_SEARCH_TOTAL_TIMEOUT` | No | `270` | The server-side total wall clock budget for a single `web_search`, in seconds. |
| `GROK_MODEL` | No | `grok-4-fast` | Compatible configuration; maps to the primary model when non-empty `GROK_PRIMARY_MODEL` is not set. |
| `TAVILY_API_KEY` | No | - | Single Tavily Key. |
| `TAVILY_API_KEYS` | No | - | Multiple Tavily Keys, supporting comma, semicolon, or line breaks separation, prioritizing single Key. |
| `TAVILY_API_URL` | No | `https://api.tavily.com` | Tavily API root address. |
| `TAVILY_ENABLED` | No | `true` | Whether to enable Tavily. |
| `TAVILY_KEY_COOLDOWN` | No | `30` | Temporary rate limiting or single Key temporary anomaly cooldown seconds. |
| `TAVILY_QUOTA_COOLDOWN` | No | `3600` | Default cooldown seconds for quota-exhausted Keys. |
| `TAVILY_SERVICE_FAILURE_THRESHOLD` | No | `2` | The number of different Key failures of the same type required to trigger service-level circuit breaking, minimum 2. |
| `TAVILY_SERVICE_COOLDOWN` | No | `30` | Tavily service-level circuit breaking cooldown seconds. |
| `TAVILY_PER_KEY_MAX_CONCURRENCY` | No | `1` | Search, Extract, Map shared per Key real request concurrency upper limit; currently must be 1. |
| `GROK_DEBUG` | No | `false` | Whether to record debug information. |
| `GROK_LOG_LEVEL` | No | `INFO` | Log level. |
| `GROK_LOG_DIR` | No | `logs` | Log directory. |
| `GROK_RETRY_MULTIPLIER` | No | `1` | Exponential backoff multiplier. |
| `GROK_RETRY_MAX_WAIT` | No | `10` | Maximum seconds for single backoff. |
When only configuring Grok, `web_search` can still be used. Setting `TAVILY_ENABLED=false` will disable Tavily even if Tavily Keys exist in the environment.
The model resolution priority is: the model set by `switch_model` in the current process, non-empty `GROK_PRIMARY_MODEL`, non-empty `GROK_MODEL`, model in the configuration file, and the default value `grok-4-fast`. Environment variables are considered unset when they only contain whitespace. The service will not automatically degrade to a weaker backup model; please directly configure the strongest available model you wish to use.
## Tool Overview
| Tool | Purpose | Tool-specific Fields |
| --- | --- | --- |
| `web_search` | Grok main search, optional Tavily candidate evidence synthesis | `session_id`, `content`, `sources_count`, `grok_error`, `tavily_error` |
| `get_sources` | Read the complete source of a search | `session_id`, `sources`, `sources_count` |
| `web_fetch` | Use Tavily Extract to extract Markdown | `url`, `content`, `provider`, `tavily_error` |
| `web_map` | Use Tavily Map to discover site structure | `base_url`, `results`, `response_time`, `tavily_error` |
| `get_config_info` | View desensitized configuration and test Grok connection | `configuration`, `connection_test` |
| `switch_model` | Persist and switch the current process's Grok primary model | `success`, `previous_model`, `current_model` |
All tools also return `status`, `error`, `error_detail`, and `partial` uniformly. `web_search`'s `query` is the only required parameter. Planning tools are optional capabilities and not prerequisites for searching; all `thought` parameters are optional.
## Search Quality and Depth-First Strategy
Each `web_search` uses a bounded `deep` strategy: first retrieve at least 5 genuinely different perspectives, then select at least 2 most relevant or most uncertain directions for further exploration, typically resulting in 7-12 retrieval actions. Person identities, strong timeliness, high risk, comparisons, niche, and controversial issues usually increase to 10-16. Simple facts and single official documents will not be lower than this limit, but the answer length still keeps concise according to the question itself.
This execution limit aligns with the original project's verified strategy: the original project requires more than 5 breadth perspectives and at least 2 deep exploration directions; this project adds deterministic budget, native language and entity-related language retrieval, source level, counter-checking, and Tavily candidate evidence synthesis. Tiny wording changes cannot be counted as different perspectives, and reaching the count cannot replace evidence quality.
These numbers are bounded search budgets in the prompt and will not form an infinite tool loop. Fuzzy entity investigations will expand aliases, accounts, organizations, teams, collaborators, events, and time ranges, and divide conclusions into direct confirmation, strong support, reasonable candidates, and conflict/exclusion, while providing explainable confidence levels. The absence of a single real-name binding page will not let the search stop early but will not disguise speculation as fact. User queries and platform prompts are passed in JSON data; instructions in web pages, search snippets, and user input cannot override system search rules.
When `extra_sources>0`, Tavily will first provide structured URL, title, and summary candidates, and Grok will then combine its own internet search to complete evidence verification and answer synthesis; candidate content is still considered unreliable data and will not override system rules. When Tavily fails, Grok can still return `partial_success`; when Grok fails, Tavily cannot replace the final answer.
Grok's upstream protocol is fixed as streaming Chat Completions. The service will not read protocol selection environment variables, will not call `/responses`, and will not automatically switch endpoints during failures; the relay station only needs to be compatible with `/v1/chat/completions` and `/v1/models`.
The general source priority is: official documentation/standards/regulations/original data/papers and systematic reviews, authoritative institutions and project maintenance teams, fact-checked professional media, professional practice experience, and finally blogs, forums, and social media clues. Key conclusions prioritize high-level sources; reprinted same original messages are not counted as independent evidence, and insufficient evidence will be clearly stated.
Domain strategies include:
- Software and GitHub: prioritize current default branch documentation, README, Release, Changelog, migration guides, API Reference, commit, issue, PR, and maintainer instructions, and verify stable versions, release dates, deprecation, and final merged code.
- Fitness, health, nutrition, and recovery: distinguish research support, expert practice, and athlete personal experience, combining training age, injury, foundation, recovery, equipment, and cycle; clearly state medical assessment boundaries for injury, disease, medication, or extreme diet.
- Automotive and other high-risk safety issues: prioritize official tests and real accident data, distinguish collision avoidance and occupant protection, do not compare star ratings across incompatible standards, and explain statistical limitations and uncertainties.
- Niche, fuzzy, or scarce evidence issues: first define concepts, use synonyms or multi-language retrieval if necessary, actively seek counterexamples, failure cases, and different schools, and try to cross-validate with two types of independent sources.
Queries like "latest", "current", "today", "current version", "still supported", etc., will use runtime actual dates and time zones, verify versions, release dates, and material update times. Complex answers explain evidence levels, controversies, limitations, applicable ranges, and uncertainties as needed; simple answers will not be forced to apply lengthy templates. P4's `success`, `partial_success`, `error`, `error_detail`, and all compatible fields remain unchanged.
Concurrency Governance
Cherry Studio suggests setting the outer timeout for MCP tools to ; this is to avoid clients producing the `-32001` security upper limit prematurely, not a performance target. The server-side single `web_search` uses a default total wall clock budget of `WEB_SEARCH_TOTAL_TIMEOUT=270` and actively returns success, partial success, or structured errors within this budget, leaving about 30 seconds for MCP process scheduling, and client transmission.
Grok's single read 120 seconds, but the actual available time for each real attempt will be shortened to the smaller of "120 seconds and the current budget". `GRO_MAX_ATTEMPTS=5` only means a maximum of 5 real HTTP requests, not guaranteeing that it will execute 5 times: waiting for Grok slots, Tavily Key slots, HTTP transmission, stream reading, exponential backoff, and `Retry-After` all consume the same total budget; if the remaining budget is not enough to accommodate a reasonable new attempt, it will stop early.
By default, the same MCP process can execute at most 2 Grok HTTP requests concurrently. Tavily Search, Extract, and Map share key health and occupancy status, with each key allowing at most 1 real request at a time; multiple healthy keys can each bear one concurrent request. All slots are released in success, error, cancellation, timeout, and stream interruption paths, and retries must be requeued. Budget termination diagnostics will distinguish between `max_attempts_exhausted`, `non_retryable_error`, `total_budget_exhausted`, and `concurrency_queue_timeout`, and report configuration/actual attempts, time consumption, budget, and queuing time.
## Unified Return Protocol
`status` has only three stable values:
- `success`: The tool's goal is fully completed. A legitimate empty source list can be successful, e.g., Grok gives a valid answer but has no source.
- `partial_success`: Available results have been returned, but some supplementary components or non-critical steps have failed. For example, Grok is successful, but Tavily supplementation fails; planning is not yet complete; the site map contains some invalid items.
- `error`: The current tool's goal is not completed. Empty answers, empty crawl content, empty URL mapping, configuration errors, and upstream failures will not masquerade as success.
| Tool | `success` | `partial_success` | `error` and empty result |
| --- | --- | --- | --- |
| `web_search` | Grok returns a non-empty valid answer; the source can be empty. | Grok is successful but the requested Tavily supplementation fails. | Grok ultimately fails, stream interruption, invalid/empty answer, or configuration error; Tavily's success cannot replace Grok's answer. |
| `get_sources` | The session exists; `sources=[]` is a legitimate empty result. | Only some sources in the cache can be verified. | The session does not exist/expire or the cache component fails. |
| `web_fetch` | Tavily returns non-empty Markdown. | The current single URL extraction is an atomic operation, and there is no partial success for now. | Configuration, authentication, rate limiting, service, parameter errors, or upstream success but no body ofavily_no_content`. |
| `web_map` | Returns at least one URL and the response is complete. | Returns a URL, but the root URL is missing or invalid items are ignored. | Tavily failure, or upstream success but no URL ofavily_no_urls`. |
| `get_config_info` | The desensitized configuration reading and Grok connection test both succeed. | The configuration can be returned, but the connection/authentication/configuration test fails. | Even the desensitized configuration object cannot be constructed. |
| `switch_model` | The main model is successfully written to the current process and compatible configuration. | Atomic writing, no partial success for now. | The model is empty or configuration persistence fails; only the main model is modified. |
| Planning tool | The required phase is completed and an executable plan is generated. | The session is valid but some required phases are not yet completed. | The session does not exist, JSON parameters are invalid, or the fails. |
Specification errors are located in `error_detail`:
```json
{
"code": "tavily_service_unavailable",
"message": "Tavily service is temporarily unavailable",
"service": "tavily",
"retryable": true,
"http_status": 503,
"upstream_code": "upstream_unavailable",
"diagnostics": {
"service_circuit": {"state": "open", "retry_after_seconds": 30}
}
}
```
Diagnostic information only contains necessary desensitized fields, not Grok/Tavily Key, Authorization headers, response bodies that may echo credentials, Python traceback, or internal object representations. Structured errors only end the current tool call, and stdio MCP processes can still discover tools and make subsequent calls.
Compatible field mapping:
| Old field | P4 mapping |
| --- | --- |
| `error` | Continue to retain string form of old error code or old message; new callers should read `error_detail`. |
| `partial` | `true` when `status="partial_success"`, default `false` for other states. |
| `tavily_error` | Retain P2 Key status and service fuse summary, and supplement retryability, HTTP/upstream error codes. |
| `grok_error` | Retain P3 compatible fields; in single-model mode, `fallback_model=null`, `fallback_attempts=0`, `switched_model=false`. |
| `content`, `results`, `success` | Continue to retain original tool fields; success is uniformly based on `status`. |
Typical returns are as follows.
`web_search` complete success; a valid answer without source is still successful:
```json
{"status":"success","session_id":"abc123","content":"valid answer","sources_count":0,"error":null,"error_detail":null,"partial":false}
```
Grok success but Tavily supplementation fails:
```json
{"status":"partial_success","session_id":"abc123","content":"valid answer","sources_count":0,"partial":true,"error":null,"error_detail":{"code":"tavily_all_keys_unavailable","message":"All Tavily Keys are unavailable","service":"tavily","retryable":false,"http_status":401,"upstream_code":"invalid_api_key","diagnostics":{"key_statuses":[{"fingerprint":"tvly…1234","state":"invalid"}]}},"tavily_error":{"code":"tavily_all_keys_unavailable","message":"All Tavily Keys are unavailable"}}
```
When ultimately fails, even if Tavily is successful, it will not masquerade as an answer:
```json
{"status":"error","session_id":"abc123","content":"","sources_count":0,"error":"grok_primary_failed","error_detail":{"code":"grok_primary_failed","message":"Grok model invocation failed, maximum attempts exhausted","service":"grok","retryable":true,"http_status":503,"upstream_code":"upstream_unavailable","diagnostics":{"primary_attempts":5,"fallback_attempts":0,"total_attempts":5,"termination_reason":"max_attempts_exhausted","configured_max_attempts":5,"actual_attempts":5,"elapsed_ms":120000,"budget_ms":270000,"queue_wait_ms":0}},"partial":false}
```
Other tool examples:
```jsonl
{"tool":"get_sources","status":"success","session_id":"abc123","sources":[],"sources_count":0}
{"tool":"web_fetch","status":"success","url":"https://example.com","content":"# Page","provider":"tavily"}
{"tool":"web_map","status":"error","base_url":"https://example.com","results":[],"error_detail":{"code":"tavily_no_urls","message":"Tavily request successful, but no URLs found","service":"tavily","retryable":false,"http_status":null,"upstream_code":null,"diagnostics":{"upstream_succeeded":true,"empty_result":true}}}
{"tool":"get_config_info","status":"partial_success","partial":true,"configuration":{"GROK_API_KEY":"not configured"},"connection_test":{"status":"configuration error"},"error_detail":{"code":"grok_configuration_error","message":"GROK_API_KEY not configured","service":"grok","retryable":false,"http_status":null,"upstream_code":null,"diagnostics":{"configuration":"grok"}}}
{"tool":"switch_model","status":"success","success":true,"previous_model":"grok-4-fast","current_model":"grok-3-mini","message":"Main model switched"}
{"tool":"plan_intent","status":"partial_success","partial":true,"session_id":"plan123","plan_complete":false,"phases_remaining":["complexity_assessment","query_decomposition"],"error_detail":{"code":"planning_incomplete","message":"Search plan not yet complete, can continue to submit remaining planning phases","service":"planning","retryable":true,"http_status":null,"upstream_code":null,"diagnostics":{"phases_remaining":["complexity_assessment","query_decomposition"]}}}
```
## Grok Chat Protocol, Single Strong Model, and Up to Five Real Attempts
The service only uses streaming Chat Completions. The OpenRouter address will continue to append the compatible `:online` suffix for the model; any failure will only be retried according to the rules on the same `/v1/chat/completions` endpoint and the current model.
Each call only uses the current model configured by the user. 408, 429, 5xx, connection failure, connection/read timeout, interruption before complete content generation or in streaming transmission, and identifiable relay station "upstream account unavailable/dead account/account pool unavailable" errors will be retried with exponential backoff with random jitter, and by default, a maximum of 5 real requests are made.
Retries will not break through `WEB_SEARCH_TOTAL_TIMEOUT`, nor will they bypass `GROK_MAX_CONCURRENCY`. Authentication, parameter, model non-existence, and permission errors will end with "stopped early due to non-retryable error"; only when the configuration limit is indeed reached will it report "maximum attempts exhausted". The total budget or concurrency queuing exhaustion uses independent termination reasons and structured diagnostics.
Model non-existence or permission will stop immediately; temporary model unavailability will continue to retry the current model. Explicit 400/422 parameter errors and 401/403/API Key authentication failures will also stop immediately. Error classification simultaneously checks HTTP status, OpenAI compatible error objects, error codes, error types, and response body semantics.
Stream content will be fully buffered and verified for the end marker on the server side. When the stream is interrupted after generating some content, the incomplete content will not be returned, cached, or extracted as a source. The final failure will return `grok_error`, including the current model, real attempt times, last error classification, status code/upstream error code, and retain old fallback model compatible fields with values of `null`/`0`/`false`; it will not contain API Key or Authorization values.
`switch_model(model)` maintains the old call form unchanged: it updates the model used by the current process and writes `primary_model` (while retaining the compatible `model` field) to the local configuration.
## Multiple Tavily Keys
Multiple keys can be configured using commas, semicolons, or line breaks:
```text
TAVILY_API_KEYS=tvly-key-1,tvly-key-2,tvly-key-3
```
Normal requests will fairly poll among healthy keys; Search, Extract, and Map share the same runtime status:
- `healthy`: Normally participates in polling.
- `cooldown`: Temporary rate limiting, timeout, network error, or temporary service exception, and re-probes after cooling down.
- `quota_exhausted`: Quota is exhausted, using a longer cooling time.
- `invalid`: Key is invalid or revoked, and will not be used within this process.
The "busy" state of a key is instantaneous occupancy information independent of the above health status and will not be misjudged as cooling down, quota exhaustion, or failure. When a key is busy, other healthy and idle keys will be prioritized; if all healthy keys are busy, it will wait for the earliest available slot within the current tool's budget.
401/403 will make the current key invalid; 429 will distinguish between temporary and quota exhaustion based on error codes, response bodies,Retry-After`; 400/422 directly returns parameter errors; 404 prompts to check `TAVILY_API_URL`. When multiple different keys encounter the same or network errors, it will trigger a service-level fuse only allow one half-open probe after cooling down.
When all keys are unavailable, `web_fetch` and `` return `status="error"`, `t_all_keys_unavailable`, and desensitized status `web_search` will retain the existing Grok result, return `status="partial_success"`, and set `partial=true` and retain `tavily_error`. This error only terminates the current tool call and will not exit the MCP process.
## Bounded Runtime Cache
The search source session is only saved in the current MCP process, with a maximum of 256 items and expiring after 1 hour; `get_sources` returns `session_id_not_found_or_expired` for expired sessions. The model directory's successful result cache for 5 minutes, and then re-read `/models`; failures will not be cached as empty results. The service does not cache final answers for a long time, nor does it write the complete search text to disk by default.
## Frequently Asked Questions
### Client cannot find the tool
Confirm that `uvx` is in the client's process `PATH`, and check the repository address, command name `grok-search`, and JSON/TOML syntax. If the Windows client cannot find `uvx`, you can fill in its absolute path.
### Grok search is available, but crawling or mapping fails
`web_fetch` and `web_map` depend on Tavily. Call `get_config_info` to confirm that Tavily is enabled and `TAVILY_API_KEY` or `TAVILY_API_KEYS` is configured.
### Certificate errors occur on the enterprise network
Add `--native-tls` at the beginning of the `uvx` parameter to let uv use the system's certificate library. See the client configuration guide for a complete example.
### Will API Key leak
The configuration diagnosis only returns desensitized keys. Do not write real keys into the repository, issues, log screenshots, or client-shared### Cherry Studio still shows `-32001: Request timed out`
Set the MCP tool timeout to 300 seconds for Cherry Studio, and confirm that the server-side does not configure `WEB_SEARCH_TOTAL_TIMEOUT` to 300 seconds or higher. The default 270 seconds will return a business-level structured timeout; 300 seconds is only a client-side security upper limit.
## Local Development
```bash
git clone https://github.com/Timmyzzo/WebSearch-MCP
cd WebSearch-MCP
uv sync --extra dev
uv run ruff check .
uv run pytest
uv run python -m build
```
See [Developer Guide](./docs/DEVELOPMENT.md) for more module descriptions, test coverage, and phase boundaries.
Code-level comparison, license boundaries, and adoption/rejection reasons for external projects are in [External Project Implementation Analysis](./docs/EXTERNAL_PROJECT_ANALYSIS.md).
## License
[MIT License](LICENSE)
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available