web_search
Search the web privately using multiple engines, filter results by category, language, time range, and safe search settings. Ideal for finding general content, news, articles, and media efficiently.
Instructions
Performs a web search using SearXNG, ideal for general queries, news, articles and online content. Supports multiple search categories, languages, time ranges and safe search filtering. Returns relevant results from multiple search engines combined.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| categories | No | ||
| language | No | Search language code (e.g. 'en', 'zh', 'jp', 'all') | all |
| page | No | Page number (default 1) | |
| query | Yes | Search query | |
| safesearch | No | 0: None, 1: Moderate, 2: Strict | |
| time_range | No | all_time |
Implementation Reference
- src/index.ts:185-213 (handler)Main request handler for CallToolRequestSchema that executes the web_search tool: validates name and args, performs fallback search, formats and returns results.server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const { name, arguments: args } = request.params; if (name !== "web_search" || !args) { throw new Error("Invalid tool or arguments: expected 'web_search'"); } if (!isWebSearchArgs(args)) { throw new Error("Invalid arguments for web_search"); } const results = await searchWithFallback(args); return { content: [{ type: "text", text: results.results.map(formatSearchResult).join('\n\n') }], isError: false, }; } catch (error) { logError('Search failed', error); return { content: [{ type: "text", text: String(error) }], isError: true, }; } });
- src/index.ts:164-178 (schema)Type guard function for validating web_search input arguments matching the inputSchema.function isWebSearchArgs(args: unknown): args is { query: string; page?: number; language?: string; categories?: string[]; time_range?: string; safesearch?: number; } { return ( typeof args === "object" && args !== null && "query" in args && typeof (args as { query: string }).query === "string" ); }
- src/index.ts:34-78 (registration)Tool registration object defining name, description, and inputSchema for web_search.const WEB_SEARCH_TOOL: Tool = { name: "web_search", description: "Performs a web search using SearXNG, ideal for general queries, news, articles and online content. " + "Supports multiple search categories, languages, time ranges and safe search filtering. " + "Returns relevant results from multiple search engines combined.", inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query" }, page: { type: "number", description: "Page number (default 1)", default: 1 }, language: { type: "string", description: "Search language code (e.g. 'en', 'zh', 'jp', 'all')", default: "all" }, categories: { type: "array", items: { type: "string", enum: ["general", "news", "science", "files", "images", "videos", "music", "social media", "it"] }, default: ["general"] }, time_range: { type: "string", enum: ["all_time", "day", "week", "month", "year"], default: "all_time" }, safesearch: { type: "number", description: "0: None, 1: Moderate, 2: Strict", default: 1 } }, required: ["query"] } };
- src/index.ts:95-138 (helper)Core helper function that performs the actual SearXNG search with fallback across multiple instances.async function searchWithFallback(params: any) { const searchParams = { q: params.query, pageno: params.page || 1, language: params.language || 'all', categories: params.categories?.join(',') || 'general', time_range: params.time_range === 'all_time' ? '' : (params.time_range || ''), safesearch: params.safesearch ?? 1, format: 'json' }; for (const instance of SEARXNG_INSTANCES) { try { const searchUrl = new URL('/search', instance); const response = await fetch(searchUrl.toString(), { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': USER_AGENT }, agent: searchUrl.protocol === 'https:' ? httpsAgent : httpAgent, body: new URLSearchParams(searchParams).toString() }); if (!response.ok) { logError(`${instance} returned ${response.status}. Please check if SearXNG is running.`); continue; } const data = await response.json(); if (!data.results?.length) { logError(`${instance} returned no results`); continue; } return data; } catch (error) { logError(`Failed to connect to ${instance}. Please check if SearXNG is running.`, error); continue; } } throw new Error("All SearXNG instances failed. Please ensure SearXNG is running on one of these instances: " + SEARXNG_INSTANCES.join(', ')); }
- src/index.ts:147-162 (helper)Helper function to format individual search results into readable text.function formatSearchResult(result: SearchResult) { const parts = [ `Title: ${result.title}`, `URL: ${result.url}` ]; if (result.content) { parts.push(`Content: ${result.content}`); } if (result.engine) { parts.push(`Source: ${result.engine}`); } return parts.join('\n'); }