Skip to main content
Glama
rthomas24

WebVector MCP Server

by rthomas24

WebVector

npm: webvector npm: webvector-mcp npm: webvector-cli CI License: MIT

AIエージェントに、1回のツール呼び出しで本物のウェブ調査を提供: 検索 → 全文ページの読み取り → ランク付け → 引用付きパッセージ。

検索ツールはモデルにタイトルと150文字のスニペットを渡すため、モデルは残りを推測します。フェッチツールは40KBのナビゲーションと定型文を渡すため、モデルは溺れてしまいます。WebVectorはその中間の全工程を担います: 検索を実行し、すべての結果(HTML、PDF、Markdown)をダウンロードしてクリーンアップし、パッセージに分割し、そのパッセージを質問に対してランク付けします(埋め込みモデルが利用可能な場合は意味的に、そうでない場合は語彙的に(BM25))。そして、クエリに答えるパッセージのみを、それぞれのURL、タイトル、オフセット、スコアとともに返します。

  • APIキーもモデルのダウンロードも不要: DuckDuckGo + BM25、インストール約12MB。

  • 任意の検索バックエンド、埋め込みプロバイダー、ベクターストア、リランカーをプラグイン可能(または1ファイルで自作)。

  • ライブラリ、MCPサーバー(Claude Code、Claude Desktop、Cursor、Windsurf、…)、CLIとして提供。

  • デフォルトで丁寧かつ安全: robots.txt、ホストごとのレート制限、SSRFガード、サイズ/リダイレクト/時間の上限、テレメトリなし。

npx -y webvector-cli search "what changed in the MCP spec in 2026?"
# Web research: what changed in the MCP spec in 2026?

**[1]** Streamable HTTP — Model Context Protocol — <https://modelcontextprotocol.io/specification/2026-07-28/…> (score 1.00)
> ### Earlier Streamable HTTP Revisions
> Protocol versions 2025-03-26 through 2025-11-25 also used the Streamable HTTP transport, but in a
> different shape: servers could assign a session via the Mcp-Session-Id header … None of these
> mechanisms are part of this revision.
…
## Sources
- Streamable HTTP — Model Context Protocol — <https://…> [1]

目次

  1. 30秒で試す

  2. MCPサーバーとして使う(Claude Code、Claude Desktop、Cursor…)

  3. ライブラリとして使う

  4. コマンドラインから使う

  5. 2つの階層: 語彙的 vs 意味的

  6. 設定

  7. プロバイダー

  8. 返ってくるもの

  9. エラーと失敗

  10. セキュリティとエチケット

  11. ソースから実行する(ローカル開発)

  12. 独自アダプターの作成

  13. 仕組み

  14. ロードマップ · ライセンス

要件: Node.js ≥ 22.12(Node 24推奨)。macOS、Linux、Windows対応。


Related MCP server: MyWebSearch MCP

1. 30秒で試す

インストール不要、キー不要:

npx -y webvector-cli search "how does reciprocal rank fusion work" --stats

パッセージが表示され、その後に統計行が表示されます: search duckduckgo 957ms · pages 4/5 908ms · embed 0 chunks (none/bm25) · retrieve 10ms · total 1879ms。embed … none/bm25 は語彙的階層(§5参照)にいることを意味します。意味的階層は、モデルランタイムまたは埋め込みAPIキーが存在すると自動的に切り替わります。

お使いのマシンが何を使うか確認:

npx -y webvector-cli doctor

2. MCPサーバーとして使う

MCPサーバーは4つのツールを公開します — web_research(メイン)、web_fetch、web_search、webvector_status — 任意のMCPクライアント向けに。

Claude Code

claude mcp add webvector -- npx -y webvector-mcp

Claude Desktop / Cursor / Windsurf / VS Code — MCP設定に追加(claude_desktop_config.json、~/.cursor/mcp.json、…):

{
  "mcpServers": {
    "webvector": {
      "command": "npx",
      "args": ["-y", "webvector-mcp"],
      "env": { "BRAVE_API_KEY": "optional — see §7" }
    }
  }
}

これが語彙的階層です。オンデバイス意味的検索の場合は、モデルランタイムを併せてインストール:

"args": ["-y", "-p", "@huggingface/transformers", "-p", "webvector-mcp", "webvector-mcp"]

