
Wraps the bioRxiv and medRxiv REST APIs plus EuropePMC search to let Claude pull preprint metadata, search by keyword with relevance ranking, list recent posts in a date range, and resolve preprints to their published journal records. Handles both servers in parallel when you don't want to pick one. Five tools cover fetch by DOI with full revision history, category filtered listings, keyword search, and journal crosswalk lookups. Useful when you're analyzing early stage research, tracking preprint to publication pipelines, or need machine readable access to life sciences and medical preprints before they hit PubMed. Built on the author's mcp-ts-core framework with retry logic and polite user agent strings.
Search and retrieve bioRxiv and medRxiv preprints — by DOI, date interval, or keyword — via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://biorxiv.caseyjhand.com/mcp
bioRxiv and medRxiv preprint metadata and full text, searchable via EuropePMC. Fetch preprints by DOI, browse by date interval or subject category, search by keyword and author, resolve journal-publication crosswalks or list them by journal publication date, and extract full text from the rendered article page, from any MCP client. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
| Tool | Description |
|---|---|
biorxiv_get_preprint | Fetch full metadata, abstract, revision history, and journal crosswalk for one or more preprints by DOI |
biorxiv_list_recent | List preprints posted or updated within a date interval, with optional server, category, and funder filters |
biorxiv_search_preprints | Search preprints by keyword and/or author via EuropePMC for relevance ranking, enriched with bioRxiv/medRxiv metadata |
biorxiv_get_published_version | Resolve a preprint DOI to its journal publication record (journal DOI, name, published date) |
biorxiv_list_published_versions | List preprints that appeared as journal articles within a journal publication-date interval, whenever they were posted |
biorxiv_get_fulltext | Retrieve a preprint's full text as best-effort Markdown extracted from its rendered HTML article page |
biorxiv_list_categories | List valid subject category strings for bioRxiv and medRxiv |
biorxiv_get_preprint toolhttps://doi.org/…, doi:…, a biorxiv.org/medrxiv.org article URL, a vN or .full suffix), scoped to biorxiv, medrxiv, or both (default both)revisions[] — title, authors, abstract, category, license, awards, jatsxmlUrl, and publishedJournalDoi once accepted. Funder names are left out because api.biorxiv.org attributes them to unrelated organizationsfailed[] with a reason (not_found, invalid_doi_format, upstream_unavailable, rate_limited) and a retryable flag; not_found only when every attempted server answeredbiorxiv_list_recent toolstart_date/end_date interval, server (default both), and optional category (a value from biorxiv_list_categories) and bioRxiv-only funder (a ROR ID) filters; a filter the API ignored or cannot apply raises invalid_category or invalid_funder rather than returning an unfiltered or empty pagecursor; pagination is per server ({ biorxiv: { cursor, total }, medrxiv: { cursor, total } }), a cursor past the last page is marked exhausted: true, and a server that did not answer is named in failed[]include_abstract: true adds thembiorxiv_search_preprints toolquery and/or author, optional date_from/date_to and server (default both); up to 100 results per page (default 25), paged with cursor_markbiorxiv_get_preprint; a record left with EuropePMC metadata only carries enriched: false and an enrichment_error (service_error, rate_limited, not_found), with partial_results setinclude_abstract: false drops them for a response about a third the sizebiorxiv_get_published_version toolserver (default both — the two servers share their DOI prefixes); 10.64898/ DOIs, which the /pubs crosswalk cannot key on, resolve through the preprint's own journal DOIserver that answered; no server answering raises a retryable upstream_unavailable or rate_limited, never doi_not_foundbiorxiv_list_published_versions toolstart_date/end_date interval of journal publication dates and server (default both); each row is the record biorxiv_get_published_version returns, so a week's publications include preprints posted years earlier, and every preprintDoi (10.1101/ or 10.64898/) feeds the DOI toolscursor; pagination is per server, a cursor past one server's last row is marked exhausted: true with no total, and a server that did not answer is named in failed[]include_abstract: true adds thembiorxiv_get_fulltext toolserver (default both), and an optional version (or a vN suffix — the two must agree; a version the preprint lacks raises version_not_found); extracts Markdown from the rendered HTML article page, since there is no keyless JATS source, and names the answering server(1–16), (Fig. 1a)) and every reference entry's bibliographic text, with the DOI of an entry that has one as a doi.org linkomittedTables names it with the URL that serves its cells, on every chunk and in the rendered textoffset/limit characters (default 20,000; a limit past the remaining text returns the rest), reporting totalChars, remainingChars, hasMore, and wordCount; the extracted article is cached per version, so paging costs one origin fetchfulltext_unavailable, routing to biorxiv_get_preprintbiorxiv_list_categories toolcategory for biorxiv_list_recentBuilt 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.
bioRxiv-specific:
BiorxivApiService wraps api.biorxiv.org — details, publications, and crosswalk endpoints with retry and exponential backoff; a 429 is classified as a retryable rate_limited error carrying the parsed Retry-After wait, with the upstream response body kept out of the payloadEuropePmcService wraps the EuropePMC search endpoint for relevance-ranked keyword and/or author results, classified the same way on a 429BiorxivFullTextService fetches and extracts Markdown from the rendered HTML article pages on www.biorxiv.org / www.medrxiv.org — a distinct origin from the JSON APIPromise.allSettled — both biorxiv and medrxiv queried in parallel when server="both", with each result naming the server that answered and listings keeping per-server paginationUser-Agent header including a mailto address (BIORXIV_MAILTO env var) per Cold Spring Harbor Lab API guidelinesAgent-friendly output:
failed[] with a typed reason and retryable flag instead of aborting the whole batch or listing callreason: "rate_limited" carrying the origin's parsed retryAfter wait, distinguished from a generic upstream_unavailablebiorxiv_search_preprints results carry enriched plus a typed enrichment_error (service_error / rate_limited / not_found) so callers branch on data, not string parsingexhausted cursors are flagged as an out-of-range artifact rather than an empty interval, and biorxiv_get_fulltext reports totalChars / remainingChars / hasMore for chunked reads{beta}, {+/-}, [≥]) become their characters, structured-abstract headings read Results: …, list items read • …, and figure and table blocks are dropped. The Markdown in content[] escapes upstream text so it renders as writtenA public instance is available at https://biorxiv.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"biorxiv-mcp-server": {
"type": "streamable-http",
"url": "https://biorxiv.caseyjhand.com/mcp"
}
}
}
Add the following to your MCP client configuration file.
{
"mcpServers": {
"biorxiv-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/biorxiv-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"BIORXIV_MAILTO": "your@email.com"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"biorxiv-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/biorxiv-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"BIORXIV_MAILTO": "your@email.com"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"biorxiv-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "-e", "BIORXIV_MAILTO=your@email.com", "ghcr.io/cyanheads/biorxiv-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 BIORXIV_MAILTO=your@email.com bun run start:http
# Server listens at http://localhost:3010/mcp
git clone https://github.com/cyanheads/biorxiv-mcp-server.git
cd biorxiv-mcp-server
bun install
cp .env.example .env
# optionally set BIORXIV_MAILTO for polite API access
All configuration is validated at startup via Zod schemas in src/config/server-config.ts.
| Variable | Description | Default |
|---|---|---|
BIORXIV_MAILTO | Email address included in the User-Agent header for polite API access per Cold Spring Harbor Lab guidelines. Optional, but recommended. | — |
BIORXIV_API_BASE_URL | Override the bioRxiv API base URL. | https://api.biorxiv.org |
EUROPEPMC_API_BASE_URL | Override the EuropePMC base URL. | https://www.ebi.ac.uk/europepmc/webservices/rest |
BIORXIV_WEB_BASE_URL | Override the bioRxiv website base URL (full-text HTML source for biorxiv_get_fulltext). | https://www.biorxiv.org |
MEDRXIV_WEB_BASE_URL | Override the medRxiv website base URL (full-text HTML source for biorxiv_get_fulltext). | https://www.medrxiv.org |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_HTTP_ENDPOINT_PATH | HTTP endpoint path. | /mcp |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
LOG_TOOL_FAILURE_PAYLOADS | Log each failed tool call's arguments and result, redacted by key name and capped at LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (default 16384). A secret inside a free-form value is not redacted. | false |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
See .env.example for the full list of optional overrides.
Build and run:
# One-time build
bun run rebuild
# Run the built server
bun run start:stdio
# or
bun run start:http
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against spec
docker build -t biorxiv-mcp-server .
docker run --rm -e BIORXIV_MAILTO=your@email.com -p 3010:3010 biorxiv-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/biorxiv-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools and initializes services. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts). Seven tools across bioRxiv and medRxiv. |
src/services/biorxiv | BiorxivApiService — details, publications, and crosswalk endpoint wrappers with retry. |
src/services/biorxiv-fulltext | BiorxivFullTextService — rendered HTML article page fetch and Markdown extraction. |
src/services/europe-pmc | EuropePmcService — preprint keyword/author search endpoint wrapper. |
tests/ | Unit and integration tests mirroring the src/ structure. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagesrc/mcp-server/tools/definitions/index.tsIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
BIORXIV_MAILTOContact email for User-Agent header — optional, for polite API access.
MCP_LOG_LEVELdefault: infoSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
MCP_HTTP_HOSTdefault: 127.0.0.1The hostname for the HTTP server.
MCP_HTTP_PORTdefault: 3010The port to run the HTTP server on.
MCP_HTTP_ENDPOINT_PATHdefault: /mcpThe endpoint path for the MCP server.
MCP_AUTH_MODEdefault: noneAuthentication mode to use: 'none', 'jwt', or 'oauth'.