Search Papers by Keyword
search_papers_by_keywordFind academic papers by entering keywords, with options to sort by publication year or citation count for targeted research discovery.
Instructions
Search academic papers by keyword
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| keyword | Yes | Search keyword | |
| page | No | Page number, starting from 0 | |
| size | No | Number of papers per page, maximum 10 | |
| order | No | Sort order: year (by publication year) or n_citation (by citation count) |
Implementation Reference
- src/index.ts:35-71 (registration)Registration of the MCP tool 'search_papers_by_keyword' including schema and inline handler that delegates to AminerClient
server.registerTool( "search_papers_by_keyword", { title: "Search Papers by Keyword", description: "Search academic papers by keyword", inputSchema: { keyword: z.string().describe("Search keyword"), page: z.number().min(0).default(0).describe("Page number, starting from 0"), size: z.number().min(1).max(10).default(10).describe("Number of papers per page, maximum 10"), order: z.enum(["year", "n_citation"]).optional().describe("Sort order: year (by publication year) or n_citation (by citation count)") } }, async ({ keyword, page, size, order }) => { try { const result = await aminerClient.searchByKeyword(keyword, page, size, order); const formattedResult = aminerClient.formatSearchResults(result); return { content: [{ type: "text", text: JSON.stringify(formattedResult, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: JSON.stringify({ error: "Search failed", message: error instanceof Error ? error.message : 'Unknown error' }, null, 2) }], isError: true }; } } ); - src/aminer-client.ts:27-94 (handler)Core handler logic for searching papers via AMiner API in AminerClient.searchPapers, called by searchByKeyword
async searchPapers(params: SearchParams): Promise<SearchResult> { // Validate required parameters if (!params.keyword && !params.venue && !params.author) { throw new Error('At least one of keyword, venue, or author must be provided'); } if (params.size > 10) { throw new Error('Size parameter cannot exceed 10'); } // Build query parameters const searchParams = new URLSearchParams(); if (params.keyword) searchParams.append('keyword', params.keyword); if (params.venue) searchParams.append('venue', params.venue); if (params.author) searchParams.append('author', params.author); searchParams.append('page', params.page.toString()); searchParams.append('size', params.size.toString()); if (params.order) searchParams.append('order', params.order); const url = `${this.config.baseUrl}?${searchParams.toString()}`; try { const response = await fetch(url, { method: 'GET', headers: { 'Authorization': this.config.apiKey, 'Content-Type': 'application/json', }, }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json() as AminerSearchResponse; // Add detailed response data check if (!data) { throw new Error('API returned empty response'); } if (!data.success) { throw new Error(`API Error (${data.code}): ${data.msg}`); } // Check the completeness of the response data if (typeof data.total !== 'number') { console.warn('API response missing or invalid total field, defaulting to 0'); } // Ensure data.data is not null, if it is null, use an empty array const papers = data.data || []; const total = data.total || 0; return { papers, total, page: params.page, size: params.size, hasMore: (params.page + 1) * params.size < total, }; } catch (error) { if (error instanceof Error) { throw new Error(`Failed to search papers: ${error.message}`); } throw new Error('Unknown error occurred while searching papers'); } } - src/aminer-client.ts:99-101 (helper)Wrapper method searchByKeyword that invokes the core searchPapers with keyword parameter
async searchByKeyword(keyword: string, page = 0, size = 10, order?: 'year' | 'n_citation'): Promise<SearchResult> { return this.searchPapers({ keyword, page, size, order }); } - src/aminer-client.ts:165-198 (helper)Helper function to format raw search results into structured JSON output used by the tool handler
formatSearchResults(result: SearchResult): SearchResultFormatted { const { papers, total, page, size, hasMore } = result; // Ensure papers is not null or undefined const formattedPapers = papers && Array.isArray(papers) ? papers.map((paper, index) => { const formattedPaper = this.formatPaper(paper); // Only process successfully formatted papers, skip error results if ('error' in formattedPaper) { return null; } return { index: page * size + index + 1, ...formattedPaper }; }).filter((paper): paper is NonNullable<typeof paper> => paper !== null) : []; return { summary: { total, page: page + 1, size, hasMore, currentPageResults: formattedPapers.length }, papers: formattedPapers, pagination: { currentPage: page + 1, nextPage: hasMore ? page + 2 : null, previousPage: page > 0 ? page : null } }; } - src/index.ts:40-44 (schema)Zod input schema definition for the search_papers_by_keyword tool parameters
inputSchema: { keyword: z.string().describe("Search keyword"), page: z.number().min(0).default(0).describe("Page number, starting from 0"), size: z.number().min(1).max(10).default(10).describe("Number of papers per page, maximum 10"), order: z.enum(["year", "n_citation"]).optional().describe("Sort order: year (by publication year) or n_citation (by citation count)")