Skip to main content
Glama
kaysiz

DataCite Librarian MCP

by kaysiz
README.md
# DataCite Librarian MCP (`mcp-test`)-test

Local **[Model Context Protocol](https://modelcontextprotocol.io)** server for the DataCite community: **repository QA**, **funder compliance**, **CSV index analytics**, **search/facets**, and **exports** over [DataCite](https://datacite.org) **monthly** and **public** datafiles you host on disk.

Built with [FastMCP](https://gofastmcp.com) · [uv](https://docs.astral.sh/uv/) · Python 3.12+ · MIT

> **This repository does not ship production datafiles.** You must download them yourself and keep them outside git (see below). CI runs only against a small **mock** corpus.

---

## Strict requirements

1. **You must obtain datafiles from DataCite**, not from this repo.
2. **Never commit** real `part_*.jsonl.gz`, `YYYY-MM.csv.gz`, TAR archives, or monthly/public extracts. They are **gitignored** under `data/local/` and at the repo root.
3. **Set `DATACITE_DATA_DIR`** to your extracted data directory. If the variable is set but the path does not exist, the MCP **errors** (it does not silently use mock data).
4. **Mock data is for demos/tests only** (or when `DATACITE_DATA_DIR` is unset / `DATACITE_USE_MOCK=1`). It is not a substitute for real monthly/public files.
5. **Aggregate tools scan a limited number of records** by default (`DATACITE_MAX_RECORDS`, default `10000`). Always inspect `truncated`, `scan_limit`, and (for indexes) `coverage_pct` so you do not treat a sample as the full corpus.
6. **Metadata vs index:** a `YYYY-MM.csv.gz` index can list hundreds of thousands of DOIs; you need the matching `part_*.jsonl.gz` files for full QA/search. Use `coverage_report` to measure the gap.
7. **Respect DataCite access terms:** the **public** annual file is openly documented; the **monthly** file is for **DataCite Members and Consortium Organizations** (authenticated S3 access). See official docs linked below.

---

## Obtain DataCite datafiles (official documentation)

Follow **only** DataCite’s documentation and portals. Do not rely on third-party mirrors unless you trust them and accept their terms.

| Resource | URL |
|----------|-----|
| **Data files portal** | [https://datafiles.datacite.org](https://datafiles.datacite.org) |
| **Public data file** (annual, public DOIs; documented for open use) | [DataCite Support — Public Data File](https://support.datacite.org/docs/datacite-public-data-file) |
| **Monthly data file** (members/consortium; S3 + credentials) | [DataCite Support — Monthly Data File](https://support.datacite.org/docs/datacite-monthly-data-file) |
| **XML ↔ JSON mapping** (record shape) | [DataCite Support — XML to JSON](https://support.datacite.org/docs/datacite-xml-to-json-mapping) |
| **Metadata schema** | [https://schema.datacite.org](https://schema.datacite.org) |

### High-level download steps (summary only — details are on Support)

**Public annual file**

1. Open [datafiles.datacite.org](https://datafiles.datacite.org) and locate the latest **public** release (e.g. `public-2025`).
2. Download the TAR (or equivalent) per the [Public Data File](https://support.datacite.org/docs/datacite-public-data-file) page.
3. Extract locally to a directory **you** control (recommended: this repo’s `data/local/`, which is gitignored).
4. Confirm you see something like `dois/updated_YYYY-MM/part_*.jsonl.gz` and/or monthly `YYYY-MM.csv.gz` indexes inside the extract.

**Monthly file (members)**

1. Confirm your organization is a DataCite Member or Consortium participant.
2. Follow [Monthly Data File](https://support.datacite.org/docs/datacite-monthly-data-file) for temporary AWS credentials and S3 access.
3. Sync/extract to `data/local/` (or another path outside git).
4. Point `DATACITE_DATA_DIR` at that root.

**After download — required layout for this MCP**

Preferred (matches DataCite releases):

```text
data/local/                    # or any path you pass as DATACITE_DATA_DIR
  STATUS.json                  # optional
  MANIFEST.json                # optional
  dois/
    updated_2026-06/
      2026-06.csv.gz           # index: doi, state, client_id, updated
      part_0000.jsonl.gz       # full metadata (~10k records/part typical)
      part_0001.jsonl.gz
      …
```

Also supported (experimental/flat):

```text
data/local/
  2026-06.csv.gz
  part_0000.jsonl.gz
```

See [data/local/README.md](data/local/README.md) and [docs/DATAFILE_SCHEMA.md](docs/DATAFILE_SCHEMA.md).

---

## Quick start (development)

### Prerequisites

- Python **3.12+**
- [uv](https://docs.astral.sh/uv/)

### Install

```bash
git clone <this-repo-url> mcp-test
cd mcp-test
uv sync --all-groups
```

### Run MCP (stdio — for Cursor / Claude Desktop / other MCP hosts)

```bash
# Demo/mock only (no real datafiles)
uv run datacite-librarian-mcp

# Production/local datafiles (STRICT: path must exist)
export DATACITE_DATA_DIR="/absolute/path/to/data/local"
export DATACITE_MAX_RECORDS=20000   # optional; raise for fuller scans
uv run datacite-librarian-mcp
```

Example MCP host config (`mcp.json` pattern):

```json
{
  "mcpServers": {
    "datacite-librarian": {
      "command": "uv",
      "args": [
        "run",
        "--directory",
        "/absolute/path/to/mcp-test",
        "datacite-librarian-mcp"
      ],
      "env": {
        "DATACITE_DATA_DIR": "/absolute/path/to/mcp-test/data/local",
        "DATACITE_MAX_RECORDS": "20000"
      }
    }
  }
}
```

### Run MCP (HTTP, local testing)

```bash
export DATACITE_DATA_DIR="/absolute/path/to/data/local"
uv run python -c "from datacite_librarian_mcp.server import mcp; mcp.run(transport='http', host='127.0.0.1', port=8765)"
```

### Natural-language REPL (maps questions → tools; not a full LLM)

```bash
export DATACITE_DATA_DIR="/absolute/path/to/data/local"
uv run datacite-librarian-chat
# or: uv run python scripts/interactive_client.py
```

Examples: `how many DOIs?`, `how many funders?`, `repository health for zenodo`, `funder compliance for European Commission`.

---

## Who this is for

| Audience | Start with |
|----------|------------|
| Librarians / RDM | `community_guide`, `repository_health`, `export_health_issues` |
| Research offices | `funder_compliance`, `export_funder_issues` |
| Repository operators | `index_summary`, `index_client`, `coverage_report` |
| Bibliometrics / policy | `facets`, `top_subjects`, `index_summary` (report `truncated`) |
| Developers | `server_info`, mock corpus, tests |
| Teachers | `datacite-librarian-chat`, mock data |

Call **`community_guide`** from any MCP client for persona-oriented workflows.

---

## Tools (summary)

**Discovery:** `community_guide`, `server_info`, `corpus_status`, `corpus_inventory`, `diff_partitions_summary`  

**Metadata QA / compliance** (needs `part_*.jsonl.gz`): `repository_health`, `funder_compliance`, `search_dois`, `get_doi`, `check_doi_qa`, `list_clients`, `list_funders`  

**Analytics:** `facets`, `top_subjects`  

**CSV index only** (no JSONL required): `index_summary`, `index_client`, `coverage_report`  

**Exports** (writes under `exports/` or `DATACITE_EXPORT_DIR`): `export_health_issues`, `export_funder_issues`, `export_search_results`  

**Ops:** `regenerate_mock_data`

---

## Configuration

| Variable | Purpose |
|----------|---------|
| `DATACITE_DATA_DIR` | Corpus root (**must exist** if set) |
| `DATACITE_USE_MOCK` | `1` / `true` forces mock corpus |
| `DATACITE_MOCK_DIR` | Override mock write/read location |
| `DATACITE_MAX_RECORDS` | Aggregate scan ceiling (default `10000`) |
| `DATACITE_DOI_LOOKUP_MAX_SCAN` | `get_doi` ceiling; `0` = full local scan |
| `DATACITE_EXPORT_DIR` | Export output directory |

---

## Development & CI

```bash
uv sync --all-groups
uv run pytest
uv run ruff check src tests
```

GitHub Actions (`.github/workflows/ci.yml`) runs **ruff** + **pytest** on Python 3.12 and 3.13 with `DATACITE_USE_MOCK=1` only—no real datafiles in CI.

Project docs:

- [docs/DATAFILE_SCHEMA.md](docs/DATAFILE_SCHEMA.md) — file/record schema notes  
- [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) — contributor workflow  
- [data/local/README.md](data/local/README.md) — where to put downloads  

---

## Design principles

1. **Local-first** — organizations keep datafiles; this project never distributes bulk DOI corpora.  
2. **Stream-read** — gzip JSONL/CSV line-by-line; suitable for large files without a database.  
3. **Light dependencies** — `fastmcp` + `pydantic` (+ stdlib).  
4. **Honest limits** — `truncated`, `scan_limit`, `coverage_pct` on tool outputs.  
5. **Index without metadata** — CSV tools help before all `part_*.jsonl.gz` are downloaded.

---

## License

MIT — see [LICENSE](LICENSE).

DataCite bulk **metadata** licensing and access are governed by DataCite (public file documentation typically describes CC0 for metadata; **confirm on Support**). Member monthly access may be restricted. This software does not redistribute production datafiles.

---

## Links

- [Data files portal](https://datafiles.datacite.org)  
- [Public data file docs](https://support.datacite.org/docs/datacite-public-data-file)  
- [Monthly data file docs](https://support.datacite.org/docs/datacite-monthly-data-file)  
- [DataCite Metadata Schema](https://schema.datacite.org)  
- [MCP specification](https://modelcontextprotocol.io)  
- [FastMCP](https://gofastmcp.com)

TDQS

C2.9/5.0

Scored across 21 tools

Disambiguation4/5

Most tools target distinct resources (search, QA, compliance, corpus status). However, get_doi and check_doi_qa both report QA issues (summary vs full breakdown), and export_* tools wrap their base operations, which could cause confusion. Overall, the descriptions are detailed enough to differentiate most tools.

Naming Consistency3/5

Tool names mix verb-first (search_dois, list_clients, export_search_results) with noun-first (facets, repository_health, corpus_status) and some ambiguous names like index_client and diff_partitions_summary. The patterns are inconsistent but readable.

Tool Count3/5

21 tools is on the heavy side for a specialized librarian server. Many tools are variations of reporting/exporting (export_health_issues, export_funder_issues, export_search_results) and status (corpus_status, corpus_inventory, server_info), but the breadth of DataCite functionality justifies most tools.

Completeness4/5

The server covers core analysis needs: search, lookup, QA, compliance, aggregations, and exports. However, there is no direct tool to fetch the full raw metadata for a DOI (only summaries and QA), and no create/update/delete operations, which might be outside scope but could be a gap for some use cases.

Maintenance

ActivityInactive
ResponsivenessNo issues