Skip to main content
Glama
h-lu

Paper Search MCP Server

by h-lu

search_semantic

Search academic papers across all disciplines using Semantic Scholar's database of 200M+ publications, with citation metrics, publication year filters, and open-access PDF links.

Instructions

Search papers on Semantic Scholar - general-purpose academic search engine.

USE THIS TOOL WHEN:
- You want to search across ALL academic disciplines
- You need citation counts and influence metrics
- You want to filter by publication year
- You need open-access PDF links when available

COVERAGE: ALL academic fields - sciences, humanities, medicine, etc.
Indexes 200M+ papers from journals, conferences, and preprints.

WORKFLOW:
1. search_semantic(query) -> get paper_id or DOI
2. download_semantic(paper_id) -> get PDF (if open-access)
3. If no PDF: use download_scihub(doi) for older papers

Args:
    query: Search terms (any topic, any field).
    year: Optional year filter: '2023', '2020-2023', '2020-', '-2019'.
    max_results: Number of results (default: 10).

Returns:
    List of paper dicts with: paper_id, title, authors, abstract,
    published_date, doi, citations, url, pdf_url (if available).

Example:
    search_semantic("climate change impact agriculture", year="2020-", max_results=5)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes
yearNo
max_resultsNo

Implementation Reference

  • Primary handler and registration for the 'search_semantic' tool. Defines input schema via type hints and docstring. Delegates to _search('semantic', ...) using the SemanticSearcher instance.
    @mcp.tool()
    async def search_semantic(
        query: str, year: Optional[str] = None, max_results: int = 10
    ) -> List[Dict]:
        """Search papers on Semantic Scholar - general-purpose academic search engine.
        
        USE THIS TOOL WHEN:
        - You want to search across ALL academic disciplines
        - You need citation counts and influence metrics
        - You want to filter by publication year
        - You need open-access PDF links when available
        
        COVERAGE: ALL academic fields - sciences, humanities, medicine, etc.
        Indexes 200M+ papers from journals, conferences, and preprints.
        
        WORKFLOW:
        1. search_semantic(query) -> get paper_id or DOI
        2. download_semantic(paper_id) -> get PDF (if open-access)
        3. If no PDF: use download_scihub(doi) for older papers
        
        Args:
            query: Search terms (any topic, any field).
            year: Optional year filter: '2023', '2020-2023', '2020-', '-2019'.
            max_results: Number of results (default: 10).
        
        Returns:
            List of paper dicts with: paper_id, title, authors, abstract,
            published_date, doi, citations, url, pdf_url (if available).
        
        Example:
            search_semantic("climate change impact agriculture", year="2020-", max_results=5)
        """
        kwargs = {'year': year} if year else {}
        return await _search('semantic', query, max_results, **kwargs)
  • Generic helper function used by search_semantic (and other tools) to invoke the searcher.search() method and convert results to dicts.
    async def _search(
        searcher_name: str, 
        query: str, 
        max_results: int = 10,
        **kwargs
    ) -> List[Dict]:
        """通用搜索函数"""
        searcher = SEARCHERS.get(searcher_name)
        if not searcher:
            logger.error(f"Unknown searcher: {searcher_name}")
            return []
        
        try:
            papers = searcher.search(query, max_results=max_results, **kwargs)
            return [paper.to_dict() for paper in papers]
        except Exception as e:
            logger.error(f"Search failed for {searcher_name}: {e}")
            return []
  • Global SEARCHERS dictionary that instantiates SemanticSearcher() for the 'semantic' key, used by _search.
    SEARCHERS = {
        'arxiv': ArxivSearcher(),
        'pubmed': PubMedSearcher(),
        'biorxiv': BioRxivSearcher(),
        'medrxiv': MedRxivSearcher(),
        'google_scholar': GoogleScholarSearcher(),
        'iacr': IACRSearcher(),
        'semantic': SemanticSearcher(),
        'crossref': CrossRefSearcher(),
        'repec': RePECSearcher(),
    }
  • Core implementation of semantic search logic in SemanticSearcher.search(): queries Semantic Scholar API, handles rate limiting, parses results into Paper objects.
    def search(
        self, 
        query: str, 
        year: Optional[str] = None, 
        max_results: int = 10
    ) -> List[Paper]:
        """搜索论文
        
        Args:
            query: 搜索关键词
            year: 年份过滤(支持格式:"2019", "2016-2020", "2010-", "-2015")
            max_results: 最大返回数量
            
        Returns:
            List[Paper]: 论文列表
        """
        params = {
            "query": query,
            "limit": min(max_results, 100),  # API 限制
            "fields": ",".join(self.DEFAULT_FIELDS),
        }
        
        if year:
            params["year"] = year
        
        response = self._make_request("paper/search", params)
        if not response:
            return []
        
        try:
            data = response.json()
            results = data.get('data', [])
        except Exception as e:
            logger.error(f"Failed to parse response: {e}")
            return []
        
        papers = []
        for item in results[:max_results]:
            paper = self._parse_paper(item)
            if paper:
                papers.append(paper)
        
        logger.info(f"Found {len(papers)} papers for query: {query}")
        return papers

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/h-lu/paper-search-mcp'

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