Skip to main content
Glama
rthomas24

WebVector MCP Server

by rthomas24

WebVector

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

한 번의 도구 호출로 AI 에이전트에 실제 웹 리서치를 제공하세요: 검색 → 전체 페이지 읽기 → 순위 지정 → 인용된 구절.

검색 도구는 모델에게 제목과 150자 분량의 스니펫만 넘겨주므로, 모델은 나머지를 추측해야 합니다. 가져오기(fetch) 도구는 40KB 분량의 내비게이션과 상용구를 넘겨주므로, 모델은 그 속에서 파묻힙니다. WebVector는 그 중간의 모든 작업을 처리합니다: 검색 실행, 모든 결과(HTML, PDF, Markdown) 다운로드 및 정리, 구절로 분할, 질문에 대한 구절 순위 지정 — 임베딩 모델이 있으면 의미론적으로, 없으면 어휘적으로(BM25) — 그리고 쿼리에 답하는 구절만 각각의 URL, 제목, 오프셋, 점수와 함께 반환합니다.

  • API 키와 모델 다운로드 없이 작동합니다: DuckDuckGo + BM25, ~12 MB 설치.

  • 모든 검색 백엔드, 임베딩 제공자, 벡터 스토어 또는 리랭커를 연결할 수 있습니다(또는 한 파일로 직접 작성).

  • 라이브러리, 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. 두 가지 계층: 어휘 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 서버는 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)(한 페이지 → Markdown), wv.fetchAndRetrieve(url, query)(한 페이지 → 관련 구절), wv.listSessions(), wv.clearSession(id).

모델에 도구로 제공하기 — 널리 쓰이는 SDK용 바인딩은 import 한 번이면 됩니다:

// 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. 두 가지 계층: 어휘 vs 의미론

embeddings.provider(기본값 auto)라는 단 하나의 설정이 구절 순위 지정 방식을 결정합니다:

계층

설치

순위 지정 방식

선택되는 조건

어휘(none)

~12 MB, 다운로드 없음

가져온 전체 페이지 대상 BM25 + 쿼리 확장 + 소스별 다양성

모델 런타임과 임베딩 키가 모두 없는 경우(일반 npx 경로)

의미론(local, openai, …)

+ @huggingface/transformers(~230 MB, 모델 23 MB, 완전 오프라인) 또는 임의의 임베딩 API 키

하이브리드: RRF로 융합된 벡터 + BM25, 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

rerank local

—

exa

EXA_API_KEY

voyage

VOYAGE_API_KEY

rerank cohere

COHERE_API_KEY

perplexity

PERPLEXITY_API_KEY

cohere

COHERE_API_KEY

rerank voyage

VOYAGE_API_KEY

searxng(자체 호스팅)

SEARXNG_URL

mistral / jina / ollama

MISTRAL_API_KEY / JINA_API_KEY / OLLAMA_HOST

rerank jina

JINA_API_KEY

wikipedia

—

모든 Vercel AI SDK 모델

—

rerank 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. 오류와 실패

두 가지 종류를 의도적으로 구분합니다:

  • 실패(Failures)는 페이지별로 발생하며 실행을 중단하지 않습니다: 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).

  • 오류(Errors)는 WebVectorError로 던져지며 code, message, remediation, retryable, provider, stage, toJSON()을 포함합니다. 비밀 값은 마스킹됩니다. 예시: MISSING_API_KEY("BRAVE_API_KEY를 설정하세요 … 또는 키가 필요 없는 제공자를 사용하세요: duckduckgo"), MISSING_DEPENDENCY("npm i @huggingface/transformers — 또는 embeddings.provider: 'none'"), `SE

  • SSRF 가드: private, loopback, link-local, CGNAT, multicast, reserved, IPv4-mapped-IPv6 및 localhost/*.internal 대상은 거부됩니다. DNS 응답을 확인하고 모든 리디렉션 홉을 다시 확인합니다. 신뢰할 수 있는 로컬 설정(ingestion.allowPrivateNetworks)에서만 선택 해제할 수 있습니다.

  • 상한: 리디렉션(5회), 응답 크기(5MB), 요청당 시간(15초), 전체 실행 마감(45초)이 있으며, 전역 및 호스트별 동시성에 제한이 있습니다.

  • 예의: robots.txt를 준수하고(Crawl-delay 포함), 식별 가능한 User-Agent를 사용하며, 호스트별 최소 간격을 지키고, Retry-After를 존중합니다.

  • 실행 없는 파싱: HTML은 linkedom으로 파싱되고(스크립트나 하위 리소스 로딩 없음), PDF는 no-eval 모드의 pdf.js로 파싱됩니다. 호출자는 제어 문자가 제거된 Markdown/일반 텍스트만 받습니다.

  • 비밀: 환경/설정에서 읽으며, 로그에 기록하지 않고, 오류, webvector config, MCP webvector_status 도구에서 모두 삭제됩니다. 페이지 캐시 디렉터리를 활성화하지 않는 한 디스크에 아무것도 기록하지 않습니다.

  • 원격 측정 없음, 절대.

  • HTTP를 통한 MCP는 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