web_search
Search the web with customizable parameters including query, language, site, and engines. Returns relevant results for integration into LLM workflows.
Instructions
Alias of web.search
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| q | Yes | ||
| max | No | ||
| lang | No | ||
| site | No | ||
| engines | No | ||
| k | No | ||
| limit | No |
Implementation Reference
- src/tools/webSearch.ts:57-70 (handler)Main handler function that executes web search across multiple engines (SearXNG and DuckDuckGo), then deduplicates and ranks results.
export async function webSearch(args: { q: string, max?: number, lang?: string, site?: string, engines?: string[] }): Promise<SearchResult[]> { const { q, max = 10, lang = CONFIG.langDefault, site, engines } = args; const order = (engines && engines.length ? engines : CONFIG.engineOrder).filter(Boolean); const tasks: Promise<SearchResult[]>[] = []; for (const eng of order) { if (eng === 'searxng') tasks.push(searchSearxng(q, lang, site, max)); if (eng === 'duckduckgo') tasks.push(searchDuckDuckGo(q, lang, site, max)); } const settled = await Promise.allSettled(tasks); const all: SearchResult[] = []; for (const s of settled) if (s.status === 'fulfilled') all.push(...s.value); if (!all.length) return []; return dedupeAndRank(all, max); } - src/server.ts:39-48 (schema)Input validation schema (Zod) for the web_search tool, defining parameters q, max, lang, site, engines, k, limit.
const webSearchShape = { q: z.string(), max: z.number().int().optional(), lang: z.string().optional(), site: z.string().optional(), engines: z.array(z.string()).optional(), // extra names model may invent k: z.number().int().optional(), limit: z.number().int().optional() }; - src/server.ts:56-62 (registration)Registration of the 'web_search' tool (alias of 'web.search') on the MCP server with its schema and handler invocation.
server.tool('web_search', 'Alias of web.search', webSearchShape, OPEN, async ({ q, max, lang, site, engines, k, limit }) => { const res = await webSearch({ q, max: max ?? k ?? limit, lang, site, engines }); return { content: [{ type: 'text', text: JSON.stringify(res) }] }; } ); - src/server.ts:49-55 (registration)Registration of the 'web.search' tool (primary name) on the MCP server with its schema and handler invocation.
server.tool('web.search', 'Multi-engine web search (SearXNG + DuckDuckGo HTML).', webSearchShape, OPEN, async ({ q, max, lang, site, engines, k, limit }) => { const res = await webSearch({ q, max: max ?? k ?? limit, lang, site, engines }); return { content: [{ type: 'text', text: JSON.stringify(res) }] }; } ); - src/tools/webSearch.ts:9-17 (helper)Deduplicates and ranks search results by URL, ensuring no duplicates and assigning sequential ranks.
function dedupeAndRank(all: SearchResult[], max: number): SearchResult[] { const seen = new Set<string>(); const out: SearchResult[] = []; for (const item of all) { const key = item.url.replace(/^https?:\/\//,'').replace(/^www\./,'').replace(/\/$/,'').toLowerCase(); if (seen.has(key)) continue; seen.add(key); out.push(item); if (out.length >= max) break; } return out.map((it, i) => ({ ...it, rank: i+1 })); } - src/tools/webSearch.ts:19-37 (helper)Helper function that performs web search via DuckDuckGo HTML scraping.
async function searchDuckDuckGo(query: string, lang?: string, site?: string, max = 10): Promise<SearchResult[]> { const q = encodeURIComponent((site ? `site:${site} ` : '') + query); const url = `https://html.duckduckgo.com/html/?q=${q}&kl=${lang || ''}`; const res = await fetchWithLimits(url, 8000, 512*1024); if (!res.body) return []; const html = res.body.toString('utf-8'); const $ = cheerioLoad(html); const items: SearchResult[] = []; $('a.result__a').each((i, el) => { const a = $(el); const title = a.text().trim(); const href = a.attr('href') || ''; const snippet = a.closest('.result').find('.result__snippet').text().trim() || ''; if (href && title) { items.push({ title, url: href, snippet, source: 'duckduckgo', rank: i+1 }); } }); return items.slice(0, max); } - src/tools/webSearch.ts:39-55 (helper)Helper function that performs web search via SearXNG JSON API.
async function searchSearxng(query: string, lang?: string, site?: string, max = 10): Promise<SearchResult[]> { const endpoints = CONFIG.searxngEndpoints; if (!endpoints.length) return []; const q = (site ? `site:${site} ` : '') + query; const endpoint = endpoints[Math.floor(Math.random()*endpoints.length)]; const url = `${endpoint}?q=${encodeURIComponent(q)}&format=json&language=${encodeURIComponent(lang || CONFIG.langDefault)}&safesearch=1`; const res = await fetchWithLimits(url, 8000, 1024*1024); if (!res.body) return []; try { const data = JSON.parse(res.body.toString('utf-8')); const results = data?.results || []; return results.slice(0, max).map((r: any, i: number) => ({ title: r.title || r.pretty_url || r.url, url: r.url, snippet: r.content || r.snippet || '', source: 'searxng', rank: i+1 })); } catch { return []; } }