Skip to main content
Glama
AlimBkb

mcp-search-failover

by AlimBkb

mcp-search-failover

An MCP server for web search that does not die when an API key runs out.

Русская версия

The problem

Standard search MCP servers (tavily-mcp, firecrawl-mcp, and friends) read a single API key from the environment at startup. When that key hits its quota, the server is dead until you restart it with a new key. On free tiers that happens constantly, and it always happens in the middle of something.

Related MCP server: serp-it

What this does

Every request pulls a key from a local store at call time instead of at boot. When a key is exhausted, the server rotates to the next key of the same provider. When every key of that provider is spent, it falls through to the next provider entirely:

tavily -> serper -> exa -> firecrawl

The working key index is persisted, so subsequent calls do not waste a round trip poking at a key that is already known to be dead.

Detecting an exhausted key is the tricky part

Providers do not agree on how to say "you are out of credits". Tavily returns 432, which is not a real HTTP status code at all - that single detail is why naive rotation logic silently fails. So detection works on two levels:

  1. Status codes - 401, 402, 403, 429, 430, 432

  2. Response body - on any 4xx, the body is scanned for markers like usage limit, quota, exceed, credits, rate limit, insufficient, upgrade your plan, out of credit, limit reached

Anything else is treated as a genuine error and is not rotated on - a malformed query should surface as a malformed query, not burn through four keys.

Tools

Tool

What it does

web_search

Search the web. provider="auto" walks the whole chain; or pin one of tavily, serper, exa, firecrawl

web_extract

Fetch a page as markdown (Firecrawl)

web_map

List the URLs of a site (Firecrawl)

keys_status

How many keys each provider has and which one is currently active

Install

git clone https://github.com/AlimBkb/mcp-search-failover.git
cd mcp-search-failover
pip install -r requirements.txt

Create the key store. The default location is ~/.claude/keys/keys.json; override it with the KEYRING_FILE environment variable.

cp keys.example.json ~/.claude/keys/keys.json
# then put your real keys in it

Format - a list per provider plus the index of the currently active key:

{
  "tavily": { "keys": ["key-one", "key-two"], "current": 0 }
}

You only need keys for the providers you actually intend to use. Missing providers are skipped rather than treated as failures.

Register with Claude Code

claude mcp add search -- python /absolute/path/to/mcp_search_server.py

Or add it to your MCP config by hand:

{
  "mcpServers": {
    "search": {
      "command": "python",
      "args": ["/absolute/path/to/mcp_search_server.py"]
    }
  }
}

CLI

The same rotation logic is available without an MCP client, which is handy for scripts and for debugging:

python search.py "your query"
python search.py "your query" --provider exa --limit 10
python keyring.py status

Reusing the rotation in your own code

keyring.py is standalone - it has no dependency on the MCP layer:

from keyring import call_with_rotation, RotateKey

def do(key):
    resp = requests.get(url, headers={"Authorization": f"Bearer {key}"})
    if resp.status_code in (401, 402, 429):
        raise RotateKey(resp.status_code)
    return resp.json()

result = call_with_rotation("tavily", do)

call_with_rotation returns None once every key for that service is spent, so the caller can decide whether to fall through to another provider or give up.

Tests

python -m pytest tests/ -v

The tests cover the exhaustion-detection logic, which is where the actual complexity lives and the one part that must not regress.

Security

The key store is never committed - keys.json is in .gitignore, and only keys.example.json with placeholder values ships with the repository. Keys are read from disk at call time and are never logged: diagnostics print the key index (#3/5), never the value.

License

MIT - see LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP server for internet search via direct Google and DuckDuckGo HTML scraping with AI-powered result normalization and optional summarization, requiring no API keys for search.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    An MCP server that aggregates web search results from multiple engines and optionally renders pages to Markdown, providing a unified search interface.
    7 npm
    3
    ISC
  • A
    license
    A
    quality
    B
    maintenance
    MCP server for local web search via SearXNG, providing unlimited queries without API keys or cost, with automatic fallback to public instances.
    3
    1
    MIT