research-mcp
Research MCP
Read-only MCP server for academic research. Lets an LLM agent search papers, inspect metadata, follow citation graphs, generate BibTeX, and read full texts of open-access PDFs — all via FastMCP tools.
Requirements
Python 3.13+
Internet access to the public APIs (no API key required)
How it works
API | Role |
Semantic Scholar | Primary search, metadata, TLDRs, citation graph. Tried first. |
OpenAlex | Automatic fallback when Semantic Scholar is rate-limited, plus open-access PDF resolution. |
arXiv | Dedicated preprint search ( |
DBLP | Venue proceedings surveys ( |
Crossref | BibTeX generation ( |
PyMuPDF | PDF text extraction. |
Semantic Scholar is rate-limited when used without a key, so every request retries with exponential backoff (honoring Retry-After) before falling back to OpenAlex. Results always tell the agent which source was used. The arXiv API enforces a ~3 s spacing rule, which the server honors; DBLP resets connections on rapid sequential requests, so venue-stream pages are fetched with a 3 s politeness delay too.
Caching
All brittle API responses, search results, venue proceedings corpora, and PDFs are cached on disk under ~/.cache/research-mcp/ (api/ for JSON responses, pdf/ for downloaded PDFs):
Fresh cache hits are served instantly — repeat queries don't touch the network.
Venue corpora (assembled from DBLP pages) are cached as a whole, so re-surveys of a conference program are instant even if DBLP drops a page.
Stale fallback: if an API is down or rate-limiting, the last cached response is served anyway, so the agent still gets an answer.
Cache TTLs: 7 days for arXiv and BibTeX (stable data), 24 h for search/metadata and DBLP. Override the location with
RESEARCH_MCP_CACHE_DIR.
Configuration
Register the server in your coding agent's MCP configuration. For example, in Opencode's opencode.json:
{
"mcp": {
"research-mcp": {
"command": [
"uvx",
"--from",
"git+https://github.com/404Simon/research-mcp",
"research-mcp"
],
"enabled": true,
"type": "local"
}
}
}Environment variables (all optional)
Variable | Purpose |
| Set for guaranteed 1 RPS and higher reliability (falls back to OpenAlex otherwise). |
| Where API responses and PDFs are cached. Default: |
Tools
search_papers
Search academic papers by keyword with optional venue and year filters. Returns structured results with title, year, venue, authors, DOI, abstract, citation count, and an open-access PDF link when available.
Argument | Type | Description |
|
| Search terms |
|
| Filter by venue, e.g. |
|
| Earliest publication year |
|
| Latest publication year |
|
| Max results (default 20) |
|
|
|
source="arxiv" searches the arXiv preprint API and is the recommended way to find specific recent papers by exact name, e.g. query='ti:"carbon intensity" AND abs:forecast' (arXiv field syntax is passed through verbatim). All results are cached, so repeat searches are instant.
venue_proceedings
Survey a venue's proceedings (what actually gets published there). Use this to check whether a paper idea fits a conference like ACM e-Energy.
Argument | Type | Description |
|
| Venue name (e.g. |
|
| Only papers from one year (e.g. |
|
| Topic filter; papers are ranked by title-keyword overlap |
|
| Max results (default 20) |
The full venue corpus is fetched from DBLP (paginated past its 100-hit cap), ranked client-side, and cached as a whole — re-surveys are instant.
{"results": [
{"title": "Reinforcement Learning Approach for Optimal Distributed Energy Management in a Microgrid",
"year": 2018, "venue": "IEEE Transactions on Power Systems",
"authors": ["Elham Foruzan", "Leen-Kiat Soh", "S. Asgarpoor"],
"doi": "10.1109/tpwrs.2018.2823641",
"abstract": "In this paper, a multiagent-based model is used ...",
"citation_count": 297, "open_access_pdf": null,
"source": "openalex"}],
"note": "(Semantic Scholar unavailable — used OpenAlex instead: RequestFailed)",
"count": 1}paper_details
Full metadata for a paper. Accepts a DOI (e.g. 10.1109/tpwrs.2018.2823641), an arXiv ID (e.g. 2408.03506, arXiv:2408.03506, or an arxiv.org/abs/... URL), or an OpenAlex ID.
Argument | Type | Description |
|
| DOI, arXiv ID, or OpenAlex ID |
Returns title, authors, venue, year, abstract, TLDR, citation count, DOI, and open-access PDF:
get_citation_graph
Follow a paper's citations forward or backward for snowball searching.
Argument | Type | Description |
|
| DOI, OpenAlex ID ( |
|
|
|
|
| Max results (default 20) |
get_bibtex
Generate a BibTeX entry for a DOI. Uses Crossref's native transform; falls back to local generation from OpenAlex metadata (handles arXiv DOIs that Crossref doesn't know).
Argument | Type | Description |
|
| DOI |
@article{Foruzan_2018, title={Reinforcement Learning Approach for Optimal Distributed Energy Management in a Microgrid}, volume={33}, ..., author={Foruzan, Elham and Soh, Leen-Kiat and Asgarpoor, Sohrab}, year={2018} }read_paper_full_text
Download an open-access PDF and extract its text with PyMuPDF. Pass a DOI, an arXiv ID (e.g. 2408.03506), or a direct PDF URL. PDFs are cached locally (~/.cache/research-mcp/pdf/).
Argument | Type | Description |
|
| DOI, arXiv ID, or |
|
| Truncate returned text (default 50000) |
|
| Cache the PDF locally (default |
Returns the extracted text, page count, source URL, and cached path. If no open-access copy is found, the agent gets a clear message telling it to search for an OA copy or pass a PDF URL directly.
File structure
src/
main.py # FastMCP server, tool definitions, fallback orchestration
client.py # HTTP client with retry/backoff (429/5xx, Retry-After)
cache.py # Disk cache (~/.cache/research-mcp/) with stale fallback
semanticscholar.py # Semantic Scholar: search, details, citations (optional API key)
openalex.py # OpenAlex: search, details, citation graph, OA-PDF resolution
arxiv.py # arXiv API: search, ID lookups (3 s politeness, 7-day cache)
dblp.py # DBLP: venue proceedings + venue-scoped search (paged corpus cache)
crossref.py # Crossref: BibTeX transform + local fallback generator
pdf.py # PDF download/validation/caching + PyMuPDF text extractionNo API key required. Run uv sync && uv run research-mcp to start the server over stdio.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/404Simon/research-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server