API: tools/research

better-web-search-mcp


better-web-search-mcp / tools/research

tools/research#

Interfaces#

Citation#

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

A span of a source page that supports the answer.

Properties#

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

ResearchResponse#

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

Properties#

PropertyTypeDescriptionDefined in
answerstring-src/tools/research.ts:72
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:79
evidence{ cited_spans: number; derivative_sources: number; independent_sources: number; low_density_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:95
evidence.cited_spansnumberNumber of cited spans in citations.src/tools/research.ts:113
evidence.derivative_sourcesnumberPages that duplicate another page’s content or host.src/tools/research.ts:105
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:103
evidence.low_density_sourcesnumberOpened pages whose information density fell below LOW_DENSITY_THRESHOLD — listicles, link farms, and templated filler. Their passages are down-weighted rather than dropped, since a thin page can still hold the one sentence that answers the question.src/tools/research.ts:120
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:111
evidence.sources_openednumberPages actually opened and extracted.src/tools/research.ts:97
extraction_stats{ avgConfidence: number; method_counts: Record<string, number>; }-src/tools/research.ts:122
extraction_stats.avgConfidencenumber-src/tools/research.ts:124
extraction_stats.method_countsRecord<string, number>-src/tools/research.ts:123
queries_usedstring[]-src/tools/research.ts:74
sourcesSearchSource[]-src/tools/research.ts:73
warnings?string[]Providers that refused or failed during the search phase. Without this a throttled research run is indistinguishable from a question the web has no answer to.src/tools/research.ts:86

SourceIndependence#

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

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:46
duplicatesnumberHow many other opened sources share this cluster.src/tools/research.ts:50
primarybooleanWhether this source is the representative of its cluster.src/tools/research.ts:48

Variables#

LOW_DENSITY_THRESHOLD#

const LOW_DENSITY_THRESHOLD: 0.5 = 0.5

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

Information density below which a page counts as thin.


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:35

Input schema for web_research.

Type Declaration#

NameTypeDefined in
count_per_queryZodDefault<ZodNumber>src/tools/research.ts:39
depthZodDefault<ZodEnum<["quick", "deep"]>>src/tools/research.ts:37
questionZodStringsrc/tools/research.ts:36
recency_daysZodOptional<ZodNumber>src/tools/research.ts:38

RESPONSE_SCHEMA#

const RESPONSE_SCHEMA: 2 = 2

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

Version of the ResearchResponse shape, embedded in the cache key.

Bump this whenever a field is added, removed, or given a new meaning, so an entry written by an older build can never be served as the current type.

Functions#

collectCitations()#

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

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

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[][]
densitiesreadonly number[][]

Returns#

Citation[]


densityWeight()#

densityWeight(density): number

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

Weight a passage score by its page’s information density.

Kept as a multiplier in [0.5, 1] rather than a filter: a listicle can still carry the one sentence that answers the question, so a thin page is made to compete at a disadvantage instead of being discarded.

Parameters#

ParameterType
densitynumber

Returns#

number


queryTermCoverage()#

queryTermCoverage(question, citations): number

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

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:532

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:418

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>