# https://github.com/robbyczgw-cla/web-search-plus-mcp Project Manual

Generated at: 2026-07-21 03:27:23 UTC

## Table of Contents

- [Introduction and Quick Start](#page-introduction)
- [v3 Request/Response Contract and Orchestration Pipeline](#page-v3-contract)
- [Provider System, Routing, and Multi-Provider Fallback](#page-providers-routing)
- [Caching, Policy Layer, and Operator Workflows](#page-policy-cache-ops)

<a id='page-introduction'></a>

## Introduction and Quick Start

### Related Pages

Related topics: [v3 Request/Response Contract and Orchestration Pipeline](#page-v3-contract), [Provider System, Routing, and Multi-Provider Fallback](#page-providers-routing), [Caching, Policy Layer, and Operator Workflows](#page-policy-cache-ops)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/README.md)
- [docs/MIGRATION_1_0.md](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/docs/MIGRATION_1_0.md)
- [CHANGELOG.md](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/CHANGELOG.md)
- [web_search_plus_mcp/__init__.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/__init__.py)
- [web_search_plus_mcp/server.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/server.py)
- [pyproject.toml](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/pyproject.toml)
</details>

# Introduction and Quick Start

`web-search-plus-mcp` is a standalone Model Context Protocol (MCP) server that exposes web search and content extraction capabilities to MCP-compatible clients. It synchronizes with the portable Web Search Plus engine contract while keeping a stable tool surface, so existing clients keep working as the underlying engine evolves. Source: [README.md:1-40](), [CHANGELOG.md:1-20]()

The server speaks MCP over stdio and ships two tools by default: `web_search` for search queries and `web_extract` for fetching and parsing a single URL. Higher‑level engine features (provider auto‑routing, cache envelopes, evidence/receipt metadata) are surfaced through these tools rather than exposed as separate MCP primitives, so the public contract stays small. Source: [web_search_plus_mcp/server.py:1-80](), [CHANGELOG.md:15-30]()

## What this server does

The server's role is to act as a thin, stable MCP adapter in front of the Web Search Plus engine:

- Accepts MCP requests for `web_search` and `web_extract` from any MCP client.
- Translates those requests into the engine's canonical v3 request/response contracts.
- Routes each request through one or more configured providers (auto mode), or a single explicitly chosen provider.
- Returns results enriched with additive metadata: evidence, provider‑attempt history, routing decisions, cache origin, and applied policy. Source: [CHANGELOG.md:8-25](), [web_search_plus_mcp/__init__.py:1-60]()

Because the server is source‑only and portable, the same artifact can be installed on any platform that supports `uvx` or `pip`. There is no separate daemon or background service to manage. Source: [README.md:10-30](), [pyproject.toml:1-40]()

## Installation

The server is published on PyPI and runnable directly with `uvx`:

```bash
uvx web-search-plus-mcp
```

This single command pulls the latest compatible wheel and starts the MCP server over stdio, ready to attach to any MCP client (Claude Desktop, MCP‑compatible IDEs, custom agents, etc.). Source: [CHANGELOG.md:5-15](), [README.md:15-35]()

For local development or pinned versions, install the package from the repository:

```bash
git clone https://github.com/robbyczgw-cla/web-search-plus-mcp
cd web-search-plus-mcp
pip install -e .
```

After installation, `python -m web_search_plus_mcp` (or the equivalent entry point declared in `pyproject.toml`) launches the server in the same stdio mode. Source: [pyproject.toml:1-40](), [web_search_plus_mcp/__init__.py:1-40]()

## Configuring providers

The server supports many search and extraction providers. Providers are activated by setting the corresponding API key (and, where required, an opt‑in flag) in the process environment before launching the server. Examples that appear across the changelog include:

| Provider family | Typical activation | Notes |
|---|---|---|
| `serper` | `SERPER_API_KEY` | Search and webpage extraction (added in v0.16.0). |
| `keenable` | `KEENABLE_API_KEY` | Search and extraction; an opt‑in keyless public tier exists but is off by default. |
| Other engines (Tavily‑class, Brave, etc.) | per‑provider `*_API_KEY` | Auto‑detected from the environment. |

The recommended path for new deployments is to set all keys you have available; with multiple keys present, `provider=auto` requests will plan a fallback chain rather than a single candidate. Source: [CHANGELOG.md:30-90](), [docs/MIGRATION_1_0.md:1-40]()

## First request and known pitfalls

Once installed and configured, the smallest useful call is a search:

```text
tool: web_search
arguments: { "query": "latest MCP specification", "provider": "auto" }
```

The same shape applies to `web_extract` for fetching a specific URL. The `provider` argument accepts `auto` (recommended) or a specific provider name; explicit providers are treated as strict and will not fall through on failure. Source: [CHANGELOG.md:20-40](), [web_search_plus_mcp/server.py:40-120]()

### Multi‑provider fallback (important)

Auto routing is the headline reliability feature: with several provider keys configured, a request should plan multiple candidates and fall through the chain on quota, rate‑limit, or transient errors. The v1.0.0 release shipped a regression where the MCP → CLI → v3 request boundary collapsed `auto` plans to a single candidate, making any provider failure terminal. This was fixed in v1.0.1, which restores the intended multi‑provider fallback behaviour. Source: [CHANGELOG.md:1-15](), [docs/MIGRATION_1_0.md:1-40]()

If you observe that every request returns only one provider‑attempt in its receipt metadata despite multiple keys being present, you are likely on a v1.0.0 install. Upgrading to v1.0.1 or later restores the chain. See issue #27 for a live reproduction. Source: [CHANGELOG.md:1-10]()

## Versioning and upgrades

The package follows the upstream Web Search Plus engine closely: each minor release (v0.x → v1.x) aligns with a corresponding engine family (v2.x, v3.x). The current line is v1.1.0, which adds budget preflight, diversity reranking, self‑hosted profiles, shadow observations, semantic extraction spans over MCP, and a public provider SDK with fail‑closed `providers.d` discovery. Source: [CHANGELOG.md:1-30]()

For operators migrating from v0.x engines to the v3 contract, `docs/MIGRATION_1_0.md` is the canonical reference; it documents the canonical request/response shape and the additive evidence/receipt fields now returned alongside every result. Source: [docs/MIGRATION_1_0.md:1-60](), [README.md:1-30]()

## Where to go next

- Read `README.md` for the full list of supported providers and tool schemas.
- Skim `docs/MIGRATION_1_0.md` if you are upgrading an existing integration from pre‑v1 contracts.
- Track `CHANGELOG.md` between upgrades: provider additions, security fixes, and engine‑side changes are recorded there with each release. Source: [README.md:1-30](), [CHANGELOG.md:1-120](), [docs/MIGRATION_1_0.md:1-40]()

---

<a id='page-v3-contract'></a>

## v3 Request/Response Contract and Orchestration Pipeline

### Related Pages

Related topics: [Introduction and Quick Start](#page-introduction), [Provider System, Routing, and Multi-Provider Fallback](#page-providers-routing), [Caching, Policy Layer, and Operator Workflows](#page-policy-cache-ops)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [web_search_plus_mcp/contract_v3.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/contract_v3.py)
- [web_search_plus_mcp/orchestrator_v3.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/orchestrator_v3.py)
- [web_search_plus_mcp/runtime_v3.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/runtime_v3.py)
- [web_search_plus_mcp/request_gate_v3.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/request_gate_v3.py)
- [web_search_plus_mcp/bounded_context_v3.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/bounded_context_v3.py)
- [web_search_plus_mcp/compat_v3.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/compat_v3.py)
</details>

# v3 Request/Response Contract and Orchestration Pipeline

## Purpose and Scope

The v3 contract is the canonical, additive envelope used by the standalone `web-search-plus-mcp` server. It replaced the older `web_search` / `web_extract` payloads with a richer schema that captures evidence, provider attempts, routing decisions, cache origins, and policy records. The orchestration pipeline is the runtime that consumes that contract, plans providers, applies the request gate, and dispatches through the runtime into the portable engine.

The v3 boundary sits between the MCP tool surface and the underlying CLI/engine. Every MCP request is translated into a v3 request, dispatched through `request_gate_v3`, executed by `orchestrator_v3` inside `runtime_v3`, and returned as a v3 response with optional compatibility shaping for older callers via `compat_v3`.

Source: [web_search_plus_mcp/contract_v3.py:1-120]()

## Request and Response Envelopes

The v3 envelope is defined in `contract_v3.py`. The request side carries the query, the mode (`search`, `extract`, or `extract_plus`), an explicit provider selection, the `allow_fallback` flag, the set of provider keys visible in the process env, freshness/locale hints, and policy hints. The response side carries results, additive evidence, per-provider `provider_attempts`, `routing` decisions, `cache_origin`, `policy` records, and `meta` (request id, timing, and similar bookkeeping).

`request_gate_v3.py` validates the envelope before it leaves the MCP layer. It normalizes `provider=auto`, prevents an absent `--allow-fallback` CLI flag from being coerced into `allow_fallback: false`, and keeps explicit provider selections strict (no silent fallback chain). This gate is the source of the multi-provider fallback restoration that landed in v1.0.1.

Source: [web_search_plus_mcp/request_gate_v3.py:1-200]()

`compat_v3.py` shapes legacy `web_search` / `web_extract` responses into the v3 envelope and back, so older MCP clients keep working while the new fields are purely additive.

Source: [web_search_plus_mcp/compat_v3.py:1-160]()

## Orchestration Pipeline

`orchestrator_v3.py` is the plan-and-dispatch coordinator. Given a gated request, it:

1. Builds the candidate plan. For `provider=auto` with `allow_fallback=True`, the plan enumerates every available provider key in env. For `provider=auto` with `allow_fallback=False`, or for explicit provider names, the plan collapses to a single candidate.
2. Hands the plan to `runtime_v3`, which enforces the `bounded_context_v3` boundaries, applies budget preflight, and runs the selected providers with bounded parallelism so a slow provider cannot stall the whole MCP call.
3. Emits a routing receipt for each provider attempt and a final envelope with `provider_attempts` and `routing` populated, so callers can audit why a particular provider was chosen or skipped.

Source: [web_search_plus_mcp/orchestrator_v3.py:1-260]()

Source: [web_search_plus_mcp/runtime_v3.py:1-220]()

Source: [web_search_plus_mcp/bounded_context_v3.py:1-180]()

```mermaid
flowchart TD
  A[MCP tool call] --> B[request_gate_v3<br/>validate + normalize]
  B --> C[orchestrator_v3<br/>build candidate plan]
  C --> D{allow_fallback?}
  D -- yes --> E[multi-provider plan]
  D -- no --> F[single-candidate plan]
  E --> G[runtime_v3<br/>bounded_context_v3]
  F --> G
  G --> H[engine dispatch]
  H --> I[v3 response envelope]
  I --> J[compat_v3 shaping]
  J --> K[MCP tool response]
```

## Known Issue: v1.0.0 Single-Candidate Plans

In v1.0.0, a regression across the MCP → CLI → v3 boundary caused `provider=auto` requests to build a single-candidate plan even when 10 provider keys were present in the process env. Any quota or rate-limit failure became terminal because there was no fallback chain to advance to. This was reproduced live with `uvx web-search-plus-mcp` on 2026-07-20 and tracked as issue #27.

The root cause was that the missing `--allow-fallback` CLI flag was being coerced into `allow_fallback: false` at the request gate, which collapsed auto plans to one provider. v1.0.1 fixed this by restoring multi-provider fallback for normal `provider=auto` Search and Extract requests while keeping explicit providers strict (no silent fallback).

Source: [web_search_plus_mcp/request_gate_v3.py:allow_fallback normalization]()

Community reference: issue #27 — "v1.0.0: auto routing builds single-candidate plans — no fallback on quota/rate-limit".

## What Lands in v1.1.0

The v1.1.0 portable parity release extends the orchestration pipeline with budget preflight, diversity reranking, self-hosted profiles, and shadow observations. The contract gains semantic extraction spans, extraction cache identity v6, and SQLite state schema v3. `runtime_v3` also exposes the public provider SDK with fail-closed `providers.d` discovery and conformance checks, so custom providers are loaded through the same gate as built-ins and never silently bypass `request_gate_v3`.

Source: [web_search_plus_mcp/runtime_v3.py:provider SDK surface]()

Source: [web_search_plus_mcp/orchestrator_v3.py:diversity reranking hook]()

---

<a id='page-providers-routing'></a>

## Provider System, Routing, and Multi-Provider Fallback

### Related Pages

Related topics: [v3 Request/Response Contract and Orchestration Pipeline](#page-v3-contract), [Caching, Policy Layer, and Operator Workflows](#page-policy-cache-ops), [Introduction and Quick Start](#page-introduction)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [web_search_plus_mcp/providers.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/providers.py)
- [web_search_plus_mcp/provider_registry.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/provider_registry.py)
- [web_search_plus_mcp/provider_dispatch.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/provider_dispatch.py)
- [web_search_plus_mcp/provider_adapter_protocol.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/provider_adapter_protocol.py)
- [web_search_plus_mcp/provider_health.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/provider_health.py)
- [web_search_plus_mcp/provider_stats.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/provider_stats.py)
</details>

# Provider System, Routing, and Multi-Provider Fallback

The provider subsystem is the load-bearing layer of `web-search-plus-mcp`. It abstracts every external search and extraction backend behind a uniform adapter protocol, decides which providers to use for each request, and chains them so that quota, rate-limit, or network failures do not terminate a call. The MCP server exposes two tools (`web_search`, `web_extract`) and delegates the "who answers this question" decision to this layer.

## Architecture and Provider Discovery

Providers plug in through a typed adapter contract and are aggregated by a registry. The registry is what the routing layer queries when assembling a candidate plan.

- The adapter shape is defined in `provider_adapter_protocol.py`, which establishes the contract every backend implementation must satisfy to be dispatchable.
  Source: [web_search_plus_mcp/provider_adapter_protocol.py:1-1]()
- Concrete adapter classes live in `providers.py`, where individual backends (e.g. Tavily, Serper, Keenable) implement search and/or extraction.
  Source: [web_search_plus_mcp/providers.py:1-1]()
- `provider_registry.py` indexes those adapters by name and capability so the planner can resolve `provider=auto` into a candidate list.
  Source: [web_search_plus_mcp/provider_registry.py:1-1]()
- v1.1.0 introduced a public provider SDK with fail-closed `providers.d` discovery and conformance checks, meaning unknown or non-conforming entries are rejected rather than silently loaded.
  Source: [web_search_plus-mcp v1.1.0 release notes]()

| Component | File | Responsibility |
|---|---|---|
| Adapter contract | `provider_adapter_protocol.py` | Defines the search/extract interface |
| Adapters | `providers.py` | Per-backend implementations |
| Registry | `provider_registry.py` | Capability and key-aware lookup |
| Dispatch | `provider_dispatch.py` | Executes the chosen plan |

## Routing Plans and the `provider=auto` Path

When a caller does not pin a provider, the dispatcher resolves `provider=auto` by:

1. Reading the process environment for provider keys and honoring `auto_routing.disabled_providers` from `config.json` (since v0.12.0).
2. Asking the registry for the remaining capable providers.
3. Building a routing plan — an ordered candidate list with the selected provider first and fallbacks afterward.

The plan is then handed to `provider_dispatch.py`, which iterates candidates in order and stops on the first non-failing response.
Source: [web_search_plus_mcp/provider_dispatch.py:1-1]()

The `v0.11.0` release added bounded parallel research handling so a slow provider cannot stall an entire MCP call indefinitely, and v0.17.0 tightened cache ownership so cache stats and clear only manage complete search-cache envelopes from healthy providers.
Source: [web-search-plus-mcp v0.11.0 release notes](), [web-search-plus-mcp v0.17.0 release notes]()

## Multi-Provider Fallback and the v1.0.0 / v1.0.1 Fix

Fallback behavior is gated by `allow_fallback`. When `true`, a failed candidate is replaced by the next one in the plan; when `false`, the dispatcher is strict and surfaces the first error.

Issue #27 (observed on v1.0.0, 2026-07-20) reported that every auto-routed request produced a **single-candidate plan**, making any provider failure terminal even with ten provider keys present. The root cause: an absent `--allow-fallback` CLI flag was being coerced into an explicit `allow_fallback: false` as the request crossed the MCP → CLI → v3 request boundary, collapsing the auto plan.
Source: [Issue #27]()

`v1.0.1` restored the intended behavior:
- Auto (`provider=auto`) requests regain the full fallback chain for both `web_search` and `web_extract`.
- An unspecified flag no longer defaults to `false`; explicit `allow_fallback: false` is required to opt into strictness.
- Explicitly selected providers (e.g. `provider=tavily`) remain strict, matching pre-v1.0.0 semantics.
Source: [web-search-plus-mcp v1.0.1 release notes]()

```mermaid
flowchart LR
  A[Tool call: web_search / web_extract] --> B{provider pin?}
  B -- yes, strict --> P[Pinned adapter]
  B -- auto --> R[Registry lookup]
  R --> C{allow_fallback?}
  C -- false --> P
  C -- true / unspecified --> L[Ordered candidate list]
  L --> D[Dispatch candidate 1]
  D -- success --> X[Return response]
  D -- quota / 429 / network --> D2[Dispatch candidate 2]
  D2 -- success --> X
  D2 -- failure --> D3[...exhausted...]
  D3 --> Y[Surface terminal error]
```

## Health, Stats, and v1.1.0 Enhancements

Sustained fallback depends on per-provider observability.

- `provider_health.py` tracks cooldowns and last-failure state. v0.11.0 made these diagnostics **fail-soft**: corrupt or unreadable cooldown/cache files no longer crash the dispatcher.
  Source: [web_search_plus_mcp/provider_health.py:1-1]()
- `provider_stats.py` exposes per-backend counters and is now scoped (since v0.17.0) to *complete* Web Search Plus envelopes so partial reads cannot pollute host usage statistics.
  Source: [web_search_plus_mcp/provider_stats.py:1-1]()
- v0.14.0 layered private/internal extraction target protection on top of dispatch: loopback, RFC1918, CGNAT, and IPv6 local/mapped-private ranges are blocked before any provider is invoked.
  Source: [web-search-plus-mcp v0.14.0 release notes]()

The v1.1.0 release extended the routing layer further with **budget preflight** (queries are sized against provider limits before dispatch), **diversity reranking** (candidate order is reshuffled to avoid one provider dominating every response), **self-hosted profiles** (operators can bind a profile name to a fixed provider subset), and **shadow observations** (parallel calls to a non-scoring provider for offline comparison). Parallelism is still bounded so a shadow provider cannot exhaust the call's wall-clock budget.
Source: [web-search-plus-mcp v1.1.0 release notes]()

Together, the adapter protocol, the registry, the dispatcher, and the health/stats feedback loop form a single system whose contract to callers is simple — *return an answer if any configured provider can give one* — while its internal behavior absorbs quota errors, key rotation, and provider outages transparently.

---

<a id='page-policy-cache-ops'></a>

## Caching, Policy Layer, and Operator Workflows

### Related Pages

Related topics: [Introduction and Quick Start](#page-introduction), [Provider System, Routing, and Multi-Provider Fallback](#page-providers-routing), [v3 Request/Response Contract and Orchestration Pipeline](#page-v3-contract)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [web_search_plus_mcp/cache.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/cache.py)
- [web_search_plus_mcp/cache_v3.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/cache_v3.py)
- [web_search_plus_mcp/cache_identity_v3.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/cache_identity_v3.py)
- [web_search_plus_mcp/state_store_v3.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/state_store_v3.py)
- [web_search_plus_mcp/state_migration_v3.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/state_migration_v3.py)
- [web_search_plus_mcp/budget_preflight_v3.py](https://github.com/robbyczgw-cla/web-search-plus-mcp/blob/main/web_search_plus_mcp/budget_preflight_v3.py)
</details>

# Caching, Policy Layer, and Operator Workflows

The `web-search-plus-mcp` server layers three cooperating subsystems above the provider boundary: a **caching layer** that stores complete search and extraction envelopes, a **policy layer** that decides which provider to try next, and an **operator workflow** surface that exposes receipts, journals, and a console for inspection. Together they form the runtime substrate that the MCP tools `web_search` and `web_extract` rely on for repeatable, observable behavior.

## Caching Subsystem

The cache is split between a portable envelope store and an identity model that is bumped whenever the on-disk shape of a cached value changes. As of v1.1.0 the extraction cache uses **identity v6** and the SQLite state schema uses **v3**; older envelopes are rejected rather than silently mis-decoded.

The v3 entry point normalizes queries before they are turned into a cache key, so cosmetic differences (whitespace, casing) do not produce duplicate entries. `cache_v3.py` also gates `cache stats` and `cache clear` so they only operate on complete Web Search Plus envelopes, leaving provider health, host usage, and cooldown files untouched. This is the "safer cache ownership" guarantee introduced in v0.17.0.

The identity module (`cache_identity_v3.py`) owns the version constant. Any change to envelope layout, normalization, or key derivation must bump this constant; on read, a mismatched identity causes the entry to be treated as a miss and rewritten under the new version, which avoids poisoning but also explains transient stampede behavior right after a release.

Source: [web_search_plus_mcp/cache_v3.py:1-40]()
Source: [web_search_plus_mcp/cache_identity_v3.py:1-30]()

## State Store and Schema Migration

Durable operator state — provider cooldowns, host usage counters, and routing plan history — lives in SQLite via `state_store_v3.py`. The store is intentionally separate from the search/extraction cache so that wiping one never destroys the other.

`state_migration_v3.py` is the only writer allowed to change the SQLite schema. It applies forward migrations idempotently, reading the current schema version from a metadata table and replaying the migration chain. The schema version is part of the on-disk contract, which is why release notes call it out explicitly (e.g. "SQLite state schema v3" in v1.1.0).

A fail-soft diagnostic was added in v0.11.0: if the cooldown or cache state file is corrupt or unreadable, the loader logs and returns an empty state rather than crashing the MCP server, so a single bad row cannot wedge every request.

Source: [web_search_plus_mcp/state_store_v3.py:1-60]()
Source: [web_search_plus_mcp/state_migration_v3.py:1-50]()

## Policy Layer: Auto Routing, Budgets, and Fallback

The policy layer decides, for each request, which provider to call and in what order. It is implemented in front of the provider registry and reads configuration from `config.json` (notably `auto_routing.disabled_providers`, honored by `extract_plus` since v0.12.0).

`budget_preflight_v3.py` performs the cheapest decision first: before contacting any provider, it checks per-host usage, active cooldowns, and any explicit `allow_fallback` flag on the request. If the preflight produces only one viable candidate, the plan is recorded as a single-candidate plan, which is exactly the failure mode reported in issue #27 for v1.0.0 — every request planned exactly one candidate and any failure became terminal. v1.0.1 restored multi-provider fallback by preventing the absent `--allow-fallback` CLI flag from being coerced into `allow_fallback: false`, and v1.1.0 reinforces this with formal budget preflight so the single-candidate collapse is caught before dispatch.

The layer also records a **routing receipt** for every request, capturing the candidate list, the policy that selected them, and the cache origin (hit, miss, rewritten). These receipts are what makes the operator console useful.

Source: [web_search_plus_mcp/budget_preflight_v3.py:1-80]()

## Operator Workflows

Operator workflows are the read/inspection side of the policy layer. They do not change request behavior; they make it auditable.

| Surface | Purpose | Backed by |
| --- | --- | --- |
| Routing receipts | Per-request provider plan, attempts, cache origin | `budget_preflight_v3.py` |
| Receipt journal | Append-only history of receipts across a session | `state_store_v3.py` |
| Operator Console (Hermes-only) | Interactive inspection of receipts and state | v1.1.0 release notes |
| Cache stats / clear | Bounded ops on complete envelopes only | `cache_v3.py` |

The Operator Console and the plugin/SDK story are Hermes-specific extensions; the portable MCP server exposes only the receipt journal, the cache stats surface, and the migration-aware state store. This split lets the core stay portable while still giving operators a way to trace a 502 back to "provider X was rate-limited at T, no fallback candidate was available."

A representative end-to-end flow: an MCP `web_search` call arrives → `budget_preflight_v3.py` builds the candidate list under the routing policy → a routing receipt is appended to the journal → the highest-ranked provider is called → the response envelope is written through `cache_v3.py` under the current `cache_identity_v3.py` constant → the operator can later query the journal and the cache stats to reconstruct what happened.

Source: [web_search_plus_mcp/cache.py:1-40]()
Source: [web_search_plus_mcp/state_store_v3.py:40-80]()

## Related Community Signals

- Issue #27 documents the v1.0.0 single-candidate regression and motivates the v1.0.1 fix and the v1.1.0 preflight.
- v0.17.0 release notes introduced the safer cache ownership rule that constrains `cache stats` and `cache clear`.
- v1.1.0 release notes name cache identity v6, SQLite schema v3, and the Hermes-only Operator Console as the operator-facing surfaces.

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Pitfall Log

Project: robbyczgw-cla/web-search-plus-mcp

Summary: Found 19 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Installation risk - Installation risk requires verification.

## 1. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this installation risk before relying on the project: web-search-plus-mcp v0.11.0
- User impact: Upgrade or migration may change expected behavior: web-search-plus-mcp v0.11.0
- Evidence: failure_mode_cluster:github_release | https://github.com/robbyczgw-cla/web-search-plus-mcp/releases/tag/v0.11.0

## 2. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this installation risk before relying on the project: web-search-plus-mcp v0.17.0
- User impact: Upgrade or migration may change expected behavior: web-search-plus-mcp v0.17.0
- Evidence: failure_mode_cluster:github_release | https://github.com/robbyczgw-cla/web-search-plus-mcp/releases/tag/v0.17.0

## 3. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this installation risk before relying on the project: web-search-plus-mcp v1.0.0
- User impact: Upgrade or migration may change expected behavior: web-search-plus-mcp v1.0.0
- Evidence: failure_mode_cluster:github_release | https://github.com/robbyczgw-cla/web-search-plus-mcp/releases/tag/v1.0.0

## 4. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this installation risk before relying on the project: web-search-plus-mcp v1.1.0
- User impact: Upgrade or migration may change expected behavior: web-search-plus-mcp v1.1.0
- Evidence: failure_mode_cluster:github_release | https://github.com/robbyczgw-cla/web-search-plus-mcp/releases/tag/v1.1.0

## 5. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/robbyczgw-cla/web-search-plus-mcp/issues/27

## 6. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.host_targets | https://github.com/robbyczgw-cla/web-search-plus-mcp

## 7. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this configuration risk before relying on the project: v0.12.0
- User impact: Upgrade or migration may change expected behavior: v0.12.0
- Evidence: failure_mode_cluster:github_release | https://github.com/robbyczgw-cla/web-search-plus-mcp/releases/tag/v0.12.0

## 8. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this configuration risk before relying on the project: v1.0.0: auto routing builds single-candidate plans — no fallback on quota/rate-limit
- User impact: Developers may misconfigure credentials, environment, or host setup: v1.0.0: auto routing builds single-candidate plans — no fallback on quota/rate-limit
- Evidence: failure_mode_cluster:github_issue | https://github.com/robbyczgw-cla/web-search-plus-mcp/issues/27

## 9. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this configuration risk before relying on the project: web-search-plus-mcp v0.13.0
- User impact: Upgrade or migration may change expected behavior: web-search-plus-mcp v0.13.0
- Evidence: failure_mode_cluster:github_release | https://github.com/robbyczgw-cla/web-search-plus-mcp/releases/tag/v0.13.0

## 10. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this configuration risk before relying on the project: web-search-plus-mcp v0.14.0
- User impact: Upgrade or migration may change expected behavior: web-search-plus-mcp v0.14.0
- Evidence: failure_mode_cluster:github_release | https://github.com/robbyczgw-cla/web-search-plus-mcp/releases/tag/v0.14.0

## 11. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this configuration risk before relying on the project: web-search-plus-mcp v0.15.0
- User impact: Upgrade or migration may change expected behavior: web-search-plus-mcp v0.15.0
- Evidence: failure_mode_cluster:github_release | https://github.com/robbyczgw-cla/web-search-plus-mcp/releases/tag/v0.15.0

## 12. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.assumptions | https://github.com/robbyczgw-cla/web-search-plus-mcp

## 13. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this migration risk before relying on the project: web-search-plus-mcp v1.0.1
- User impact: Upgrade or migration may change expected behavior: web-search-plus-mcp v1.0.1
- Evidence: failure_mode_cluster:github_release | https://github.com/robbyczgw-cla/web-search-plus-mcp/releases/tag/v1.0.1

## 14. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/robbyczgw-cla/web-search-plus-mcp

## 15. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: downstream_validation.risk_items | https://github.com/robbyczgw-cla/web-search-plus-mcp

## 16. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: risks.scoring_risks | https://github.com/robbyczgw-cla/web-search-plus-mcp

## 17. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/robbyczgw-cla/web-search-plus-mcp

## 18. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/robbyczgw-cla/web-search-plus-mcp

## 19. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: Developers should check this maintenance risk before relying on the project: web-search-plus-mcp v0.16.0
- User impact: Upgrade or migration may change expected behavior: web-search-plus-mcp v0.16.0
- Evidence: failure_mode_cluster:github_release | https://github.com/robbyczgw-cla/web-search-plus-mcp/releases/tag/v0.16.0

<!-- canonical_name: robbyczgw-cla/web-search-plus-mcp; human_manual_source: deepwiki_human_wiki -->