…または、単にenvに埋め込みキーを入れるだけ(OPENAI_API_KEY、VOYAGE_API_KEY、GEMINI_API_KEY、COHERE_API_KEY)で自動的にアップグレードされます。

HTTP経由(エージェントフレームワーク向け): npx -y webvector-mcp --http --port 3333 → http://127.0.0.1:3333/mcp(Streamable HTTP、localhostのみ)。--token <secret>(またはWEBVECTOR_MCP_TOKEN)を追加するとAuthorization: Bearer <secret>が必要になります。他のアドレスにバインドするには--host 0.0.0.0 --allow-remote --token …が必要で、TLS/独自認証の背後に置くべきです。死活監視はGET /health。

すべてのweb_research結果は、コンパクトなMarkdown(モデル用)とstructuredContent(アプリ用)の両方で返され、実行中は進捗通知が送られます。

3. ライブラリとして使う

npm i webvector
import { WebVector } from 'webvector';

const wv = new WebVector();                                        // zero-config
const res = await wv.research('what is reciprocal rank fusion');

console.log(res.markdown);                                         // ready to drop into a prompt
for (const p of res.passages) console.log(p.score, p.citation);    // "[1] Title — https://…"
await wv.close();

オプションを渡して設定(完全なリストは§6参照):

const wv = new WebVector({
  search: { provider: 'brave' },                                   // reads BRAVE_API_KEY
  embeddings: { provider: 'openai', model: 'text-embedding-3-small' },
  retrieval: { topK: 8, rerank: 'cohere' },
  store: { mode: 'session' },                                      // reuse pages across calls
});

const res = await wv.research('How does Node 24 handle AbortSignal.any?', {
  relatedQueries: ['AbortSignal.any example'],  // extra angles (also searched)
  freshness: 'year',                            // day | week | month | year
  domainsAllow: ['nodejs.org', 'developer.mozilla.org'],
  sessionId: 'conversation-42',                 // pages already read this session are reused
  onProgress: (p) => console.error(p.stage, p.message),
});

他の呼び出し: wv.search(query)(結果のみ)、wv.fetch(url)(1ページ→Markdown)、wv.fetchAndRetrieve(url, query)(1ページ→関連パッセージ)、wv.listSessions()、wv.clearSession(id)。

モデルにツールとして渡す — 一般的なSDK向けのバインディングは1つのインポートで利用可能:

// Vercel AI SDK
import { generateText, isStepCount } from 'ai';
import { webVectorTools } from 'webvector/ai-sdk';
await generateText({ model, tools: await webVectorTools(wv), stopWhen: isStepCount(5), prompt });

// Anthropic Messages API           // OpenAI Responses API            // LangChain.js
import { anthropicTools, runAnthropicTool } from 'webvector/anthropic';
import { openaiTools, runOpenAITool } from 'webvector/openai';
import { langchainTools } from 'webvector/langchain';

// Anything else: plain JSON Schema
import { webResearchToolDefinition } from 'webvector';

それぞれの実行可能なバージョンはexamples/にあります。

4. コマンドラインから使う

npm i -g webvector-cli          # or keep using npx -y webvector-cli …

webvector search "query" [-k 8] [-p 12] [--provider brave] [--embeddings openai] [--rerank local] [--json|--md] [--stats]
webvector fetch <url> [--query "…"]     # one page as Markdown, or just the passages relevant to --query
webvector serp "query"                  # search results only
webvector doctor [--live]               # config, dependencies, provider connectivity, active tier
webvector init                          # writes webvector.config.yaml + .env.example
webvector config                        # print resolved config (secrets redacted)
webvector providers                     # every provider and the env var it reads
webvector mcp [--http]                  # run the MCP server

5. 2つの階層: 語彙的 vs 意味的

1つのつまみ — embeddings.provider(デフォルトauto)— がパッセージのランク付け方法を決定します:

階層

インストール

ランキング

選択される条件

語彙的 (none)

約12MB、ダウンロード不要

取得した全ページに対するBM25 + クエリ拡張 + ソースごとの多様性

モデルランタイムも埋め込みキーもない場合(通常のnpxパス)

意味的 (local、openai、…)

+ @huggingface/transformers(約230MB、モデル23MB、完全オフライン)または任意の埋め込みAPIキー

