arxiv-mcp-server
Provides tools to search arXiv papers, fetch metadata, read full-text content, and list category taxonomy, enabling AI agents to access and analyze academic papers from arXiv.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@arxiv-mcp-serversearch for the latest papers on large language models"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Hosted Server: https://arxiv.caseyjhand.com/mcp
Overview
arXiv papers, metadata, and full text from the arXiv API and its OAI-PMH metadata feed. Search papers by query, category, and submission date; fetch structured metadata by ID; and read full paper text with automatic fallback across HTML and PDF renders. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
Tools
Tool | Description |
| Search arXiv papers by query with field prefixes, category, and date filters |
| Fetch metadata for one or more papers by arXiv ID |
| Read full paper text via HTML, ar5iv, or PDF-extracted fallback |
| List the arXiv category taxonomy, optionally filtered by group |
Resources
Resource | Description |
| Paper metadata by arXiv ID |
| Full arXiv category taxonomy |
Related MCP server: arxiv-reader-mcp
Capability reference
arxiv_search tool
Field prefixes
ti:,au:,abs:,cat:,co:(comment),jr:(journal ref),all:(all fields); booleanAND/OR/ANDNOT; query capped at 1000 characterscategoryaccepts a leaf code (cs.CL) or a whole archive (astro-ph,cs,math) — a bare archive matches its subject classes plus pre-subdivision legacy paperssort_by(relevance/submitted/updated) andsort_order(ascending/descending); up to 50 results per call (max_results)submitted_from/submitted_tobound submission date inclusively (UTCYYYY-MM-DD); consecutive windows cover matches with no gap — de-duplicate by ID at the seam — the way to reach results past the 10,000startpagination ceilingResponse enrichment echoes the effective query (every filter folded in, replayable), total match count, and page offset; empty or overshot pages carry recovery guidance instead of an error
arxiv_get_metadata tool
Up to 10 IDs per call (single string or array); versioned (
2401.12345v2), unversioned, and legacy (hep-th/9901001) formats acceptedPartial-batch results: found papers plus a typed
not_found[](not_in_arxiv/version_not_in_mirror) for the rest — never fails the whole batch for one bad IDFails
no_matchonly when every ID misses; failsversion_unavailablewhen every miss is a mirror-only version gap reachable on the live API
arxiv_read_paper tool
Tries native arXiv HTML first, then ar5iv, then text extracted from the PDF — the
sourcefield reports which one answeredStrips HTML head/boilerplate and collapses MathML to dollar-delimited LaTeX (
$…$inline,$$…$$block) so the character budget targets paper contentReturns raw HTML for HTML sources — the LLM interprets content directly; PDF-extracted bodies are plain text, so prose is reliable but math, tables, and heading structure flatten
max_charactersdefaults to 100,000; passnullfor the whole paper in one call. Raw HTML can run 500KB-3MB+ for math-heavy papers — page withstartinsteadTyped failures:
content_unavailable(no render, no PDF),pdf_extraction_failed(PDF has no text layer),version_unavailable(version-pinned ID needs the live API)
arxiv_list_categories tool
~155 categories across 8 top-level groups (
cs,econ,eess,math,physics,q-bio,q-fin,stat)Optional
groupfilter to narrow resultsStatic data — always succeeds
arxiv://paper/{paperId} resource
paperIdaccepts versioned, unversioned, and legacy formats — same resolution asarxiv_get_metadataPercent-encode a legacy ID's slash:
arxiv://paper/hep-th%2F9901001Typed errors:
empty_id,no_match,version_unavailable
arxiv://categories resource
Full arXiv category taxonomy as
{ categories: [...] }, one flat array withcode/name/groupper entryCacheable for 24h (
cacheHint.ttlMs: 86400000), public scopeNo parameters
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
arXiv-specific:
Read-only, no authentication required — arXiv API is free, metadata is CC0
Sequential request queue enforcing arXiv's 3-second crawl delay; rate-limit responses (429, or 200 OK with a
Rate exceeded.body) fail fast with a server-computed cooldown rather than retrying blindlyContent fallback chain:
arxiv.org/html→ ar5iv → PDF text extraction, in that order — thesourcefield reports which one answeredFull arXiv category taxonomy embedded as static data
Optional local OAI-PMH metadata mirror (SQLite + FTS5) — opt-in, eliminates rate-limit exposure for
arxiv_searchandarxiv_get_metadata. See Optional: local mirror
Agent-friendly output:
Provenance on every read —
arxiv_read_paper'ssourcefield names which upstream artifact answered;arxiv_searchechoes the effective query so results are reproducibleGraceful partial failure —
arxiv_get_metadatareturns found papers alongside a typednot_found[]reason per miss instead of failing the whole batchDiscriminated output contracts — typed
sourceandnot_found[].reasonenums let callers branch on data, not string parsing
Getting started
Public Hosted Instance
A public instance is available at https://arxiv.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"arxiv-mcp-server": {
"type": "streamable-http",
"url": "https://arxiv.caseyjhand.com/mcp"
}
}
}Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"arxiv-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/arxiv-mcp-server@latest"]
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"arxiv-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/arxiv-mcp-server@latest"]
}
}
}Or with Docker:
{
"mcpServers": {
"arxiv-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/arxiv-mcp-server:latest"]
}
}
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcpPrerequisites
Bun v1.4.0 or higher (or Node.js v24+).
Installation
Clone the repository:
git clone https://github.com/cyanheads/arxiv-mcp-server.gitNavigate into the directory:
cd arxiv-mcp-serverInstall dependencies:
bun installConfiguration
All configuration is optional — the server works out of the box with sensible defaults.
Variable | Description | Default |
| arXiv API base URL. |
|
| Minimum delay between arXiv API requests (ms). |
|
| Timeout for paper body fetches — HTML renders and PDF downloads (ms). |
|
| Timeout for API search/metadata requests (ms). |
|
| Enable the local OAI-PMH metadata mirror for search and metadata. |
|
| SQLite path for the mirror. |
|
| UTC cron expression for in-process daily refresh (HTTP mode only). | unset |
| Fall through to live API on local ID-lookup miss. |
|
| Positive values route every |
|
| arXiv OAI-PMH endpoint base URL. |
|
| Minimum delay between OAI-PMH requests (ms). |
|
| Abort budget for one scheduled refresh subprocess (ms). |
|
| Transport: |
|
| Port for HTTP server. |
|
|
|
|
| Auth mode: |
|
| Log level (RFC 5424). |
|
| Enable OpenTelemetry instrumentation (spans, metrics, completion logs). |
|
See .env.example for the full list of optional overrides.
Running the server
Local development
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:http # or bun run start:stdioRun checks and tests:
bun run devcheck # Lint, format, typecheck, security audit bun run test # Vitest test suite
Optional: local mirror
For self-hosted deployments behind a single egress IP, arXiv's ~3-second crawl delay serializes concurrent users. An optional local mirror removes that rate-limit exposure for arxiv_search and arxiv_get_metadata by serving from a SQLite + FTS5 store harvested via OAI-PMH. arxiv_read_paper always uses the live API — full-content harvesting is against arXiv's data policy.
Disabled by default. To enable:
# 1. Cold-start harvest (~4.4h sequential, resumable from checkpoint). One-time per installation.
bun run mirror:init
# 2. Enable the mirror.
export ARXIV_MIRROR_ENABLED=true
# 3. Start the server — reads switch to the mirror once the harvest completes.
bun run start:httpKeep it current with bun run mirror:refresh (wire to cron/systemd/launchd, or set ARXIV_MIRROR_REFRESH_CRON to schedule it in-process in HTTP mode) and check integrity with bun run mirror:verify. A newer server migrates an existing mirror's schema in place on first open — never a re-harvest — and an upgrade that rebuilds the full-text index makes that first start noticeably slower on a full-corpus mirror; mirror:verify reports the schema version and exits non-zero if a migration didn't complete.
FTS5 BM25 ranking differs from arXiv's own relevance ranking, so sort_by=relevance returns a different top-K against the mirror than against the live API. The mirror serves only the latest version of each paper — a version-pinned request falls through to the live API. A stale or failed refresh keeps serving the last completed harvest rather than dropping to the live API mid-request.
Docker
docker build -t arxiv-mcp-server .
docker run --rm -p 3010:3010 arxiv-mcp-serverThe Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/arxiv-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Directory | Purpose |
|
|
| Server-specific environment variable parsing and validation with Zod. |
| Tool definitions ( |
| Resource definitions ( |
|
|
| Optional OAI-PMH mirror — harvester, SQLite + FTS5 store, query translator, runner. |
| Mirror lifecycle scripts ( |
| Unit and integration tests. |
| Design document and directory structure. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storagearXiv API returns HTTP 200 for everything — including rate limits — so check content-type and body before parsing
Validate raw arXiv responses → normalize to domain types → return the output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
This server cannot be deployed
Maintenance
Related MCP Connectors
Search arXiv/Semantic Scholar/OpenAlex + medical evidence (PubMed/Europe PMC) + LaTeX/PDF tools.
Search and download academic papers from arXiv, PubMed, bioRxiv, medRxiv, Google Scholar, Semantic…
arXiv MCP — preprint server search (free, no auth)
Academic research search across PubMed and arXiv
Related MCP Servers
- FlicenseBqualityDmaintenanceEnables searching arXiv papers and retrieving paper metadata through MCP tools.2-
- AlicenseAqualityCmaintenanceMCP server for searching and retrieving arXiv papers with full-text PDF extraction.52MIT
- AlicenseNot gradedqualityDmaintenanceEnables searching arXiv, fetching metadata, reading papers as section-aware Markdown, listing recent papers, and downloading PDFs via five MCP tools.11 npm2MIT
- AlicenseNot gradedqualityDmaintenanceEnables searching arXiv and downloading papers via MCP tools, no API key required.Apache 2.0