API: tools/research

better-web-search-mcp


better-web-search-mcp / tools/research

tools/research#

Interfaces#

Citation#

Defined in: src/tools/research.ts:50

A span of a source page that supports the answer.

Properties#

PropertyTypeDescriptionDefined in
citationnumber1-based index into sources.src/tools/research.ts:52
endnumberCharacter offset of the quote end.src/tools/research.ts:62
quotestringThe supporting text, verbatim from the extracted content.src/tools/research.ts:58
relevancenumberRelevance of the span to the question. Higher is stronger.src/tools/research.ts:64
startnumberCharacter offset of the quote within that page’s extracted content.src/tools/research.ts:60
titlestringThe source title.src/tools/research.ts:56
urlstringThe source URL the span was taken from.src/tools/research.ts:54

ResearchResponse#

Defined in: src/tools/research.ts:67

Properties#

PropertyTypeDescriptionDefined in
answerstring-src/tools/research.ts:68
citationsCitation[]The exact spans the answer was assembled from, so an agent can attribute a statement to a span rather than to a whole page.src/tools/research.ts:75
evidence{ cited_spans: number; derivative_sources: number; independent_sources: number; query_term_coverage: number; sources_opened: number; }Countable facts about the evidence behind the answer. Every field is something the server measured, not a judgement: there is no language model here to score truth or agreement, and an invented confidence number would be worse than none. An agent can use these to decide whether to research further.src/tools/research.ts:84
evidence.cited_spansnumberNumber of cited spans in citations.src/tools/research.ts:102
evidence.derivative_sourcesnumberPages that duplicate another page’s content or host.src/tools/research.ts:94
evidence.independent_sourcesnumberDistinct content clusters among those pages. Syndicated reprints and multiple pages from one host collapse into a single cluster, so this is the number of genuinely separate accounts.src/tools/research.ts:92
evidence.query_term_coveragenumberFraction of the question’s content words that appear in the cited passages, 0..1. Low values mean the citations may not address the question, not that the answer is wrong.src/tools/research.ts:100
evidence.sources_openednumberPages actually opened and extracted.src/tools/research.ts:86
extraction_stats{ avgConfidence: number; method_counts: Record<string, number>; }-src/tools/research.ts:104
extraction_stats.avgConfidencenumber-src/tools/research.ts:106
extraction_stats.method_countsRecord<string, number>-src/tools/research.ts:105
queries_usedstring[]-src/tools/research.ts:70
sourcesSearchSource[]-src/tools/research.ts:69

SourceIndependence#

Defined in: src/tools/research.ts:40

Whether a source is an independent account or a copy of another.

Properties#

PropertyTypeDescriptionDefined in
clusternumberIndex of the content cluster this source belongs to.src/tools/research.ts:42
duplicatesnumberHow many other opened sources share this cluster.src/tools/research.ts:46
primarybooleanWhether this source is the representative of its cluster.src/tools/research.ts:44

Variables#

researchInputSchema#

const researchInputSchema: { count_per_query: ZodDefault<ZodNumber>; depth: ZodDefault<ZodEnum<["quick", "deep"]>>; question: ZodString; recency_days: ZodOptional<ZodNumber>; }

Defined in: src/tools/research.ts:31

Input schema for web_research.

Type Declaration#

NameTypeDefined in
count_per_queryZodDefault<ZodNumber>src/tools/research.ts:35
depthZodDefault<ZodEnum<["quick", "deep"]>>src/tools/research.ts:33
questionZodStringsrc/tools/research.ts:32
recency_daysZodOptional<ZodNumber>src/tools/research.ts:34

Functions#

collectCitations()#

collectCitations(pages, sources, question, limit?, independence?): Citation[]

Defined in: src/tools/research.ts:217

Pick the spans of the opened pages that actually address the question.

The previous implementation took the first 400 characters of each page and never looked at the question, so the “answer” was usually page intros and boilerplate. Passages are now scored against the question with BM25 and the best ones returned with their offsets, which raises the signal and cuts the token count, since only matching paragraphs are included.

Parameters#

ParameterTypeDefault value
pagesreadonly RoutedPage[]undefined
sourcesreadonly SearchSource[]undefined
questionstringundefined
limitnumberMAX_EXCERPTS
independencereadonly IndependenceResult[][]

Returns#

Citation[]


queryTermCoverage()#

queryTermCoverage(question, citations): number

Defined in: src/tools/research.ts:312

Fraction of the question’s content words that appear in the cited passages.

A blunt but honest measure of whether the citations engage with the question at all. It says nothing about correctness, which is not something this server can determine.

Parameters#

ParameterType
questionstring
citationsreadonly Citation[]

Returns#

number


registerResearch()#

registerResearch(server, cache?): void

Defined in: src/tools/research.ts:450

Register the web_research tool (alias deep_search) on the given MCP server.

Parameters#

ParameterType
serverMcpServer
cache?Cache

Returns#

void


runResearch()#

runResearch(args): Promise<ResearchResponse>

Defined in: src/tools/research.ts:354

Run a deep research query and return the spec-shaped response.

Exported separately so tests and the smoke harness can call the handler logic directly.

Parameters#

ParameterType
args{ cache?: Cache; count_per_query?: number; depth?: "deep" | "quick"; question: string; recency_days?: number; }
args.cache?Cache
args.count_per_query?number
args.depth?"deep" | "quick"
args.questionstring
args.recency_days?number

Returns#

Promise<ResearchResponse>