ハイブリッド: ベクトル + BM25をRRFで融合、MMR多様性、オプションのリランカー

どちらかが利用可能になると自動的に

いつでもアップグレード可能: パッケージの隣にnpm i @huggingface/transformers、またはキーを設定。webvector doctorでアクティブな階層を確認できます。語彙的モードはフォールバックではなくサポートされたモードであり、結果はstats.embed.provider: 'none'とマークされ、「劣化」ではありません。

6. 設定

優先順位: コード → 設定ファイル → 環境変数 → デフォルト。設定ファイル: webvector.config.{ts,js,mjs,json,yaml,yml}、.webvectorrc、またはpackage.jsonのwebvectorキー。作業ディレクトリから上方向に探します。値内の${VAR} / ${VAR:-default}は環境から埋められます。

webvector initはコメント付きスターターを書き出します。実際に変更されることの多い設定は次のとおり:

search:
  provider: duckduckgo          # duckduckgo | brave | serper | serpapi | google-cse | searxng | tavily | tavily-keyless | exa | perplexity | wikipedia
  fallbackProviders: [tavily-keyless, wikipedia]
  resultsPerQuery: 10
embeddings:
  provider: auto                # auto | none | local | openai | openai-compatible | gemini | voyage | cohere | mistral | jina | ollama
  model: Xenova/all-MiniLM-L6-v2   # local aliases: minilm (fast) | granite (quality) | embeddinggemma (best) | bge-small | nomic …
store:
  provider: memory              # memory | chroma | qdrant | pgvector
  mode: ephemeral               # ephemeral (per call) | session (reuse by sessionId, TTL) | persistent (external store)
retrieval:
  topK: 12
  hybrid: true                  # BM25 + vectors fused with RRF (semantic tier)
  queryExpansion: true          # heuristic (no LLM); pass retrieval.llm in code for LLM multi-query
  maxPerSource: 3
  mmr: true
  rerank: false                 # local | cohere | voyage | jina | llm
ingestion:
  maxPages: 10
  maxConcurrentFetches: 8
  timeoutMs: 15000
  totalDeadlineMs: 45000
  respectRobotsTxt: true
  chunkSize: 480                # tokens
output:
  markdown: true
  maxPassageChars: 1500
logging:
  level: warn

環境変数での同等物: WEBVECTOR_SEARCH_PROVIDER、WEBVECTOR_EMBEDDINGS_PROVIDER、WEBVECTOR_EMBEDDINGS_MODEL、WEBVECTOR_STORE_PROVIDER、WEBVECTOR_STORE_MODE、WEBVECTOR_TOP_K、WEBVECTOR_MAX_PAGES、WEBVECTOR_LOG_LEVEL、WEBVECTOR_MODEL_CACHE、および以下のプロバイダーキー。すべてのオプションとデフォルト: docs/CONFIGURATION.md。

7. プロバイダー

環境変数を設定し、プロバイダーを指定するだけです。プロバイダーごとの詳細と注意点: docs/PROVIDERS.md。

検索

env

埋め込み

env

ストア / リランカー

env

duckduckgo(デフォルト)

—

none(BM25)

—

memory(デフォルト)

—

brave

BRAVE_API_KEY

local(Transformers.js)

—

chroma

CHROMA_URL

serper(Google)

SERPER_API_KEY

openai

OPENAI_API_KEY

qdrant

QDRANT_URL

serpapi

SERPAPI_API_KEY

openai-compatible(LM Studio、vLLM、…)

OPENAI_COMPATIBLE_BASE_URL

pgvector

DATABASE_URL

tavily / tavily-keyless

TAVILY_API_KEY

gemini

GEMINI_API_KEY

リランク local

—

exa

EXA_API_KEY

voyage

VOYAGE_API_KEY

リランク cohere

COHERE_API_KEY

perplexity

PERPLEXITY_API_KEY

cohere

COHERE_API_KEY

リランク voyage

VOYAGE_API_KEY

searxng(セルフホスト)

SEARXNG_URL

mistral / jina / ollama

MISTRAL_API_KEY / JINA_API_KEY / OLLAMA_HOST

リランク jina

JINA_API_KEY

wikipedia

—

任意のVercel AI SDKモデル

—

リランク llm(独自関数)

—

プライマリ検索プロバイダーが失敗またはレート制限された場合、fallbackProvidersチェーンが自動的に試行され、各試行はstats.search.attemptsに記録されます。

