search
Search the web to retrieve clean, LLM-friendly content using Jina.ai Reader, returning top results with URLs and processed text for efficient information extraction.
Instructions
Search the web and get clean, LLM-friendly content using Jina.ai Reader. Returns top 5 results with URLs and clean content.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query | |
| format | No | Response format (json or text) | text |
| no_cache | No | Bypass cache for fresh results | |
| token_budget | No | Maximum number of tokens for this request | |
| browser_locale | No | Browser locale for rendering content | |
| stream | No | Enable stream mode for large pages | |
| gather_links | No | Gather all links at the end of the response | |
| gather_images | No | Gather all images at the end of the response | |
| image_caption | No | Caption images in the content | |
| enable_iframe | No | Extract content from iframes | |
| enable_shadow_dom | No | Extract content from shadow DOM | |
| resolve_redirects | No | Follow redirect chains to final URL |
Implementation Reference
- src/index.ts:127-249 (handler)Handler for CallToolRequestSchema that checks if the tool is 'search' and executes the Jina.ai search API call with parameters, handling response and errors.this.server.setRequestHandler( CallToolRequestSchema, async (request) => { if (request.params.name !== 'search') { throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`, ); } const arguments_record = request.params.arguments as { query: string; format?: 'json' | 'text'; no_cache?: boolean; token_budget?: number; browser_locale?: string; stream?: boolean; gather_links?: boolean; gather_images?: boolean; image_caption?: boolean; enable_iframe?: boolean; enable_shadow_dom?: boolean; resolve_redirects?: boolean; }; const { query, format = 'text', no_cache = false, token_budget, browser_locale, stream = false, gather_links = false, gather_images = false, image_caption = false, enable_iframe = false, enable_shadow_dom = false, resolve_redirects = true, } = arguments_record; const search_url = `https://s.jina.ai/${encodeURIComponent( query, )}`; const headers: Record<string, string> = { Authorization: `Bearer ${API_KEY}`, Accept: format === 'json' ? 'application/json' : 'text/plain', }; if (no_cache) { headers['X-Bypass-Cache'] = 'true'; } if (token_budget) { headers['X-Token-Budget'] = token_budget.toString(); } if (browser_locale) { headers['X-Browser-Locale'] = browser_locale; } if (stream) { headers['X-Stream-Mode'] = 'true'; } if (gather_links) { headers['X-Gather-Links'] = 'true'; } if (gather_images) { headers['X-Gather-Images'] = 'true'; } if (image_caption) { headers['X-Image-Caption'] = 'true'; } if (enable_iframe) { headers['X-Enable-Iframe'] = 'true'; } if (enable_shadow_dom) { headers['X-Enable-Shadow-DOM'] = 'true'; } if (!resolve_redirects) { headers['X-No-Redirect'] = 'true'; } try { const response = await fetch(search_url, { method: 'POST', headers, }); if (!response.ok) { const error_text = await response.text(); throw new Error(error_text); } const result = format === 'json' ? await response.json() : await response.text(); return { content: [ { type: 'text', text: format === 'json' ? JSON.stringify(result, null, 2) : result, }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Jina.ai API error: ${ error instanceof Error ? error.message : String(error) }`, }, ], isError: true, }; } }, );
- src/index.ts:27-96 (schema)Schema definition for the 'search' tool, specifying name, description, and detailed input schema with parameters such as query (required), format, token_budget, etc.const search_tool_schema = { name: 'search', description: 'Search the web and get clean, LLM-friendly content using Jina.ai Reader. Returns top 5 results with URLs and clean content.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query', }, format: { type: 'string', description: 'Response format (json or text)', enum: ['json', 'text'], default: 'text', }, no_cache: { type: 'boolean', description: 'Bypass cache for fresh results', default: false, }, token_budget: { type: 'number', description: 'Maximum number of tokens for this request', minimum: 1, }, browser_locale: { type: 'string', description: 'Browser locale for rendering content', }, stream: { type: 'boolean', description: 'Enable stream mode for large pages', default: false, }, gather_links: { type: 'boolean', description: 'Gather all links at the end of the response', default: false, }, gather_images: { type: 'boolean', description: 'Gather all images at the end of the response', default: false, }, image_caption: { type: 'boolean', description: 'Caption images in the content', default: false, }, enable_iframe: { type: 'boolean', description: 'Extract content from iframes', default: false, }, enable_shadow_dom: { type: 'boolean', description: 'Extract content from shadow DOM', default: false, }, resolve_redirects: { type: 'boolean', description: 'Follow redirect chains to final URL', default: true, }, }, required: ['query'], }, };
- src/index.ts:120-125 (registration)Registration of the 'search' tool by returning it in the ListToolsRequest handler.this.server.setRequestHandler( ListToolsRequestSchema, async () => ({ tools: [search_tool_schema], }), );