search_web
Search the web for current information, news, articles, and websites to find up-to-date content, research topics, or answer questions about recent events.
Instructions
Search the entire web for current information, news, articles, and websites. Use this when you need up-to-date information, want to find specific websites, research topics, or get the latest news. Ideal for answering questions about recent events, finding resources, or discovering relevant content.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search terms or keywords to find relevant web content (e.g., 'climate change news 2024', 'best pizza recipe'). Can be a single query string or an array of queries for parallel search. | |
| num | No | Maximum number of search results to return, between 1-100 | |
| tbs | No | Time-based search parameter, e.g., 'qdr:h' for past hour, can be qdr:h, qdr:d, qdr:w, qdr:m, qdr:y | |
| location | No | Location for search results, e.g., 'London', 'New York', 'Tokyo' | |
| gl | No | Country code, e.g., 'dz' for Algeria | |
| hl | No | Language code, e.g., 'zh-cn' for Simplified Chinese |
Implementation Reference
- src/tools/jina-tools.ts:276-318 (handler)Primary handler function for the 'search_web' MCP tool. Processes input parameters, supports single or multiple queries (parallel execution), validates bearer token, delegates to executeWebSearch utility, and formats results as MCP content items.
async ({ query, num, tbs, location, gl, hl }: { query: string | string[]; num: number; tbs?: string; location?: string; gl?: string; hl?: string }) => { try { const props = getProps(); const tokenError = checkBearerToken(props.bearerToken); if (tokenError) { return tokenError; } // Handle single query or single-element array if (typeof query === 'string' || (Array.isArray(query) && query.length === 1)) { const singleQuery = typeof query === 'string' ? query : query[0]; const searchResult = await executeWebSearch({ query: singleQuery, num, tbs, location, gl, hl }, props.bearerToken); return { content: formatSingleSearchResultToContentItems(searchResult), }; } // Handle multiple queries with parallel search if (Array.isArray(query) && query.length > 1) { const searches = query.map(q => ({ query: q, num, tbs, location, gl, hl })); const uniqueSearches = searches.filter((search, index, self) => index === self.findIndex(s => s.query === search.query) ); const webSearchFunction = async (searchArgs: SearchWebArgs) => { return executeWebSearch(searchArgs, props.bearerToken); }; const results = await executeParallelSearches(uniqueSearches, webSearchFunction, { timeout: 30000 }); return { content: formatParallelSearchResultsToContentItems(results), }; } return createErrorResponse("Invalid query format"); } catch (error) { return createErrorResponse(`Error: ${error instanceof Error ? error.message : String(error)}`); } }, - src/tools/jina-tools.ts:264-320 (registration)Registers the 'search_web' tool with the MCP server using server.tool(), including name, description, Zod input schema, and handler function, conditional on tool being enabled.
if (isToolEnabled("search_web")) { server.tool( "search_web", "Search the entire web for current information, news, articles, and websites. Use this when you need up-to-date information, want to find specific websites, research topics, or get the latest news. Ideal for answering questions about recent events, finding resources, or discovering relevant content.", { query: z.union([z.string(), z.array(z.string())]).describe("Search terms or keywords to find relevant web content (e.g., 'climate change news 2024', 'best pizza recipe'). Can be a single query string or an array of queries for parallel search."), num: z.number().default(30).describe("Maximum number of search results to return, between 1-100"), tbs: z.string().optional().describe("Time-based search parameter, e.g., 'qdr:h' for past hour, can be qdr:h, qdr:d, qdr:w, qdr:m, qdr:y"), location: z.string().optional().describe("Location for search results, e.g., 'London', 'New York', 'Tokyo'"), gl: z.string().optional().describe("Country code, e.g., 'dz' for Algeria"), hl: z.string().optional().describe("Language code, e.g., 'zh-cn' for Simplified Chinese") }, async ({ query, num, tbs, location, gl, hl }: { query: string | string[]; num: number; tbs?: string; location?: string; gl?: string; hl?: string }) => { try { const props = getProps(); const tokenError = checkBearerToken(props.bearerToken); if (tokenError) { return tokenError; } // Handle single query or single-element array if (typeof query === 'string' || (Array.isArray(query) && query.length === 1)) { const singleQuery = typeof query === 'string' ? query : query[0]; const searchResult = await executeWebSearch({ query: singleQuery, num, tbs, location, gl, hl }, props.bearerToken); return { content: formatSingleSearchResultToContentItems(searchResult), }; } // Handle multiple queries with parallel search if (Array.isArray(query) && query.length > 1) { const searches = query.map(q => ({ query: q, num, tbs, location, gl, hl })); const uniqueSearches = searches.filter((search, index, self) => index === self.findIndex(s => s.query === search.query) ); const webSearchFunction = async (searchArgs: SearchWebArgs) => { return executeWebSearch(searchArgs, props.bearerToken); }; const results = await executeParallelSearches(uniqueSearches, webSearchFunction, { timeout: 30000 }); return { content: formatParallelSearchResultsToContentItems(results), }; } return createErrorResponse("Invalid query format"); } catch (error) { return createErrorResponse(`Error: ${error instanceof Error ? error.message : String(error)}`); } }, ); } - src/utils/search.ts:7-14 (schema)TypeScript interface SearchWebArgs defining the input parameters for web search operations, used for typing in handlers and utilities.
export interface SearchWebArgs { query: string; num?: number; tbs?: string; location?: string; gl?: string; hl?: string; } - src/utils/search.ts:67-98 (helper)Core utility function that executes the actual web search API call to Jina's svip.jina.ai endpoint, handles parameters, authentication, and returns formatted results or errors.
export async function executeWebSearch( searchArgs: SearchWebArgs, bearerToken: string ): Promise<SearchResultOrError> { try { const response = await fetch('https://svip.jina.ai/', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Bearer ${bearerToken}`, }, body: JSON.stringify({ q: searchArgs.query, num: searchArgs.num || 30, ...(searchArgs.tbs && { tbs: searchArgs.tbs }), ...(searchArgs.location && { location: searchArgs.location }), ...(searchArgs.gl && { gl: searchArgs.gl }), ...(searchArgs.hl && { hl: searchArgs.hl }) }), }); if (!response.ok) { return { error: `Search failed for query "${searchArgs.query}": ${response.statusText}` }; } const data = await response.json() as any; return { query: searchArgs.query, results: data.results || [] }; } catch (error) { return { error: `Search failed for query "${searchArgs.query}": ${error instanceof Error ? error.message : String(error)}` }; } } - src/index.ts:99-102 (registration)Calls registerJinaTools to register all tools including 'search_web' on the MCP server instance, passing props getter and enabled tools filter.
// Register all Jina AI tools with optional filtering registerJinaTools(server, () => currentProps, enabledTools); return server;