# Scholarly research MCP (Crossref, Europe PMC, arXiv) (`keepable_injera/scholarly-research-mcp`) Actor

Search scholarly metadata and arXiv preprints through MCP, or look up a DOI. Uses Crossref, Europe PMC and arXiv without source API keys.

- **URL**: https://apify.com/keepable_injera/scholarly-research-mcp.md
- **Developed by:** [Chee Chiaw Lim](https://apify.com/keepable_injera) (community)
- **Categories:** AI, Developer tools, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 tool calls

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Scholarly research MCP

An Apify Standby MCP server for scholarly metadata from Crossref, Europe PMC, and arXiv. It uses public metadata APIs without source API keys. It also runs one tool as a batch Actor.

### Connect

Use this Streamable HTTP endpoint in your MCP client.

```text
https://<username>--scholarly-research-mcp.apify.actor/mcp
Authorization: Bearer <APIFY_TOKEN>
```

Apify authenticates requests to the hosted endpoint. The local Express server relies on that platform authentication when deployed. The Apify MCP server at `mcp.apify.com` also lists the Actor.

For a local server with no INPUT, run `npm start` and connect to `http://localhost:3000/mcp`. Node 20 or later is required. There is no build step. GET `/` responds to Apify readiness probes. GET and DELETE `/mcp` return 405 because the MCP transport is stateless.

### Tools

All search queries accept 1 to 300 characters. Limits are integers from 1 to 20, default 5. Dates use YYYY-MM-DD. Crossref and Europe PMC abstracts default to hidden.

| Tool | Arguments |
| --- | --- |
| `search_works` | Required `query`. `source` is `crossref` by default or `europepmc`. Optional `fromDate`, `untilDate`, `type` for Crossref, `openAccessOnly` for Europe PMC, `limit`, `includeAbstract`. |
| `get_work_by_doi` | Required `doi`, accepting a bare DOI, `doi:` prefix, or doi.org URL. Optional `includeAbstract`. |
| `search_preprints` | Required `query`, using arXiv syntax such as `all:transformer`. Optional `category` such as `cs.LG`, `sortBy` of `relevance`, `submittedDate`, or `lastUpdatedDate`, and `limit`. Abstracts are always included. |
| `search_biomedical` | Required `query`. Optional `openAccessOnly`, `fromDate`, `untilDate`, `limit`, `includeAbstract`. Uses Europe PMC. |

Each result has `tool`, `query` or `doi`, `source`, `total` when supplied by the source, `count`, and `works`. A DOI lookup returns a result such as this abbreviated example.

```json
{
  "tool": "get_work_by_doi",
  "doi": "10.1038/nature12373",
  "source": "crossref",
  "count": 1,
  "works": [{
    "source": "crossref",
    "id": "10.1038/nature12373",
    "doi": "10.1038/nature12373",
    "title": "Nanometre-scale thermometry in a living cell",
    "url": "https://doi.org/10.1038/nature12373",
    "abstract": null
  }]
}
```

Work records also contain up to 20 authors, `authorsTruncated`, publication date, venue, type, citation count, open access status, licence, and source attribution. Missing values are null. arXiv adds categories and a PDF link. Abstract text has tags removed and is capped at 1500 characters. DOI values are trimmed and lowercased. Crossref open access status is null because a licence URL alone does not establish open access.

### Batch mode

Outside Standby, an INPUT runs one tool and exits. Use the Actor input form or save this as `storage/key_value_stores/default/INPUT.json` before `npm start`.

```json
{"tool":"search_works","query":"crispr malaria","source":"crossref","limit":5,"includeAbstract":false}
```

The program also accepts `{"tool":"search_works","arguments":{"query":"crispr malaria"}}`. Only arguments belonging to the selected tool are mapped from the flat form. Tool validation rejects unsupported source filters and reversed date ranges.

The batch writes works to the default dataset and the result to the `OUTPUT` key. Successful calls also append a small log item with `tool`, `args`, `source`, `count`, and `calledAt`. Dataset rows therefore include call logs as well as works. Logging failures do not fail a successful call. A tool error writes an error to OUTPUT and exits with code 1.

### Pricing

Each successful tool call costs $0.002 through the `tool-call` event. Failed calls, including missing Crossref DOIs, are not charged. An empty successful search counts as a call. A spending limit that prevents charging returns `Spending limit reached`. Dataset writes carry no event charge. Apify also bills Standby platform usage.

### Sources and terms

- Crossref metadata comes from `api.crossref.org`. Attribution is `Metadata from Crossref (api.crossref.org)`. Crossref metadata is generally open; abstracts and linked content may have separate copyright. The record preserves the first supplied licence URL without treating it as an open access guarantee. Set `CROSSREF_MAILTO` to add a contact address to requests.
- Europe PMC data comes from EMBL-EBI. Attribution is `Data from Europe PMC (europepmc.org), EMBL-EBI`. The source licence field is preserved when supplied. Open access filtering does not grant reuse rights beyond the work's own licence.
- arXiv metadata is CC0 1.0, including the returned metadata abstracts. Attribution is `Metadata from arXiv.org (CC0). Not affiliated with or endorsed by arXiv.` E-print licences are shown on their abstract pages.

Crossref and Europe PMC abstract requests include the notice `Abstract may be copyrighted by the publisher or authors; shown for research and discovery only.`

The server spaces requests per host by at least 1000 ms for Crossref and Europe PMC, and 3100 ms for arXiv. Requests to a host run serially, including body consumption. Rate limits apply per server process. HTTP 429 and server errors receive bounded retries with backoff and Retry-After support.

The Actor fetches no full text or PDFs and hosts no PDFs. Crossref and Europe PMC abstracts are opt-in. It is not affiliated with Crossref, EMBL-EBI, or arXiv.

### Offline verification

Run `npm test`. Run `npm run verify:local` to execute all four tools through `npm start` and inspect their stored outputs. Tests use the captured responses in `test/fixtures` and never need source network access. With a batch INPUT present, `npm run start:offline` runs the real Actor entry point with fixture responses. This preload replaces only upstream fetch calls.

# Actor input Schema

## `tool` (type: `string`):

Tool.

## `query` (type: `string`):

Query.

## `doi` (type: `string`):

DOI.

## `source` (type: `string`):

Source.

## `limit` (type: `integer`):

Result limit.

## `includeAbstract` (type: `boolean`):

Include abstract.

## `category` (type: `string`):

arXiv category.

## `sortBy` (type: `string`):

arXiv sort order.

## `fromDate` (type: `string`):

Published from.

## `untilDate` (type: `string`):

Published until.

## `openAccessOnly` (type: `boolean`):

Open access only, Europe PMC.

## `type` (type: `string`):

Crossref only, for example journal-article.

## Actor input object example

```json
{
  "tool": "search_works",
  "query": "crispr malaria",
  "source": "crossref",
  "limit": 5,
  "includeAbstract": false,
  "sortBy": "relevance"
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `output` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "query": "crispr malaria"
};

// Run the Actor and wait for it to finish
const run = await client.actor("keepable_injera/scholarly-research-mcp").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "query": "crispr malaria" }

# Run the Actor and wait for it to finish
run = client.actor("keepable_injera/scholarly-research-mcp").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "query": "crispr malaria"
}' |
apify call keepable_injera/scholarly-research-mcp --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,keepable_injera/scholarly-research-mcp"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/p6BElVfzPBmHa6brV/builds/csF376kJ7h9RjkmZN/openapi.json
