search_papers
Search for academic papers using a specific query across multiple sources. Retrieve metadata, abstracts, and full-text content, with results limited to a specified number for structured, real-time access.
Instructions
Search for papers across multiple sources.
args:
query: the search query
limit: the maximum number of results to return (default 10)
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes |
Implementation Reference
- server.py:88-133 (handler)The core handler function for the 'search_papers' tool. Decorated with @mcp.tool() which handles both implementation and registration. Searches Semantic Scholar and Crossref APIs for papers matching the query.@mcp.tool() async def search_papers(query: str, limit: int = 10) -> str: """Search for papers across multiple sources. args: query: the search query limit: the maximum number of results to return (default 10) """ if query == "": return "Please provide a search query." # Truncate long queries MAX_QUERY_LENGTH = 300 if len(query) > MAX_QUERY_LENGTH: original_length = len(query) query = query[:MAX_QUERY_LENGTH] + "..." try: # Search Semantic Scholar semantic_url = f"{SEMANTIC_SCHOLAR_API}/paper/search?query={query}&limit={limit}" semantic_data = await make_api_request(semantic_url) # Search Crossref crossref_url = f"{CROSSREF_API}?query={query}&rows={limit}" crossref_data = await make_api_request(crossref_url) results = [] if semantic_data and 'papers' in semantic_data: results.append("=== Semantic Scholar Results ===") for paper in semantic_data['papers']: results.append(format_paper_data(paper, "semantic_scholar")) if crossref_data and 'items' in crossref_data.get('message', {}): results.append("\n=== Crossref Results ===") for paper in crossref_data['message']['items']: results.append(format_paper_data(paper, "crossref")) if not results: return "No results found or error occurred while fetching papers." return "\n".join(results) except: return "Error searching papers."
- server.py:38-86 (helper)Helper function to format paper data from Semantic Scholar or Crossref into a consistent readable string format. Called within search_papers for each result.def format_paper_data(data: dict, source: str) -> str: """Format paper data from different sources into a consistent string format.""" if not data: return "No paper data available" try: if source == "semantic_scholar": title = unicodedata.normalize('NFKD', str(data.get('title', 'No title available'))) authors = ', '.join([author.get('name', 'Unknown Author') for author in data.get('authors', [])]) year = data.get('year') or 'Year unknown' external_ids = data.get('externalIds', {}) or {} doi = external_ids.get('DOI', 'No DOI available') venue = data.get('venue') or 'Venue unknown' abstract = data.get('abstract') or 'No abstract available' tldr = (data.get('tldr') or {}).get('text', '') is_open = "Yes" if data.get('isOpenAccess') else "No" pdf_data = data.get('openAccessPdf', {}) or {} pdf_url = pdf_data.get('url', 'Not available') elif source == "crossref": title = (data.get('title') or ['No title available'])[0] authors = ', '.join([ f"{author.get('given', '')} {author.get('family', '')}".strip() or 'Unknown Author' for author in data.get('author', []) ]) year = (data.get('published-print', {}).get('date-parts', [['']])[0][0]) or 'Year unknown' doi = data.get('DOI') or 'No DOI available' result = [ f"Title: {title}", f"Authors: {authors}", f"Year: {year}", f"DOI: {doi}" ] if source == "semantic_scholar": result.extend([ f"Venue: {venue}", f"Open Access: {is_open}", f"PDF URL: {pdf_url}", f"Abstract: {abstract}" ]) if tldr: result.append(f"TL;DR: {tldr}") return "\n".join(result) + "\t\t\n" except Exception as e: return f"Error formatting paper data: {str(e)}"
- server.py:26-37 (helper)Async helper function to make HTTP GET requests to external APIs with error handling and timeout. Used by search_papers to query Semantic Scholar and Crossref.async def make_api_request(url: str, headers: dict = None, params: dict = None) -> dict[str, Any] | None: """Make a request to the API with proper error handling.""" if headers is None: headers = { "User-Agent": USER_AGENT } async with httpx.AsyncClient() as client: try: response = await client.get(url, headers=headers, params=params, timeout=30.0) response.raise_for_status() return response.json() except Exception as e: return None
- server.py:90-95 (schema)Input schema defined in the tool's docstring, specifying parameters query (str) and limit (int=10)."""Search for papers across multiple sources. args: query: the search query limit: the maximum number of results to return (default 10) """