Skip to main content
Glama
fegizii

Semantic Scholar MCP Server

by fegizii

get_paper_batch

Retrieve detailed information for multiple academic papers simultaneously using paper IDs from the Semantic Scholar database.

Instructions

Get information for multiple papers in a single request.

Args:
    paper_ids: Comma-separated list of paper IDs
    fields: Comma-separated list of fields to return

Returns:
    Batch paper information

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
paper_idsYes
fieldsNo

Implementation Reference

  • The primary handler function for the 'get_paper_batch' tool. It is registered as an MCP tool via the @mcp.tool() decorator. Parses comma-separated paper IDs, calls the Semantic Scholar batch API (/paper/batch), processes results, formats each paper using the format_paper helper, and returns a formatted string output.
    @mcp.tool()
    async def get_paper_batch(paper_ids: str, fields: Optional[str] = None) -> str:
        """
        Get information for multiple papers in a single request.
    
        Args:
            paper_ids: Comma-separated list of paper IDs
            fields: Comma-separated list of fields to return
    
        Returns:
            Batch paper information
        """
        id_list = [id.strip() for id in paper_ids.split(",")]
    
        params: Dict[str, Any] = {"ids": id_list}
    
        if fields:
            params["fields"] = fields
        else:
            params["fields"] = "paperId,title,authors,year,venue,citationCount,abstract"
    
        result = await make_api_request("paper/batch", params, method="POST")
    
        if result is None:
            return "Error: Failed to fetch papers"
    
        if "error" in result:
            return f"Error: {result['error']}"
    
        papers = result if isinstance(result, list) else result.get("data", [])
    
        if not papers:
            return "No papers found for the provided IDs."
    
        formatted_papers = []
        for i, paper in enumerate(papers, 1):
            if paper is None:
                formatted_papers.append(f"{i}. Paper not found")
            elif isinstance(paper, dict):
                formatted_papers.append(f"{i}. {format_paper(paper)}")
            else:
                formatted_papers.append(f"{i}. Invalid paper data")
    
        result_text = f"Retrieved {len(papers)} papers:\n\n"
        result_text += "\n\n".join(formatted_papers)
    
        return result_text
  • Helper function used by get_paper_batch (and other tools) to format individual paper data into a concise, readable multi-line string including title, authors, year, venue, citations, and paper ID.
    def format_paper(paper: Dict[str, Any]) -> str:
        """Format a paper for display."""
        title = paper.get("title", "Unknown Title")
        authors = paper.get("authors", [])
        author_names = [author.get("name", "Unknown") for author in authors[:3]]
        author_str = ", ".join(author_names)
        if len(authors) > 3:
            author_str += f" (and {len(authors) - 3} others)"
    
        year = paper.get("year")
        year_str = f" ({year})" if year else ""
    
        venue = paper.get("venue", "")
        venue_str = f" - {venue}" if venue else ""
    
        citation_count = paper.get("citationCount", 0)
    
        paper_id = paper.get("paperId", "")
    
        return f"Title: {title}\nAuthors: {author_str}{year_str}{venue_str}\nCitations: {citation_count}\nPaper ID: {paper_id}"
  • Core utility function called by get_paper_batch to perform the actual API request to Semantic Scholar's /paper/batch endpoint via POST. Handles authentication, timeouts, errors, and rate limiting gracefully.
    async def make_api_request(
        endpoint: str, params: Optional[Dict[str, Any]] = None, method: str = "GET"
    ) -> Optional[Dict[str, Any]]:
        """Make a request to the Semantic Scholar API."""
        url = f"{BASE_URL}/{endpoint.lstrip('/')}"
    
        headers = {
            "Accept": "application/json",
            "User-Agent": f"semantic-scholar-mcp/{USER_AGENT_VERSION}",
        }
    
        if API_KEY:
            headers["x-api-key"] = API_KEY
    
        try:
            async with httpx.AsyncClient(timeout=API_TIMEOUT) as client:
                if method == "GET":
                    response = await client.get(url, headers=headers, params=params)
                elif method == "POST":
                    response = await client.post(url, headers=headers, json=params)
                else:
                    raise ValueError(f"Unsupported HTTP method: {method}")
    
                response.raise_for_status()
                return response.json()
    
        except httpx.HTTPStatusError as e:
            if e.response.status_code == 403:
                if not API_KEY:
                    return {
                        "error": "Rate limit exceeded. The shared public rate limit (1000 req/sec) may be exceeded. Get a free API key from https://www.semanticscholar.org/product/api for dedicated limits."
                    }
                else:
                    return {
                        "error": f"API key may be invalid or rate limit exceeded: {str(e)}"
                    }
            elif e.response.status_code == 429:
                return {
                    "error": "Rate limit exceeded. Please wait a moment and try again, or get an API key for dedicated higher limits."
                }
            else:
                return {"error": f"HTTP error: {str(e)}"}
        except httpx.HTTPError as e:
            return {"error": f"HTTP error: {str(e)}"}
        except Exception as e:
            return {"error": f"Request failed: {str(e)}"}

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/fegizii/SemanticScholarMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server