8. 返ってくるもの

interface ResearchResult {
  query: string; queries: string[];        // the query + expansions actually used
  passages: Passage[];                     // ranked; each: text, url, title, score (0–1), cosine?, bm25?,
                                           //   rerankScore?, chunkIndex, startOffset, endOffset, publishedAt?,
                                           //   fetchedAt, matchedQueries, citation "[n] Title — url"
  sources: SourceSummary[];                // one per page: status ok|failed|cached, chunks, bestScore, passageIndices, failure?
  failures: Failure[];                     // per-URL / per-stage problems with machine codes (never thrown)
  stats: { search, ingest, embed, retrieve, totalMs, warnings };   // timings + counts per stage
  markdown?: string;                       // the pre-rendered version above
  degraded?: 'search_only' | 'partial';    // e.g. every fetch failed → search snippets returned instead
}

9. エラーと失敗

2種類、意図的に分離:

  • 失敗はページごとで、実行を中断しません: FETCH_TIMEOUT、FETCH_HTTP_ERROR、FETCH_BLOCKED_ROBOTS、FETCH_BLOCKED_SSRF、FETCH_TOO_LARGE、TOO_MANY_REDIRECTS、UNSUPPORTED_CONTENT_TYPE、PARSE_EMPTY、PARSE_FAILED。これらはresult.failures[]とsources[].failureに入ります。すべてのページが失敗した場合でも、検索スニペットは取得できます(degraded: 'search_only'、ALL_FETCHES_FAILED)。

  • エラーはWebVectorErrorとしてスローされ、code、message、remediation、retryable、provider、stage、toJSON()を持ちます。シークレットは編集されます。例: MISSING_API_KEY(「BRAVE_API_KEYを設定するか、キーレスプロバイダーを使用: duckduckgo」)、MISSING_DEPENDENCY(「npm i @huggingface/transformers — またはembeddings.provider: 'none'」)、SEARCH_BLOCKED、PROVIDER_RATE_LIMITED(retryAfterMs付き)、EMBEDDING_DIMENSION_MISMATCH(両方のモデルを指定し、store.clear()または新しいコレクションを提案)、INVALID_CONFIG。

10. セキュリティとエチケット

WebVectorは検索エンジンが選んだURLを取得します — つまり攻撃者が影響を与えられるコンテンツです — そのためフェッチャーはデフォルトで防御的です:

  • SSRFガード: プライベート、ループバック、リンクローカル、CGNAT、マルチキャスト、予約済み、IPv4-mapped-IPv6、localhost/*.internal ターゲットは拒否されます。DNS応答はチェックされ、すべてのリダイレクトホップは再チェックされます。信頼できるローカル設定でのみオプトアウト可能です(ingestion.allowPrivateNetworks)。

  • 上限: リダイレクト(5)、レスポンスサイズ(5 MB)、リクエストあたりの時間(15秒)、実行全体のデッドライン(45秒)。同時実行数はグローバルおよびホストごとに制限されます。

  • エチケット: robots.txtを尊重(Crawl-delayを含む)、識別可能なUser-Agent、ホストごとの最小間隔、Retry-Afterを尊重。

  • 実行なしのパース: HTMLはlinkedomでパース(スクリプトなし、サブリソース読み込みなし)、PDFはpdf.jsのno-evalモードでパース。呼び出し元は制御文字が除去されたMarkdown/プレーンテキストのみを受け取ります。

  • シークレット: env/configから読み取り、ログに記録されることはありません。エラー、webvector config、MCPのwebvector_statusツールで秘匿化されます。ページキャッシュディレクトリを有効にしない限り、ディスクには何も書き込まれません。

  • テレメトリは一切ありません。

  • MCP over HTTPは127.0.0.1のみにバインドし、Host/Originを検証(DNSリバインディング保護)、ベアラートークンをサポートし、--allow-remoteかつトークンなしでは他の場所へのバインドを拒否します。

  • DNSリバインディングは接続時に閉じられます: SSRFチェックはソケットを開くために使用されるDNSルックアップ内で実行されるため、チェックされるアドレスはダイヤルされるアドレスです。

  • DuckDuckGoに関する注記: キーレスプロバイダーは、ブラウザ風のUser-AgentでDuckDuckGoの公開HTMLエンドポイントと通信します(公式APIはありません)。本質的にレート制限があり脆弱です。ヘビーまたは商用利用は、キー付きプロバイダー(brave、serper、tavily)に切り替える必要があります。ページ取得は常に正直なWebVector/… User-Agentを使用します。

何か見つかりましたか?公開イシューではなく、GitHubでプライベートセキュリティアドバイザリを開いてください。

11. ソースから実行する(ローカル開発)

git clone https://github.com/rthomas24/web-vector
cd webvector
npm install                     # installs all workspaces (~1 min; includes the optional model runtime for tests)
npm run build                   # tsdown → packages/*/dist

