Skip to main content
Glama
smaniches

Semantic Scholar MCP Server

by smaniches

semantic_scholar_recommendations

Find relevant academic papers by providing a seed paper ID. This tool analyzes research connections to suggest related publications for literature review and discovery.

Instructions

Get paper recommendations based on a seed paper.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
paramsYes

Implementation Reference

  • Handler function implementing the semantic_scholar_recommendations tool. Calls Semantic Scholar's recommendations API using the provided paper_id as seed, retrieves recommended papers, and formats output in Markdown or JSON.
    @mcp.tool(name="semantic_scholar_recommendations")
    async def get_recommendations(params: PaperRecommendationsInput) -> str:
        """Get paper recommendations based on a seed paper."""
        logger.info(f"Recommendations for: {params.paper_id}")
    
        async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client:
            resp = await client.post(
                f"https://api.semanticscholar.org/recommendations/v1/papers/forpaper/{params.paper_id}",
                params={"fields": ",".join(PAPER_FIELDS), "limit": params.limit},
                json={"positivePaperIds": [params.paper_id]},
                headers=_get_headers()
            )
            resp.raise_for_status()
            data = resp.json()
        
        papers = data.get("recommendedPapers", [])
        
        if params.response_format == ResponseFormat.JSON:
            return json.dumps({"seed": params.paper_id, "recommendations": papers}, indent=2)
        
        lines = [f"## Recommendations", f"**Seed:** {params.paper_id}", f"**Found:** {len(papers)}", ""]
        for paper in papers:
            lines.append(_format_paper_markdown(paper))
        return "\n".join(lines)
  • Pydantic input schema defining parameters for the semantic_scholar_recommendations tool: seed paper_id, number of recommendations, and output format.
    class PaperRecommendationsInput(BaseModel):
        model_config = ConfigDict(str_strip_whitespace=True, extra="forbid")
        paper_id: str = Field(..., description="Seed paper ID for recommendations", min_length=1)
        limit: int = Field(default=10, description="Max recommendations", ge=1, le=100)
        response_format: ResponseFormat = Field(default=ResponseFormat.MARKDOWN, description="Output format")
  • Helper function to format individual paper data into Markdown, used in the tool's output rendering.
    def _format_paper_markdown(paper: Dict[str, Any]) -> str:
        lines = []
        title = paper.get("title", "Unknown Title")
        year = paper.get("year", "N/A")
        lines.append(f"### {title} ({year})")
        
        authors = paper.get("authors", [])
        if authors:
            names = [a.get("name", "?") for a in authors[:5]]
            if len(authors) > 5:
                names.append(f"... +{len(authors)-5} more")
            lines.append(f"**Authors:** {', '.join(names)}")
        
        venue = paper.get("venue") or (paper.get("publicationVenue") or {}).get("name")
        if venue:
            lines.append(f"**Venue:** {venue}")
        
        citations = paper.get("citationCount", 0)
        influential = paper.get("influentialCitationCount", 0)
        lines.append(f"**Citations:** {citations} ({influential} influential)")
        
        pdf_info = paper.get("openAccessPdf") or {}
        if pdf_info.get("url"):
            lines.append(f"**Open Access:** [PDF]({pdf_info['url']})")
    
        fields = paper.get("fieldsOfStudy") or []
        if fields:
            lines.append(f"**Fields:** {', '.join(fields[:5])}")
        
        tldr = paper.get("tldr") or {}
        if tldr.get("text"):
            lines.append(f"**TL;DR:** {tldr['text']}")
        
        abstract = paper.get("abstract")
        if abstract:
            lines.append(f"**Abstract:** {abstract[:500]}..." if len(abstract) > 500 else f"**Abstract:** {abstract}")
        
        ext_ids = paper.get("externalIds") or {}
        ids = []
        if ext_ids.get("DOI"): ids.append(f"DOI: {ext_ids['DOI']}")
        if ext_ids.get("ArXiv"): ids.append(f"ArXiv: {ext_ids['ArXiv']}")
        if ext_ids.get("PubMed"): ids.append(f"PMID: {ext_ids['PubMed']}")
        if ids:
            lines.append(f"**IDs:** {', '.join(ids)}")
        
        if paper.get("url"):
            lines.append(f"**Link:** [{paper.get('paperId')}]({paper['url']})")
        
        lines.append("")
        return "\n".join(lines)
  • Helper function providing HTTP headers including optional API key for Semantic Scholar requests.
    def _get_headers() -> Dict[str, str]:
        headers = {"Accept": "application/json", "Content-Type": "application/json"}
        if SEMANTIC_SCHOLAR_API_KEY:
            headers["x-api-key"] = SEMANTIC_SCHOLAR_API_KEY
        return headers

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/smaniches/semantic-scholar-mcp'

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