Skip to main content
Glama
afrise

Academic Paper Search MCP Server

by afrise

fetch_paper_details

Retrieve comprehensive details for a specific academic paper, including metadata and abstracts, by providing its unique identifier and preferred database source (Crossref or Semantic Scholar).

Instructions

Get detailed information about a specific paper.

Args:
    paper_id: Paper identifier (DOI for Crossref, paper ID for Semantic Scholar)
    source: Source database ("semantic_scholar" or "crossref")

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
paper_idYes
sourceNosemantic_scholar

Implementation Reference

  • The main handler function for the 'fetch_paper_details' tool. It constructs the appropriate API URL based on the source, fetches the data using make_api_request, handles Crossref response structure, and formats the output using format_paper_data. Registered via @mcp.tool() decorator.
    @mcp.tool()
    async def fetch_paper_details(paper_id: str, source: str = "semantic_scholar") -> str:
        """Get detailed information about a specific paper.
    
        Args:
            paper_id: Paper identifier (DOI for Crossref, paper ID for Semantic Scholar)
            source: Source database ("semantic_scholar" or "crossref")
        """
        if source == "semantic_scholar":
            url = f"{SEMANTIC_SCHOLAR_API}/paper/{paper_id}"
        elif source == "crossref":
            url = f"{CROSSREF_API}/{paper_id}"
        else:
            return "Unsupported source. Please use 'semantic_scholar' or 'crossref'."
    
        data = await make_api_request(url)
        
        if not data:
            return f"Unable to fetch paper details from {source}."
    
        if source == "crossref":
            data = data.get('message', {})
    
        return format_paper_data(data, source)
  • Helper function to make HTTP requests to the Semantic Scholar or Crossref APIs with error handling and timeout.
    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
  • Helper function that formats the raw API response data from either source into a consistent human-readable string format, handling fields like title, authors, year, DOI, and source-specific fields.
    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:134-134 (registration)
    The @mcp.tool() decorator registers the fetch_paper_details function as an MCP tool.
    @mcp.tool()

Tool Definition Quality

Score is being calculated. Check back soon.

Install Server

Other Tools

Related Tools

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/afrise/academic-search-mcp-server'

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