# use the local build
node packages/cli/dist/cli.js search "reciprocal rank fusion" --stats
node packages/mcp/dist/bin.js                     # MCP server on stdio
node packages/mcp/dist/bin.js --http --port 3333  # …or HTTP

# point an MCP client at the local build
claude mcp add webvector-dev -- node /absolute/path/to/webvector/packages/mcp/dist/bin.js

# quality gates
npm test                        # unit tests, offline (mocked HTTP), ~5 s
npm run test:live               # real network + local model + MCP stdio round-trip (~20 s)
npm run lint                    # biome
npm run typecheck               # TypeScript 7

リポジトリのレイアウトと追加場所: docs/ARCHITECTURE.md。

公開せずにローカルビルドを別のプロジェクトから使用するには: packages/core(およびmcp/cli)でnpm packを実行し、そこでnpm i ./webvector-0.1.0.tgzを実行するか、npm linkを使用します。

12. 独自アダプターの作成

各プロバイダータイプはpackages/core/src/types.tsの小さなインターフェースです — SearchProvider、EmbeddingProvider、VectorStore、ContentParser、Reranker。実装して、設定でインスタンスを渡すか、名前を登録して設定ファイルで使用できるようにします:

import { customSearchProvider, registerSearchProvider, WebVector } from 'webvector';

const myIndex = customSearchProvider('my-index', async (query) => [
  { url: 'https://…', title: '…', snippet: '…' },
]);
new WebVector({ search: { instance: myIndex } });
// or: registerSearchProvider('my-index', (opts) => new MyProvider(opts));  → search.provider: my-index

webvector/testingは適合性チェック(searchProviderConformance、embeddingProviderConformance、vectorStoreConformance)をエクスポートしており、任意のテストランナーに組み込めます。

13. 仕組み

research(query)
  1. search      provider chain (DuckDuckGo → fallbacks) → dedupe by canonical URL → domain filters → top N
  2. ingest      concurrent, polite fetch → HTML (Readability→Markdown) | PDF | text → page cache
  3. chunk+embed markdown-aware recursive chunks with heading breadcrumbs → content-hash dedupe → embed (batched, cached)
  4. retrieve    query + expansions → vector top-k lists + BM25 top-k lists → weighted RRF → cosine cutoffs
                 → near-duplicate removal → per-source cap → MMR → optional rerank → top-k
  5. format      passages with citations, sources, failures, per-stage stats, Markdown

ラップトップでの一般的な実行: 検索約1秒、8ページ取得+パース約1〜2.5秒、取得<50ms → 約2秒(語彙検索)/ 約4秒(意味論的検索)。

14. ロードマップ

LanceDBおよびPineconeストア · JSレンダリングページ用のヘッドレスブラウザフェッチアダプター · コンテキスト検索(LLM要約チャンクコンテキスト)をオプトインとして · Node不要のスタンドアロンバイナリ · 適合性フィクスチャを共有するPythonパッケージ。

ライセンス

MIT © Ryan Thomas

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to perform grounded web research with injection resistance, claim verification, and cost-aware routing through MCP tools like web_search, fetch_url, extract_claims, and check_grounding.
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to perform unified web research through a single MCP server, including search, page fetching, recursive crawling, document parsing, YouTube transcript extraction, and deep multi-query research.
    3
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to perform live web searches across 9 engines, scrape web pages into clean formats, and run agentic research with citations via MCP.
    98 PyPI
    3
    MIT
  • A
    license
    B
    quality
    B
    maintenance
    Enables AI agents to perform web searches and extract full-text content from web pages via standard MCP tools, with fallback search and semantic reranking.
    2
    2
    MIT