parallel_search_arxiv
Conduct simultaneous arXiv searches to explore diverse academic angles and research methodologies efficiently. Ideal for comprehensive research coverage across multiple queries.
Instructions
Run multiple arXiv searches in parallel for comprehensive research coverage and diverse academic angles. For best results, provide multiple search queries that explore different research angles and methodologies. You can use expand_query to help generate diverse queries, or create them yourself. 💡 Use this when you need to explore multiple research directions simultaneously for efficiency.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| searches | Yes | Array of arXiv search configurations to execute in parallel (maximum 5 searches for optimal performance) | |
| timeout | No | Timeout in milliseconds for all searches |
Input Schema (JSON Schema)
Implementation Reference
- src/tools/jina-tools.ts:459-486 (handler)Handler function that implements the core logic for the 'parallel_search_arxiv' tool: authenticates, deduplicates search queries, wraps single arXiv search, executes parallel searches, formats results.async ({ searches, timeout }: { searches: SearchArxivArgs[]; timeout: number }) => { try { const props = getProps(); const tokenError = checkBearerToken(props.bearerToken); if (tokenError) { return tokenError; } const uniqueSearches = searches.filter((search, index, self) => index === self.findIndex(s => s.query === search.query) ); // Use the common arXiv search function const arxivSearchFunction = async (searchArgs: SearchArxivArgs) => { return executeArxivSearch(searchArgs, props.bearerToken); }; // Execute parallel searches using utility const results = await executeParallelSearches(uniqueSearches, arxivSearchFunction, { timeout }); return { content: formatParallelSearchResultsToContentItems(results), }; } catch (error) { return createErrorResponse(`Error: ${error instanceof Error ? error.message : String(error)}`); } },
- src/tools/jina-tools.ts:451-457 (schema)Input schema using Zod for validating the tool parameters: array of up to 5 search configs and optional timeout.{ searches: z.array(z.object({ query: z.string().describe("Academic search terms, author names, or research topics"), num: z.number().default(30).describe("Maximum number of academic papers to return, between 1-100"), tbs: z.string().optional().describe("Time-based search parameter, e.g., 'qdr:h' for past hour") })).max(5).describe("Array of arXiv search configurations to execute in parallel (maximum 5 searches for optimal performance)"), timeout: z.number().default(30000).describe("Timeout in milliseconds for all searches")
- src/tools/jina-tools.ts:448-487 (registration)Registers the 'parallel_search_arxiv' tool on the MCP server within the registerJinaTools function.server.tool( "parallel_search_arxiv", "Run multiple arXiv searches in parallel for comprehensive research coverage and diverse academic angles. For best results, provide multiple search queries that explore different research angles and methodologies. You can use expand_query to help generate diverse queries, or create them yourself. 💡 Use this when you need to explore multiple research directions simultaneously for efficiency.", { searches: z.array(z.object({ query: z.string().describe("Academic search terms, author names, or research topics"), num: z.number().default(30).describe("Maximum number of academic papers to return, between 1-100"), tbs: z.string().optional().describe("Time-based search parameter, e.g., 'qdr:h' for past hour") })).max(5).describe("Array of arXiv search configurations to execute in parallel (maximum 5 searches for optimal performance)"), timeout: z.number().default(30000).describe("Timeout in milliseconds for all searches") }, async ({ searches, timeout }: { searches: SearchArxivArgs[]; timeout: number }) => { try { const props = getProps(); const tokenError = checkBearerToken(props.bearerToken); if (tokenError) { return tokenError; } const uniqueSearches = searches.filter((search, index, self) => index === self.findIndex(s => s.query === search.query) ); // Use the common arXiv search function const arxivSearchFunction = async (searchArgs: SearchArxivArgs) => { return executeArxivSearch(searchArgs, props.bearerToken); }; // Execute parallel searches using utility const results = await executeParallelSearches(uniqueSearches, arxivSearchFunction, { timeout }); return { content: formatParallelSearchResultsToContentItems(results), }; } catch (error) { return createErrorResponse(`Error: ${error instanceof Error ? error.message : String(error)}`); } }, );
- src/utils/search.ts:165-197 (helper)Helper function that executes multiple searches in parallel with timeout handling, used by the tool handler.export async function executeParallelSearches<T>( searches: T[], searchFunction: (searchArgs: T) => Promise<SearchResultOrError>, options: ParallelSearchOptions = {} ): Promise<ParallelSearchResult[]> { const { timeout = 30000 } = options; // Execute all searches in parallel const searchPromises = searches.map(async (searchArgs) => { try { return await searchFunction(searchArgs); } catch (error) { return { error: `Search failed: ${error instanceof Error ? error.message : String(error)}` }; } }); // Wait for all searches with timeout const results = await Promise.allSettled(searchPromises); const timeoutPromise = new Promise(resolve => setTimeout(() => resolve('timeout'), timeout)); const completedResults = await Promise.race([ Promise.all(results.map(result => result.status === 'fulfilled' ? result.value : { error: 'Promise rejected' } )), timeoutPromise ]); if (completedResults === 'timeout') { throw new Error(`Parallel search timed out after ${timeout}ms`); } return completedResults as ParallelSearchResult[]; }
- src/utils/search.ts:91-120 (helper)Helper function that performs a single arXiv search via Jina API, wrapped and used in parallel by the tool.export async function executeArxivSearch( searchArgs: SearchArxivArgs, 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, domain: 'arxiv', num: searchArgs.num || 30, ...(searchArgs.tbs && { tbs: searchArgs.tbs }) }), }); if (!response.ok) { return { error: `arXiv 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: `arXiv search failed for query "${searchArgs.query}": ${error instanceof Error ? error.message : String(error)}` }; } }