Skip to main content
Glama
musharna

data-aggregator-mcp

by musharna

🔎 data-aggregator-mcp

One MCP server to find and fetch research data across archives, omics registries, and literature — behind a single normalized model.

PyPI Python Downloads License: MIT CI Glama DOI

search one query across 17 sourcesZenodo, DataCite (Dryad / Figshare / Dataverse / OSF / OpenNeuro / Mendeley), NCBI omics (GEO / SRA / BioProject), BioStudies (EBI, incl. ArrayExpress), literature (PubMed / OpenAIRE), HuggingFace datasets, DataONE (eco / environmental), OmicsDI (proteomics / metabolomics), DANDI (neurophysiology), CZ CELLxGENE (single-cell), OpenML (ML datasets), RCSB PDB (structures), UniProtKB (proteins), the GWAS Catalog, GBIF (biodiversity), data.gov (US federal open data), and NASA CMR (Earth science) — deduplicated, normalized, and cross-linked. resolve any hit to its file manifest, citation, trust signals, and the data it points at. fetch it to disk with checksum verification.

mcp-name: io.github.musharna/data-aggregator-mcp

✨ Why this

Most data MCPs wrap a single source. This one unifies them behind six tools and one DataResource model, so an agent searches once and gets back comparable records:

  • Multi-domain, one model — generalist archives + raw omics + literature, deduplicated by DOI (the fetchable record wins over bare metadata).

  • Taxonomy synonym expansionorganism="Orobanche aegyptiaca" also matches Phelipanche aegyptiaca (NCBI Taxonomy), so a species rename doesn't cost you results.

  • Paper → data bridge — resolve a paper and get links to the GEO / SRA / BioProject / DataCite records it produced.

  • Verified fetch — streams to disk with md5 verification where the source exposes a checksum, optional archive unpacking, and a fail-loud integrity sniff that rejects an HTML paywall page served as a "PDF".

  • Citations, access & full text — render a citation in any CSL style, get normalized access/license, and pull open-access full text — all in one resolve.

  • Trust signals — usage metrics (citations / views / downloads / likes), version status (is_latest / superseded_by), and last_updated freshness, surfaced wherever the source exposes them.

  • Interop exportsresolve(format="croissant") or "ro-crate" hands a dataset to an ML or research-packaging pipeline as standard JSON-LD.

  • Operate on data in placeoperate reads the schema, previews rows, or runs a read-only SQL SELECT against a remote Parquet/CSV/TSV without downloading it (Parquet footer + DuckDB httpfs range reads). Optional [operate] extra; base install is unchanged.

  • Relate across recordsrelate takes a handful of resolved ids and reports how they connect — shared accession, shared cross-identifier, an explicit link, or version lineage — naming the literal shared value as evidence. Metadata hints only: it never reads files or executes a join.

→ Full rationale and a comparison vs. single-source servers, breadth gateways, and ML-dataset tools: docs/POSITIONING.md.

Related MCP server: Academic MCP

⚡ Quickstart

Run with no install:

uvx data-aggregator-mcp

Register with Claude Code:

claude mcp add data-aggregator -- uvx data-aggregator-mcp

A typical agent flow:

search("drought stress RNA-seq", organism="Sorghum bicolor")
  → [ geo:GSE..., sra:SRX..., zenodo:..., pubmed:... ]   # deduped, taxa-normalized

resolve("sra:SRX079566")
  → DataResource{ files: [ENA FASTQ urls…], access: "open", taxa: [...] }

fetch("sra:SRX079566", dest="./data")
  → ["./data/SRX079566_1.fastq.gz", …]                   # md5-verified
pip install data-aggregator-mcp
data-aggregator-mcp        # or: python -m data_aggregator_mcp

To use the operate tool (query remote tabular files in place), install the optional extra:

pip install "data-aggregator-mcp[operate]"

Add to a client's MCP config (e.g. Claude Desktop claude_desktop_config.json):

{
  "mcpServers": {
    "data-aggregator": {
      "command": "uvx",
      "args": ["data-aggregator-mcp"],
      "env": { "NCBI_API_KEY": "your-optional-key" }
    }
  }
}

🌐 Transports

stdio (default) — the server runs as a child of the client, so fetch() writes to your own disk. Nothing to configure; every command above uses it.

Streamable HTTP — the same six tools, prompts, and resources over HTTP:

data-aggregator-mcp --transport http     # → http://127.0.0.1:8000/mcp/

flag

default

notes

--transport {stdio,http}

stdio

--host

127.0.0.1

this machine only; any non-loopback value requires --allow-host

--port

8000

--allow-host HOST:PORT

auto on loopback

permitted Host header, repeatable — required off loopback

--allow-origin ORIGIN

derived

permitted browser Origin header, repeatable

--stateless

off

fresh transport per request, no session affinity

--json-response

off

plain JSON responses instead of SSE streams

The endpoint is served at /mcp/ — with the trailing slash. /mcp answers 307 redirecting there, which is fine for any client that follows redirects (a 307 preserves the POST body); point one that doesn't straight at /mcp/. In stateful mode, sessions idle for 30 minutes are reaped.

DNS-rebinding protection is always on. A loopback bind derives its own host/origin allowlist, so the default needs no configuration. A non-loopback bind (--host 0.0.0.0, a LAN address, a container interface) refuses to start without at least one explicit --allow-host — guessing an allowlist there is precisely the hole the protection exists to close, so it fails loud instead of open:

data-aggregator-mcp --transport http --host 0.0.0.0 \
  --allow-host data.example.org:8000

Once running, a request whose Host header is outside the allowlist is refused with 421 Invalid Host header.

⚠️ fetch(dest=…) writes to the server's filesystem, not the client's. Over stdio those are the same disk; over HTTP they may be different machines, and the caller gets back paths it cannot read. Treat dest on an HTTP deployment as server-side staging, or use stdio when you need the bytes locally. search, resolve, operate, relate, and list_sources are unaffected — they return data, not paths.

🗂️ Sources

Source

Discover

Fetch

Checksum

Zenodo

md5

DataCite → Figshare

md5

DataCite → Dataverse

md5

DataCite → OSF

md5

DataCite → Dryad

manifest only¹

sha-256 (listed)

DataCite → Mendeley & others

NCBI SRA

✅ (ENA FASTQ)

md5

NCBI GEO

✅ (suppl/)

none²

NCBI BioProject

→ SRA links

PubMed / OpenAIRE

✅ (OA full text)

none²

HuggingFace datasets

✅ (resolve URL)

none

DataONE (eco/env)

✅ (Member Node)

md5 / sha-256

OmicsDI → PRIDE

✅ (HTTPS FTP)

size only

OmicsDI → MetaboLights

✅ (HTTPS FTP)

none

OmicsDI → other MS repos

DataCite → OpenNeuro

✅ (snapshot)

none²

DANDI (neurophysiology)

✅ (302→S3)

none²

CZ CELLxGENE (single-cell)

✅ (H5AD/RDS)

none²

OpenML (ML datasets)

✅ (ARFF)

md5

RCSB PDB (structures)

✅ (.cif/.pdb)

none²

GWAS Catalog

→ PMID bridge

¹ Dryad downloads are token / bot-challenge gated, so fetch fails loud; resolve still lists the files. ² No upstream checksum — fetch verifies content-type instead (rejects an HTML page served in place of a binary).

🛠️ Tools

search(query?, size?, sources?, organism?, disease?, tissue?, chemical?, assay?, kind?, published_after?, published_before?, rank?, cursor?, collapse_mirrors?, understand?, multi_query?, provenance?)

Fan out across all wired sources in parallel and return compact DataResource records, deduped by DOI. Per-source failures land in errors{} — never silently dropped.

  • organism — expand the query with NCBI-Taxonomy synonyms; the expansion is echoed in taxon_expansion, and results carry normalized taxa[] ({taxid, name}) plus a described_in link to plant-genomics-mcp for plant taxa.

  • sources — restrict the fan-out, e.g. ["omics"].

  • size — max results (1–50).

  • kind — keep only dataset / sequencing_run / study / publication / software.

  • published_after / published_before — filter by publication year.

  • rankrelevance (default) or semantic (re-rank the fetched page by embedding similarity to the query; needs EMBEDDING_API_BASE, degrades to relevance order otherwise).

  • understand — opt into LLM query understanding (default false). A free-text query is normalized into a focused keyword query: conversational fluff ("I'm looking for…", "where can I find…") is stripped while the scientific and entity terms are kept so they still match by text. The LLM also detects structured entities (organism/disease/tissue/chemical/assay, kind) — these are echoed in query_understanding.extracted for transparency but not auto-applied, because ANDing LLM-inferred facets across free-text keyword upstreams over-constrains and hurts recall. Only the cleaned keyword_core and explicit year scopes are applied; the ontology resolvers still run on the facets you pass (the LLM proposes, you dispose). Needs an LLM endpoint (LLM_API_BASE); with none configured the search runs unchanged and notes it in errors['understand']. Effectiveness is query- and model-dependent — opt-in / default-off; validate the recall lift on your own corpus and LLM (see the eval harness below). On our small verified set multi_query= is the stronger, always-safe recall lever; understand= is approximately neutral with a weak local model.

  • multi_query — opt into diverse multi-query recall expansion (default false). An LLM generates up to a few deliberately-diverse reformulations of your query (different facets/synonyms/framings, not paraphrases), each is fanned out across every source, and the deduped union is re-ranked against your original query — surfacing relevant records a single keyword query would miss. Bounded at MAX_QUERY_VARIANTS (4, incl. the original, which is always kept so recall never drops below baseline), so it costs at most N× the upstream calls. Composes with understand= (which structures variant 0). The variants used are echoed in query_expansion. Needs an LLM endpoint (LLM_API_BASE); with none configured the search runs as a normal single query and notes it in errors['multi_query'].

  • cursor — opaque token from a prior result's next_cursor; pages forward across every source. In cursor mode the other params are read from the token, so query is optional.

resolve(id, cite?, format?, trust?, fair?, use?)

Full record + files manifest. Routes by id shape — zenodo:7654321, a bare DOI, datacite:10.5061/dryad.x, an omics id (sra:SRX079566, geo:GSE332789, bioproject:PRJNA1468572), a literature id (pubmed:34320281, openaire:<id>), a HuggingFace id (hf:owner/name), a DataONE id (dataone:doi:10.5063/F1HT2M7Q), or an OmicsDI id (omicsdi:pride:PXD000001). Attaches, where available:

  • files[] — ENA FASTQ manifest (SRA), GEO suppl/, or the host repo's native manifest (Figshare / Dataverse / OSF / Dryad).

  • links[] — paper → data: pubmed:sra: / geo: / bioproject: (NCBI elink); openaire:datacite: (ScholeXplorer Scholix).

  • access / license — normalized status (open / embargoed / restricted / closed / unknown) and license where the source exposes it.

  • identifiers — normalized {pmid, pmcid, doi}, plus an open-access full-text FileEntry (EuropePMC XML, or an Unpaywall PDF fallback) for papers.

  • citation — pass cite=<format>: bibtex, ris, csl-json, or any CSL style name (apa, mla, vancouver, …). DOI records use content negotiation; others render CSL-JSON from metadata. Off by default; failures degrade quietly.

  • trust signalsmetrics (citations / views / downloads / likes), is_latest / superseded_by (derived from version links), and last_updated freshness, where the source provides them.

  • trust=true — attach retraction status (via Crossref) under trust{}. One extra Crossref call; meaningful for DOI-bearing records only.

  • fair=true — attach an RDA-grounded FAIRness score (0–100 + F/A/I/R sub-scores + actionable gaps) computed from the record metadata under fair{}. Pure/local — no extra network call.

  • use=<intent> — attach a licence-compatibility advisory under license_compat{} for the intended use (commercial / redistribute / modify / ml-training). Returns ALLOW/REVIEW/DENY with the governing clause. Metadata-derived advisory, not legal advice; an absent/unrecognized licence yields REVIEW.

  • format — pass format="croissant" (file-level Croissant JSON-LD), "ro-crate" (minimal RO-Crate 1.1), or "provenance" (one-call RO-Crate 1.1 data-availability dossier bundling version-currency, licence+SPDX, FAIR score, and retraction status) to attach a standard manifest under the matching field.

fetch(id, dest?, files?, max_bytes?, force?, extract?)

Download files to disk and return their paths. Streams under a max_bytes guard (force to override) with md5 verification wherever a checksum exists.

  • files — restrict to a subset of the resolved manifest.

  • extract — unpack downloaded zip / tar archives in place, guarded against path traversal and runaway extracted size. Off by default.

  • Unverified fetches (GEO suppl/, literature full text) get a content-type sniff that fails loud if a declared binary is actually an HTML page.

  • Fetchable: Zenodo, SRA, GEO, DataONE (Member-Node objects, md5/sha-256 verified), DataCite-hosted Figshare / Dataverse / OSF, HuggingFace datasets, PRIDE / MetaboLights (via OmicsDI, unverified), and literature open-access full text. Dryad, other DataCite repos, and other OmicsDI repos (MassIVE / GNPS / ...) are discovery-only and raise FetchNotSupportedError.

list_sources()

Wired sources with their capabilities — layer, kinds, supported filters, fetchability, operable flag, id examples, auth, and rate limits.

operate(op, id, file?, query?, n?, columns?)

Inspect or query a remote tabular file (Parquet / CSV / TSV) without downloading it. Addresses a file by catalog id + file name (defaults to the first tabular file on the resolved record). Ops:

  • schema — column names + types (reads the Parquet footer / sniffs the CSV header; no full load).

  • preview — a small sample of rows.

  • head — the first n rows (default 20), optionally restricted to columns.

  • sql — a read-only SELECT (the file is the view data), e.g. SELECT col, count(*) FROM data GROUP BY 1.

  • peek — per-column profile via DuckDB SUMMARIZE (type, null-rate, approximate distinct count, min/max, numeric quartiles) without downloading the file. Like head/sql, reads the whole file and honors the source-size ceiling.

Backed by the Parquet footer reader + DuckDB httpfs range reads. sql runs in a locked-down DuckDB (read-only, local filesystem disabled, single-SELECT validation, row / wall-clock caps). Requires the optional [operate] extra (pip install data-aggregator-mcp[operate]); without it, operate returns a clear install-the-extra message and the other four tools are unaffected.

Any HuggingFace dataset with a datasets-server converted view is operable (schema / preview / head / sql): resolve surfaces the auto-converted Parquet files (source="hf-datasets-server") even for datasets stored as JSON/JSONL/arrow, so pass file=<config>/<split>/...parquet to pick a split when there are several.

relate(ids)

Cross-resource join/harmonization hints. Given 2–10 resource ids, relate resolves each (TTL-cached) and reports how they relate and on what key they could be joined:

  • shared_accession — same BioProject/SRA/GEO accession on ≥2 records → joinable key.

  • shared_identifier — same doi/pmid/pmcid across records → same work / paper↔data link.

  • explicit_link — one record's links[] points at another input record.

  • version_lineage — one record supersedes another (dedupe, don't join, those).

Hints only. relate never reads file columns, fetches files, or executes a join/merge/conversion — every hint names the shared value as evidence. Per-id resolve failures are reported in errors, not fatal; an empty result carries an explanatory note.

Prompts

Three workflow prompts surface in clients (e.g. /mcp__data_aggregator__* in Claude Code):

  • find_data — find datasets for a topic, optionally scoped to an organism.

  • data_behind_paper — find the datasets / accessions behind a paper.

  • search_resolve_fetch — walk the end-to-end search → resolve → fetch flow.

⚙️ Configuration

All optional, set via environment variables:

  • NCBI_API_KEY — raises the NCBI E-utilities rate limit (3 → 10 req/s) used by the omics, literature, and taxonomy lookups.

  • DATA_GOV_API_KEY — a free api.data.gov key for the data.gov source. Absent ⇒ requests fall back to the shared public DEMO_KEY, rate-limited to roughly 30 requests/hour per IP — fine for light discovery, worth setting for anything heavier.

  • UNPAYWALL_EMAIL — enables the Unpaywall fallback leg of literature full-text retrieval (the EuropePMC leg works without it).

  • NCBI_EMAIL — contact address sent to NCBI's ID converter; falls back to UNPAYWALL_EMAIL when unset.

  • DATAVERSE_BASE_URL — resolve Dataverse DOIs against a different installation (default https://dataverse.harvard.edu).

  • CACHE_TTL_SECONDS — resolve-cache lifetime in seconds (default 3600; an unparseable value falls back to that default).

  • EMBEDDING_API_BASE / EMBEDDING_API_KEY / EMBEDDING_MODEL — an OpenAI-compatible embeddings endpoint enabling rank=semantic. Absent ⇒ semantic re-rank degrades to relevance order. Key is optional (keyless local servers supported); model defaults to text-embedding-3-small.

  • LLM_API_BASE / LLM_API_KEY / LLM_MODEL — an OpenAI-compatible /chat/completions endpoint enabling search(understand=true) (NL→structured query rewriting) and search(multi_query=true) (diverse multi-query recall expansion). Absent ⇒ both run the raw query unchanged and note it in errors['understand'] / errors['multi_query']. Key is optional (keyless local servers supported); model defaults to gpt-4o-mini (a passthrough string — set it to whatever your endpoint serves). multi_query fans out at most MAX_QUERY_VARIANTS (4, incl. the original) variants, bounding the N× cost.

To measure the recall lift of understand=true / multi_query=true on a small labeled set, run the gated eval harnesses (need a live LLM endpoint):

DATA_AGGREGATOR_MCP_LIVE=1 LLM_API_BASE=... python scripts/eval_understand.py
DATA_AGGREGATOR_MCP_LIVE=1 LLM_API_BASE=... python scripts/eval_multi_query.py

They print per-query and mean recall@20 (understand / multi-query off vs. on). See the fixtures at scripts/eval_understand_fixture.json and scripts/eval_multi_query_fixture.json.

🧪 Develop

uv venv && uv pip install -e ".[dev]"
uv run pytest -q
uv run ruff check src tests
DATA_AGGREGATOR_MCP_LIVE=1 uv run pytest -k live -q   # real-API probes

The README demo (examples/assets/demo.svg) is recorded network-free from examples/_demo_stdio.py — see the header of that file to re-record.

License

MIT — see LICENSE.

Available Tools

6 tools
fetchA

Download a resource's files to local disk and return the PATHS (never the file contents). Fetchable backends: Zenodo (md5-verified); SRA via ENA FASTQ (md5-verified); GEO supplementary files (unverified); DataCite sub-repos — Figshare/Dataverse/OSF (md5-verified), OpenNeuro (snapshot manifest, unverified), Dryad is manifest-only (resolve lists files, fetch fails loud), Mendeley + other DataCite repos fail loud; PubMed/OpenAIRE open-access full text (EuropePMC XML / Unpaywall PDF, unverified); HuggingFace Hub (unverified); DataONE Member-Node objects (md5/SHA-256-verified); OmicsDI — PRIDE + MetaboLights only (unverified), MassIVE/GNPS/PeptideAtlas/Metabolomics Workbench fail loud; DANDI dandisets (302→S3, unverified); CZ CELLxGENE H5AD/RDS assets (unverified); OpenML ARFF (md5-verified); RCSB PDB .cif/.pdb structure files (unverified). Fails loud if selected files exceed max_bytes unless force=true. Verifies checksums; writes a .dataresource.json sidecar.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesSource-prefixed id or bare Zenodo id
destNoDestination dir (default managed cache)
filesNoGlob over file names (default all)
forceNoOverride max_bytes
extractNoUnpack downloaded zip/tar archives into the destination (default false). Path-traversal-guarded; counts against max_bytes.
max_bytesNoByte ceiling before failing loud

Output Schema

ParametersJSON Schema
NameRequiredDescription
bytesNo
pathsNo
resumedNo
skippedNo
unverifiedNo

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavioral context beyond annotations: it describes checksum verification, sidecar writing, failure behavior on size/backends, and unverified sources. There is no contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-organized: it front-loads the core purpose, then lists backends with verification status, then general behavior. Every sentence adds information, though it could be slightly more concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (many backends, multiple parameters, output schema exists), the description is comprehensive. It covers backend-specific behavior, failure modes, sidecar file, and checksum verification, with no obvious gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters. The description adds global context about 'max_bytes' and 'force' but does not significantly enhance individual parameter semantics beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it downloads a resource's files to local disk and returns paths, not contents. It lists specific backends, distinguishing this tool from siblings like search or resolve.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit context about when to use this tool (e.g., downloading from various backends) and mentions failure conditions (e.g., Dryad, Mendeley). However, it does not explicitly state when not to use it or suggest alternatives beyond naming sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_sourcesA
Read-only

List wired data sources and their capabilities (layer, kinds, supported filters, auth requirement, rate limit, status).

ParametersJSON Schema
NameRequiredDescriptionDefault
check_healthNoWhen true, probe 5 sources (zenodo, datacite, omics, literature, huggingface) and attach a 'health' field ({status: up|down, latency_ms, detail}) to those entries; every other source gets health: null. Default false: returns the static catalog with no network.

Output Schema

ParametersJSON Schema
NameRequiredDescription
sourcesYes

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=true, and the description adds capabilities context. However, it omits the dynamic health probe behavior triggered by check_health parameter, which is a behavioral trait beyond the static listing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, well-structured sentence of 12 words, front-loading the action. Every word adds value without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple list tool with an output schema and one optional parameter, the description covers the main function. It could mention the optional health probing for completeness, but overall it is adequate.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% (one parameter with full description). The tool description adds no additional meaning beyond the schema for the parameter, meeting the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'List wired data sources and their capabilities' with a specific verb and resource. It distinguishes from siblings like search, resolve, fetch, and operate, which imply different actions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides the primary action but lacks explicit guidance on when to use this tool vs alternatives. There is no 'when not to use' or mention of sibling tools for different use cases.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

operateA
Read-only

Inspect or query a remote tabular file (Parquet/CSV/TSV) WITHOUT downloading it. op='schema' returns columns+types; 'preview' a small sample; 'head' the first n rows; 'sql' a read-only SELECT against the file (exposed as the view 'data', e.g. "SELECT * FROM data WHERE x > 1"). op='peek' profiles every column WITHOUT downloading — type, null-rate, approximate distinct count, min/max, and numeric quartiles (a DuckDB SUMMARIZE; like head/sql it reads the whole file, so it honors the source-size ceiling). Addresses a file by catalog id + file name (resolve the id first to see files[] and access_modes). Requires the [operate] extra; fails loud if the file is not an operable tabular file.

ParametersJSON Schema
NameRequiredDescriptionDefault
nNoRow count for head/preview
idYesDataResource id (e.g. 'zenodo:7654321')
opYes
fileNoFile name within the record; optional when exactly one operable file is present.
queryNoRead-only SELECT for op='sql'.
columnsNoOptional column projection for head.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=true, and the description adds details: peek uses DuckDB SUMMARIZE, reads whole file, honors source-size ceiling; sql is read-only using view 'data'; failures documented. No contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is informative but slightly verbose; each sentence adds value but could be tightened. Front-loaded with purpose, then operations, then prerequisites.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 5 operations, 6 parameters, and no output schema, the description adequately covers all ops, parameter usage, prerequisites, failure modes, and links to other tools (resolve). Indirectly describes return types.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema covers 5/6 params (83%) with descriptions; the description adds meaning by explaining each op value, file addressing by catalog id + file name, default n=20, and sql view 'data'. Adds significant value beyond schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it inspects/queries remote tabular files without downloading, lists five specific operations (schema, preview, head, sql, peek), and distinguishes from siblings like fetch (download) and resolve (ID lookup).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says when to use (inspect/query without download), prerequisites (resolve id first, need [operate] extra), failure conditions (fails if not operable), and hints at alternatives via sibling context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

relateA
Read-only

Given 2-10 resource ids, return metadata-level join/harmonization HINTS: how the datasets relate and on what key they could be joined. Detects shared accessions (BioProject/SRA/GEO), shared cross-identifiers (doi/pmid/pmcid), explicit links between the inputs, and version lineage. HINTS ONLY — it does not read file columns, fetch files, or execute any join/merge/conversion; each hint names the shared value as evidence. Resolve ids first if you only have a search result. Per-id resolve failures are reported, not fatal.

ParametersJSON Schema
NameRequiredDescriptionDefault
idsYes2-10 source-prefixed resource ids to relate.

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNo
hintsNo
errorsNo
resolvedYes
input_idsYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes beyond the readOnlyHint annotation by detailing exactly what the tool does (detect shared accessions, cross-identifiers, explicit links, version lineage) and what it does not do (read file columns, fetch files, execute join/merge/conversion). No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, well-structured, and front-loaded with the core functionality. Every sentence adds necessary information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of detecting relationships between resources, the description covers all essential aspects: purpose, input constraints, types of relationships detected, what is not done, and behavior on failures. An output schema exists, so return values need not be detailed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%. The description adds context that the ids are 'source-prefixed' and explains the purpose ('resource ids to relate'). It also reiterates the min and max items, adding value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it returns 'metadata-level join/harmonization HINTS' for given resource ids, specifying the types of relationships detected (shared accessions, cross-identifiers, explicit links, version lineage) and what it does not do. This distinguishes it from siblings like list_sources, fetch, and operate.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description specifies the input range (2-10 ids) and advises to resolve ids first if only a search result is available. It also clarifies that per-id failures are reported and not fatal. While it doesn't explicitly state when not to use, the context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

resolveA
Read-only

Fetch the full DataResource for a known id (e.g. 'zenodo:7654321', 'datacite:10.5061/dryad.x', 'hf:owner/name', a bare Zenodo record id, or a DOI), including the complete files[] manifest. Publication resolve also attaches normalized identifiers (pmid/pmcid/doi) and, when open access, a full-text file. Pass cite= to render a citation onto the result (citation field); omitted means no citation. Pass trust=true to attach retraction status (via Crossref) under trust{}. Pass fair=true to attach an RDA-grounded FAIRness score (0–100 + F/A/I/R sub-scores + actionable gaps) computed from the record under fair{}. Pass use= (commercial/redistribute/modify/ml-training) to attach a licence-compatibility advisory (ALLOW/REVIEW/DENY, not legal advice) under license_compat{}. Pass format=provenance for a one-call RO-Crate 1.1 data-availability dossier (under provenance{}) composing version-currency, licence+SPDX, FAIR score, retraction status, and the source/DOI/ID chain — it auto-attaches fair + trust.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesSource-prefixed id, bare Zenodo id, or DOI
useNoWhen set, attach a licence-compatibility advisory under license_compat{} for an intended use of the record. Supported intents: 'commercial', 'redistribute', 'modify', 'ml-training' (training = a derivative+commercial use, our stated interpretation). The verdict is ALLOW/REVIEW/DENY computed from a bundled choosealicense.com licence matrix keyed on the normalized SPDX id, naming the governing clause — a metadata-derived advisory, NOT legal advice. An unrecognized or absent licence yields REVIEW (never a fabricated ALLOW/DENY); an unknown intent is an error.
citeNoOptional citation format to render onto the result: 'bibtex', 'ris', 'csl-json', or any CSL style name ('apa', 'mla', 'vancouver', ...). DOI-bearing records render via DOI content negotiation; non-DOI records support 'csl-json' only. Omitted = no citation. Failures degrade quietly (citation stays null).
fairNoWhen true, attach an RDA-grounded FAIRness assessment under fair{}: a 0–100 overall score plus findable/accessible/interoperable/reusable sub-scores, the count of indicators evaluated, and actionable gaps each naming its RDA FAIR Data Maturity Model indicator id. Pure/local — no network call. Only the machine-evaluable subset is scored (never fabricates what the metadata cannot show).
trustNoWhen true, attach trust signals (retraction status via Crossref) to the result under trust{}. One extra Crossref call; only meaningful for DOI-bearing records (a DataCite data DOI Crossref does not register leaves retracted=null = unknown, never a false clean claim).
formatNoOptional export to render onto the result. 'croissant' attaches a file-level Croissant JSON-LD manifest (croissant field); 'ro-crate' attaches a minimal RO-Crate 1.1 manifest (ro_crate field); 'provenance' attaches a one-call RO-Crate 1.1 data-availability dossier (provenance field) bundling version-currency, licence+SPDX, FAIR score, retraction status, and the source/DOI/ID chain — it auto-attaches fair{} and trust{} so the dossier is complete in one call (unknown signals are reported as unknown, never as a clean claim).

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
doiNo
fairNo
kindYes
taxaNo
yearNo
filesNo
linksNo
titleYes
trustNo
accessNo
sourceYes
fundingNo
licenseNo
metricsNo
mirrorsNo
citationNo
creatorsNo
organismNo
ro_crateNo
subjectsNo
croissantNo
is_latestNo
accessionsNo
provenanceNo
descriptionNo
identifiersNo
access_modesNo
last_updatedNo
superseded_byNo
license_compatNo

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint=true annotation, the description details behaviors of all optional parameters (e.g., 'fair is pure/local, no network call', 'trust only for DOI-bearing records', 'failures degrade quietly') and explains auto-attachment in provenance mode, offering comprehensive transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and efficiently lists parameters with concise explanations. Though lengthy, it packs necessary detail without redundancy. Slightly more brevity could improve score.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (6 parameters, optional nested outputs) and the presence of an output schema, the description covers all intended behaviors and edge cases. It does not explicitly describe the base return structure, but output schema likely fills that gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, providing baseline 3. The description adds extra context for each parameter (e.g., 'use' explains verdict logic and matrix, 'cite' lists supported formats and fallbacks), elevating clarity beyond the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Fetch the full DataResource for a known id', providing a specific verb and resource, and includes example IDs, which clearly defines the tool's purpose and distinguishes it from siblings like search (query-based) and fetch (likely simpler).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The intended usage (resolve by known ID) is implicit from the purpose, but the description does not explicitly contrast with siblings or state when not to use it. No exclusions or alternative tool mentions are provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev0.45.3
    • Changedfetch1 field changed
      • addedOutput schema / properties / unverified
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "title": "Unverified",
        +  "type": "array"
        +}
  2. 2 tool updatesv0.45.1
    • Addedresolve
    • Addedsearch
  3. 3 tool updatesv0.43.0
    • Addedrelate
    • Removedresolve
    • Removedsearch
  4. 3 tool updatesv0.42.0
    • Changedlist_sources1 field changed
      • changedInput schema / properties / check_health / description
        Previous value: -"When true, probe 5 sources (zenodo, datacite, omics, literature, huggingface) and attach a 'health' field ({status: up|down, latency_ms, detail}) to those entries; the remaining 7 sources get health: null. Default false: returns the static catalog with no network."New value: +"When true, probe 5 sources (zenodo, datacite, omics, literature, huggingface) and attach a 'health' field ({status: up|down, latency_ms, detail}) to those entries; every other source gets health: null. Default false: returns the static catalog with no network."
    • Removedrelate
    • Changedsearch4 fields changed
      • changedInput schema / properties / sources / description
        Previous value: -"Restrict fan-out to these sources (default: all). Available: zenodo, dataone, cellxgene, datacite, dandi, omics, literature, huggingface, omicsdi, openml, pdb, uniprot, gwas"New value: +"Restrict fan-out to these sources (default: all). Available: zenodo, dataone, gbif, cellxgene, datacite, dandi, omics, literature, huggingface, datagov, nasacmr, omicsdi, openml, pdb, uniprot, gwas, biostudies"
      • addedOutput schema / $defs / QueryUnderstanding / properties / confidence
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Confidence"
        +}
      • addedOutput schema / $defs / UnresolvedEntity
        Added value: +{
        +  "description": "Echo of an ontology-typed search param that was supplied but matched NO term,\nso the query ran WITHOUT that expansion.\n\nDistinct from ``SearchResult.errors``: an entry there means the ontology LOOKUP\nFAILED (HTTP/parse) and the two are mutually exclusive per field. An entry here\nmeans the lookup SUCCEEDED and legitimately returned no match — the common case\nfor a common name the registry does not index (NCBI Taxonomy has no ``yeast``,\n``oak`` or ``cedar``; UBERON has no bare ``root``).\n\nWithout this echo the response for a silently-dropped param is byte-identical to\none where the param was never passed, so the caller cannot tell that the filter\nthey asked for was not applied.",
        +  "properties": {
        +    "field": {
        +      "title": "Field",
        +      "type": "string"
        +    },
        +    "input": {
        +      "title": "Input",
        +      "type": "string"
        +    },
        +    "note": {
        +      "title": "Note",
        +      "type": "string"
        +    },
        +    "ontology": {
        +      "title": "Ontology",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "field",
        +    "input",
        +    "ontology",
        +    "note"
        +  ],
        +  "title": "UnresolvedEntity",
        +  "type": "object"
        +}
      • addedOutput schema / properties / unresolved
        Added value: +{
        +  "items": {
        +    "$ref": "#/$defs/UnresolvedEntity"
        +  },
        +  "title": "Unresolved",
        +  "type": "array"
        +}
  5. 1 tool updatev0.41.1
    • Changedsearch1 field changed
      • changedInput schema / properties / sources / description
        Previous value: -"Restrict fan-out to these sources (default: all). Available: zenodo, dataone, cellxgene, datacite, dandi, omics, literature, huggingface, omicsdi, openml, pdb, gwas"New value: +"Restrict fan-out to these sources (default: all). Available: zenodo, dataone, cellxgene, datacite, dandi, omics, literature, huggingface, omicsdi, openml, pdb, uniprot, gwas"
  6. 5 tool updatesv0.40.0
    • Changedlist_sources1 field changed
      • changedInput schema / properties / check_health / description
        Previous value: -"When true, probe each source's base endpoint and attach a 'health' field ({status: up|down, latency_ms, detail}) to each source. Default false: returns the static catalog with no network."New value: +"When true, probe 5 sources (zenodo, datacite, omics, literature, huggingface) and attach a 'health' field ({status: up|down, latency_ms, detail}) to those entries; the remaining 7 sources get health: null. Default false: returns the static catalog with no network."
    • Changedoperate1 field changed
      • changedInput schema / properties / op / enum
        Previous value: -[
        -  "schema",
        -  "preview",
        -  "head",
        -  "sql"
        -]New value: +[
        +  "schema",
        +  "preview",
        +  "head",
        +  "sql",
        +  "peek"
        +]
    • Addedrelate
    • Changedresolve14 fields changed
      • addedInput schema / properties / fair
        Added value: +{
        +  "description": "When true, attach an RDA-grounded FAIRness assessment under fair{}: a 0–100 overall score plus findable/accessible/interoperable/reusable sub-scores, the count of indicators evaluated, and actionable gaps each naming its RDA FAIR Data Maturity Model indicator id. Pure/local — no network call. Only the machine-evaluable subset is scored (never fabricates what the metadata cannot show).",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / format / description
        Previous value: -"Optional export to render onto the result. 'croissant' attaches a file-level Croissant JSON-LD manifest (croissant field); 'ro-crate' attaches a minimal RO-Crate 1.1 manifest (ro_crate field)."New value: +"Optional export to render onto the result. 'croissant' attaches a file-level Croissant JSON-LD manifest (croissant field); 'ro-crate' attaches a minimal RO-Crate 1.1 manifest (ro_crate field); 'provenance' attaches a one-call RO-Crate 1.1 data-availability dossier (provenance field) bundling version-currency, licence+SPDX, FAIR score, retraction status, and the source/DOI/ID chain — it auto-attaches fair{} and trust{} so the dossier is complete in one call (unknown signals are reported as unknown, never as a clean claim)."
      • changedInput schema / properties / format / enum
        Previous value: -[
        -  "croissant",
        -  "ro-crate"
        -]New value: +[
        +  "croissant",
        +  "ro-crate",
        +  "provenance"
        +]
      • addedInput schema / properties / trust
        Added value: +{
        +  "description": "When true, attach trust signals (retraction status via Crossref) to the result under trust{}. One extra Crossref call; only meaningful for DOI-bearing records (a DataCite data DOI Crossref does not register leaves retracted=null = unknown, never a false clean claim).",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / use
        Added value: +{
        +  "description": "When set, attach a licence-compatibility advisory under license_compat{} for an intended use of the record. Supported intents: 'commercial', 'redistribute', 'modify', 'ml-training' (training = a derivative+commercial use, our stated interpretation). The verdict is ALLOW/REVIEW/DENY computed from a bundled choosealicense.com licence matrix keyed on the normalized SPDX id, naming the governing clause — a metadata-derived advisory, NOT legal advice. An unrecognized or absent licence yields REVIEW (never a fabricated ALLOW/DENY); an unknown intent is an error.",
        +  "type": "string"
        +}
      • addedOutput schema / $defs / FairAssessment
        Added value: +{
        +  "description": "FAIRness assessment attached on resolve(fair=True). PURE-function output:\na 0–100 overall score plus 0–100 per-dimension sub-scores, grounded in the\nmachine-evaluable subset of the RDA FAIR Data Maturity Model. ``assessed`` is\nthe count of indicators actually evaluated (transparency — we never score what\nthe metadata can't show). ``gaps`` are failed-indicator reasons, each naming its\nRDA indicator id and framed as a metadata-exposure gap, not a value judgement.",
        +  "properties": {
        +    "accessible": {
        +      "title": "Accessible",
        +      "type": "integer"
        +    },
        +    "assessed": {
        +      "title": "Assessed",
        +      "type": "integer"
        +    },
        +    "findable": {
        +      "title": "Findable",
        +      "type": "integer"
        +    },
        +    "gaps": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "title": "Gaps",
        +      "type": "array"
        +    },
        +    "interoperable": {
        +      "title": "Interoperable",
        +      "type": "integer"
        +    },
        +    "reusable": {
        +      "title": "Reusable",
        +      "type": "integer"
        +    },
        +    "score": {
        +      "title": "Score",
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "score",
        +    "findable",
        +    "accessible",
        +    "interoperable",
        +    "reusable",
        +    "assessed"
        +  ],
        +  "title": "FairAssessment",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / LicenseVerdict
        Added value: +{
        +  "description": "Licence-compatibility advisory attached on resolve(use=<intent>). PURE-function\noutput: an ALLOW / REVIEW / DENY verdict for an intended use of the resolved record,\ncomputed from a bundled licence matrix (choosealicense.com flag vocabulary) keyed on\nthe normalized SPDX id. ``spdx_id`` is None exactly when the licence was unrecognized\nor absent (→ REVIEW, never a fabricated ALLOW/DENY). ``reason`` names the governing\nclause; ``disclaimer`` states this is a metadata-derived advisory, not legal advice.",
        +  "properties": {
        +    "disclaimer": {
        +      "title": "Disclaimer",
        +      "type": "string"
        +    },
        +    "license_raw": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "License Raw"
        +    },
        +    "reason": {
        +      "title": "Reason",
        +      "type": "string"
        +    },
        +    "spdx_id": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Spdx Id"
        +    },
        +    "use": {
        +      "title": "Use",
        +      "type": "string"
        +    },
        +    "verdict": {
        +      "enum": [
        +        "ALLOW",
        +        "REVIEW",
        +        "DENY"
        +      ],
        +      "title": "Verdict",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "use",
        +    "verdict",
        +    "spdx_id",
        +    "license_raw",
        +    "reason",
        +    "disclaimer"
        +  ],
        +  "title": "LicenseVerdict",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / Mirror
        Added value: +{
        +  "description": "A same-dataset copy folded into this record by content dedup (resolve the\nmirror's id to reach the original deposit). Only populated when a search ran\nwith the opt-in ``collapse_mirrors`` flag.",
        +  "properties": {
        +    "doi": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Doi"
        +    },
        +    "id": {
        +      "title": "Id",
        +      "type": "string"
        +    },
        +    "source": {
        +      "title": "Source",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "source",
        +    "id"
        +  ],
        +  "title": "Mirror",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / TrustSignals
        Added value: +{
        +  "description": "Integrity/provenance signals attached on resolve(trust=True). All nullable:\nNone = not checked or not determinable (e.g. a DOI Crossref doesn't register) —\nNEVER a negative claim. A *found* Crossref work yields definitive booleans.",
        +  "properties": {
        +    "concern": {
        +      "anyOf": [
        +        {
        +          "type": "boolean"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Concern"
        +    },
        +    "retracted": {
        +      "anyOf": [
        +        {
        +          "type": "boolean"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Retracted"
        +    },
        +    "retraction_doi": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Retraction Doi"
        +    }
        +  },
        +  "title": "TrustSignals",
        +  "type": "object"
        +}
      • addedOutput schema / properties / fair
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/FairAssessment"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / license_compat
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/LicenseVerdict"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / mirrors
        Added value: +{
        +  "items": {
        +    "$ref": "#/$defs/Mirror"
        +  },
        +  "title": "Mirrors",
        +  "type": "array"
        +}
      • addedOutput schema / properties / provenance
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Provenance"
        +}
      • addedOutput schema / properties / trust
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/TrustSignals"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
    • Changedsearch31 fields changed
      • addedInput schema / properties / assay
        Added value: +{
        +  "description": "Optional assay/method name. Resolved via EDAM topics (EBI OLS); the query is expanded with the canonical name + exact synonyms (e.g. 'ChIP-seq' also matches 'ChIP-sequencing'/'ChIP-exo'). An unknown term yields no expansion; an OLS failure surfaces in errors. The expansion is echoed in assay_expansion.",
        +  "type": "string"
        +}
      • addedInput schema / properties / chemical
        Added value: +{
        +  "description": "Optional chemical/compound name. Resolved via ChEBI (EBI OLS); the query is expanded with the canonical name + exact synonyms (e.g. 'caffeine' also matches '1,3,7-trimethylxanthine'), capped to a bounded number of synonyms. An unknown term yields no expansion; an OLS failure surfaces in errors. The expansion is echoed in chemical_expansion.",
        +  "type": "string"
        +}
      • addedInput schema / properties / collapse_mirrors
        Added value: +{
        +  "default": false,
        +  "description": "Opt into conservative cross-repo content dedup (default false). On top of the always-on exact-DOI dedup, folds records that are the SAME dataset deposited under different (or no) DOIs — e.g. a Zenodo mirror of a figshare deposit, GEO<->ArrayExpress — into one record, annotating the survivor with the folded copies under mirrors[]. Conservative: a merge needs a shared file checksum OR identical (normalized-title, first-author-surname, year); title-only or partial matches never merge. Intra-page / best-effort only (a mirror on a different page is not collapsed), so a page may return fewer than size items; pagination is unaffected.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / disease
        Added value: +{
        +  "description": "Optional disease/phenotype name. Resolved via MeSH (NCBI E-utilities); the query is expanded with the canonical descriptor + entry-term synonyms (e.g. 'breast cancer' also matches 'Breast Neoplasms'). The expansion is echoed in mesh_expansion.",
        +  "type": "string"
        +}
      • addedInput schema / properties / multi_query
        Added value: +{
        +  "default": false,
        +  "description": "Opt into diverse multi-query recall expansion: an LLM generates up to a few deliberately-diverse reformulations of your query, each is fanned out across all sources, and the deduped union is re-ranked against your original query — surfacing relevant records a single keyword query would miss. Costs N× the upstream calls (bounded). Requires an LLM endpoint (LLM_API_BASE); with none configured the search runs as a normal single query and notes it in errors['multi_query']. The variants used are echoed in query_expansion. Composes with understand=. NOTE: multi_query=true ALWAYS applies semantic re-ranking of the window internally regardless of rank=; the rank= param has no effect in this mode.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / provenance
        Added value: +{
        +  "default": false,
        +  "description": "Opt into a whole-search RO-Crate 1.1 Run Crate (default false). Attaches provenance_crate{} — a machine-readable manifest documenting this search: the query, the sources queried, the ontology expansions that fired, the per-source errors (a partial search is disclosed), and per-hit provenance for every result (version-currency, licence + normalized SPDX, FAIR score). Per-hit RETRACTION is omitted — it would need one Crossref call per hit; use per-record resolve(format=provenance) for that. Covers THIS search page only (intra-page; each page of a paginated search gets its own crate).",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / sources / description
        Previous value: -"Restrict fan-out to these sources (default: all). Available: zenodo, datacite, omics, literature, huggingface, dataone, omicsdi"New value: +"Restrict fan-out to these sources (default: all). Available: zenodo, dataone, cellxgene, datacite, dandi, omics, literature, huggingface, omicsdi, openml, pdb, gwas"
      • addedInput schema / properties / tissue
        Added value: +{
        +  "description": "Optional tissue/anatomy name. Resolved via UBERON (EBI OLS); the query is expanded with the canonical term + exact synonyms (e.g. 'liver' also matches 'iecur'/'jecur'). The expansion is echoed in tissue_expansion.",
        +  "type": "string"
        +}
      • addedInput schema / properties / understand
        Added value: +{
        +  "default": false,
        +  "description": "Opt into LLM query understanding: a free-text query is rewritten into a keyword core + structured params (organism/disease/tissue/chemical/assay, kind, year) before fan-out; extracted entities are validated by the same ontology resolvers (a hallucinated entity that doesn't resolve is simply dropped), explicit params you pass always win, and the interpretation is echoed in query_understanding. Requires an LLM endpoint (LLM_API_BASE); with none configured the search runs unchanged and notes it in errors['understand'].",
        +  "type": "boolean"
        +}
      • addedOutput schema / $defs / AssayExpansion
        Added value: +{
        +  "description": "Echo of EDAM assay-synonym expansion that fired for a search (transparency).",
        +  "properties": {
        +    "canonical_name": {
        +      "title": "Canonical Name",
        +      "type": "string"
        +    },
        +    "edam_id": {
        +      "title": "Edam Id",
        +      "type": "string"
        +    },
        +    "input": {
        +      "title": "Input",
        +      "type": "string"
        +    },
        +    "synonyms": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "title": "Synonyms",
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "input",
        +    "edam_id",
        +    "canonical_name",
        +    "synonyms"
        +  ],
        +  "title": "AssayExpansion",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / ChemicalExpansion
        Added value: +{
        +  "description": "Echo of ChEBI chemical-synonym expansion that fired for a search (transparency).",
        +  "properties": {
        +    "canonical_name": {
        +      "title": "Canonical Name",
        +      "type": "string"
        +    },
        +    "chebi_id": {
        +      "title": "Chebi Id",
        +      "type": "string"
        +    },
        +    "input": {
        +      "title": "Input",
        +      "type": "string"
        +    },
        +    "synonyms": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "title": "Synonyms",
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "input",
        +    "chebi_id",
        +    "canonical_name",
        +    "synonyms"
        +  ],
        +  "title": "ChemicalExpansion",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / DataResource / properties / fair
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/FairAssessment"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / $defs / DataResource / properties / license_compat
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/LicenseVerdict"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / $defs / DataResource / properties / mirrors
        Added value: +{
        +  "items": {
        +    "$ref": "#/$defs/Mirror"
        +  },
        +  "title": "Mirrors",
        +  "type": "array"
        +}
      • addedOutput schema / $defs / DataResource / properties / provenance
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Provenance"
        +}
      • addedOutput schema / $defs / DataResource / properties / trust
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/TrustSignals"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / $defs / FairAssessment
        Added value: +{
        +  "description": "FAIRness assessment attached on resolve(fair=True). PURE-function output:\na 0–100 overall score plus 0–100 per-dimension sub-scores, grounded in the\nmachine-evaluable subset of the RDA FAIR Data Maturity Model. ``assessed`` is\nthe count of indicators actually evaluated (transparency — we never score what\nthe metadata can't show). ``gaps`` are failed-indicator reasons, each naming its\nRDA indicator id and framed as a metadata-exposure gap, not a value judgement.",
        +  "properties": {
        +    "accessible": {
        +      "title": "Accessible",
        +      "type": "integer"
        +    },
        +    "assessed": {
        +      "title": "Assessed",
        +      "type": "integer"
        +    },
        +    "findable": {
        +      "title": "Findable",
        +      "type": "integer"
        +    },
        +    "gaps": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "title": "Gaps",
        +      "type": "array"
        +    },
        +    "interoperable": {
        +      "title": "Interoperable",
        +      "type": "integer"
        +    },
        +    "reusable": {
        +      "title": "Reusable",
        +      "type": "integer"
        +    },
        +    "score": {
        +      "title": "Score",
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "score",
        +    "findable",
        +    "accessible",
        +    "interoperable",
        +    "reusable",
        +    "assessed"
        +  ],
        +  "title": "FairAssessment",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / LicenseVerdict
        Added value: +{
        +  "description": "Licence-compatibility advisory attached on resolve(use=<intent>). PURE-function\noutput: an ALLOW / REVIEW / DENY verdict for an intended use of the resolved record,\ncomputed from a bundled licence matrix (choosealicense.com flag vocabulary) keyed on\nthe normalized SPDX id. ``spdx_id`` is None exactly when the licence was unrecognized\nor absent (→ REVIEW, never a fabricated ALLOW/DENY). ``reason`` names the governing\nclause; ``disclaimer`` states this is a metadata-derived advisory, not legal advice.",
        +  "properties": {
        +    "disclaimer": {
        +      "title": "Disclaimer",
        +      "type": "string"
        +    },
        +    "license_raw": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "License Raw"
        +    },
        +    "reason": {
        +      "title": "Reason",
        +      "type": "string"
        +    },
        +    "spdx_id": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Spdx Id"
        +    },
        +    "use": {
        +      "title": "Use",
        +      "type": "string"
        +    },
        +    "verdict": {
        +      "enum": [
        +        "ALLOW",
        +        "REVIEW",
        +        "DENY"
        +      ],
        +      "title": "Verdict",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "use",
        +    "verdict",
        +    "spdx_id",
        +    "license_raw",
        +    "reason",
        +    "disclaimer"
        +  ],
        +  "title": "LicenseVerdict",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / MeshExpansion
        Added value: +{
        +  "description": "Echo of MeSH-synonym expansion that fired for a search (transparency).",
        +  "properties": {
        +    "canonical_name": {
        +      "title": "Canonical Name",
        +      "type": "string"
        +    },
        +    "input": {
        +      "title": "Input",
        +      "type": "string"
        +    },
        +    "mesh_ui": {
        +      "title": "Mesh Ui",
        +      "type": "string"
        +    },
        +    "synonyms": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "title": "Synonyms",
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "input",
        +    "mesh_ui",
        +    "canonical_name",
        +    "synonyms"
        +  ],
        +  "title": "MeshExpansion",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / Mirror
        Added value: +{
        +  "description": "A same-dataset copy folded into this record by content dedup (resolve the\nmirror's id to reach the original deposit). Only populated when a search ran\nwith the opt-in ``collapse_mirrors`` flag.",
        +  "properties": {
        +    "doi": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Doi"
        +    },
        +    "id": {
        +      "title": "Id",
        +      "type": "string"
        +    },
        +    "source": {
        +      "title": "Source",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "source",
        +    "id"
        +  ],
        +  "title": "Mirror",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / QueryExpansion
        Added value: +{
        +  "description": "Transparency echo of A2.P2 multi-query recall expansion (search multi_query=true).\n\nWhen enabled and an LLM endpoint is configured, the LLM generates deliberately-diverse\nreformulations of the query; each variant is fanned out across all sources, and the\ndeduped union is re-ranked against the ORIGINAL query. ``variants`` lists the RAW variants\nactually fanned out, the original query first. Each variant received the same ontology\nexpansion (shown by the ``*_expansion`` echoes); results are the deduped union re-ranked\nagainst ``input``.",
        +  "properties": {
        +    "input": {
        +      "title": "Input",
        +      "type": "string"
        +    },
        +    "variants": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "title": "Variants",
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "input",
        +    "variants"
        +  ],
        +  "title": "QueryExpansion",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / QueryUnderstanding
        Added value: +{
        +  "description": "Echo of the LLM query-understanding rewrite that fired (transparency, A2.P1).\n\nThe LLM proposes; explicit caller params win; the ontology resolvers then VALIDATE the\nproposed entities. ``applied`` lists the fields the caller left None that were FED into\nthis search as parameters — for ontology entities (organism/disease/tissue/chemical/\nassay) this means \"passed to the resolver\", NOT \"resolved\": whether it actually expanded\nis shown by the corresponding ``*_expansion`` echo (None there ⇒ the entity did not\nresolve, and was never silently treated as a match). ``overridden`` lists fields the LLM\nproposed but the caller had set explicitly (so the LLM's value was ignored).",
        +  "properties": {
        +    "applied": {
        +      "additionalProperties": true,
        +      "title": "Applied",
        +      "type": "object"
        +    },
        +    "extracted": {
        +      "additionalProperties": true,
        +      "title": "Extracted",
        +      "type": "object"
        +    },
        +    "input": {
        +      "title": "Input",
        +      "type": "string"
        +    },
        +    "keyword_core": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "title": "Keyword Core"
        +    },
        +    "overridden": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "title": "Overridden",
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "input",
        +    "keyword_core"
        +  ],
        +  "title": "QueryUnderstanding",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / TissueExpansion
        Added value: +{
        +  "description": "Echo of UBERON tissue-synonym expansion that fired for a search (transparency).",
        +  "properties": {
        +    "canonical_name": {
        +      "title": "Canonical Name",
        +      "type": "string"
        +    },
        +    "input": {
        +      "title": "Input",
        +      "type": "string"
        +    },
        +    "synonyms": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "title": "Synonyms",
        +      "type": "array"
        +    },
        +    "uberon_id": {
        +      "title": "Uberon Id",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "input",
        +    "uberon_id",
        +    "canonical_name",
        +    "synonyms"
        +  ],
        +  "title": "TissueExpansion",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / TrustSignals
        Added value: +{
        +  "description": "Integrity/provenance signals attached on resolve(trust=True). All nullable:\nNone = not checked or not determinable (e.g. a DOI Crossref doesn't register) —\nNEVER a negative claim. A *found* Crossref work yields definitive booleans.",
        +  "properties": {
        +    "concern": {
        +      "anyOf": [
        +        {
        +          "type": "boolean"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Concern"
        +    },
        +    "retracted": {
        +      "anyOf": [
        +        {
        +          "type": "boolean"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Retracted"
        +    },
        +    "retraction_doi": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Retraction Doi"
        +    }
        +  },
        +  "title": "TrustSignals",
        +  "type": "object"
        +}
      • addedOutput schema / properties / assay_expansion
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/AssayExpansion"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / chemical_expansion
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/ChemicalExpansion"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / mesh_expansion
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/MeshExpansion"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / provenance_crate
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Provenance Crate"
        +}
      • addedOutput schema / properties / query_expansion
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/QueryExpansion"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / query_understanding
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/QueryUnderstanding"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / tissue_expansion
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/TissueExpansion"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
  7. 3 tool updatesv0.20.0
    • Addedoperate
    • Changedresolve9 fields changed
      • addedInput schema / properties / format
        Added value: +{
        +  "description": "Optional export to render onto the result. 'croissant' attaches a file-level Croissant JSON-LD manifest (croissant field); 'ro-crate' attaches a minimal RO-Crate 1.1 manifest (ro_crate field).",
        +  "enum": [
        +    "croissant",
        +    "ro-crate"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / $defs / Metrics
        Added value: +{
        +  "description": "Usage/impact signals, each a separate axis — NO blended score. All\nnullable: a source that does not expose an axis leaves it None.",
        +  "properties": {
        +    "citations": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Citations"
        +    },
        +    "downloads": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Downloads"
        +    },
        +    "likes": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Likes"
        +    },
        +    "views": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Views"
        +    }
        +  },
        +  "title": "Metrics",
        +  "type": "object"
        +}
      • addedOutput schema / properties / access_modes
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "title": "Access Modes",
        +  "type": "array"
        +}
      • addedOutput schema / properties / croissant
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Croissant"
        +}
      • addedOutput schema / properties / is_latest
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Is Latest"
        +}
      • addedOutput schema / properties / last_updated
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Last Updated"
        +}
      • addedOutput schema / properties / metrics
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/Metrics"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / properties / ro_crate
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Ro Crate"
        +}
      • addedOutput schema / properties / superseded_by
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Superseded By"
        +}
    • Changedsearch9 fields changed
      • changedInput schema / properties / sources / description
        Previous value: -"Restrict fan-out to these sources (default: all). Available: zenodo, datacite, omics, literature, huggingface"New value: +"Restrict fan-out to these sources (default: all). Available: zenodo, datacite, omics, literature, huggingface, dataone, omicsdi"
      • addedOutput schema / $defs / DataResource / properties / access_modes
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "title": "Access Modes",
        +  "type": "array"
        +}
      • addedOutput schema / $defs / DataResource / properties / croissant
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Croissant"
        +}
      • addedOutput schema / $defs / DataResource / properties / is_latest
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "boolean"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Is Latest"
        +}
      • addedOutput schema / $defs / DataResource / properties / last_updated
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Last Updated"
        +}
      • addedOutput schema / $defs / DataResource / properties / metrics
        Added value: +{
        +  "anyOf": [
        +    {
        +      "$ref": "#/$defs/Metrics"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • addedOutput schema / $defs / DataResource / properties / ro_crate
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Ro Crate"
        +}
      • addedOutput schema / $defs / DataResource / properties / superseded_by
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null,
        +  "title": "Superseded By"
        +}
      • addedOutput schema / $defs / Metrics
        Added value: +{
        +  "description": "Usage/impact signals, each a separate axis — NO blended score. All\nnullable: a source that does not expose an axis leaves it None.",
        +  "properties": {
        +    "citations": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Citations"
        +    },
        +    "downloads": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Downloads"
        +    },
        +    "likes": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Likes"
        +    },
        +    "views": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Views"
        +    }
        +  },
        +  "title": "Metrics",
        +  "type": "object"
        +}
  8. 4 tool updatesv0.16.0
    • Changedfetch1 field changed
      • addedOutput schema / properties / resumed
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "title": "Resumed",
        +  "type": "array"
        +}
    • Changedlist_sources1 field changed
      • addedInput schema / properties / check_health
        Added value: +{
        +  "default": false,
        +  "description": "When true, probe each source's base endpoint and attach a 'health' field ({status: up|down, latency_ms, detail}) to each source. Default false: returns the static catalog with no network.",
        +  "type": "boolean"
        +}
    • Changedresolve5 fields changed
      • addedOutput schema / $defs / Creator
        Added value: +{
        +  "properties": {
        +    "name": {
        +      "title": "Name",
        +      "type": "string"
        +    },
        +    "orcid": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Orcid"
        +    }
        +  },
        +  "required": [
        +    "name"
        +  ],
        +  "title": "Creator",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / FundingRef
        Added value: +{
        +  "properties": {
        +    "award": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Award"
        +    },
        +    "funder": {
        +      "title": "Funder",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "funder"
        +  ],
        +  "title": "FundingRef",
        +  "type": "object"
        +}
      • addedOutput schema / properties / creators / items / $ref
        Added value: +"#/$defs/Creator"
      • removedOutput schema / properties / creators / items / type
        Removed value: -"string"
      • addedOutput schema / properties / funding
        Added value: +{
        +  "items": {
        +    "$ref": "#/$defs/FundingRef"
        +  },
        +  "title": "Funding",
        +  "type": "array"
        +}
    • Changedsearch12 fields changed
      • addedInput schema / properties / cursor
        Added value: +{
        +  "description": "Opaque pagination token from a prior search's next_cursor. When set, all other search params are read from the cursor.",
        +  "type": "string"
        +}
      • addedInput schema / properties / kind
        Added value: +{
        +  "description": "Keep only results of this kind.",
        +  "enum": [
        +    "dataset",
        +    "sequencing_run",
        +    "study",
        +    "publication",
        +    "software"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / published_after
        Added value: +{
        +  "description": "Keep results with year >= this.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / published_before
        Added value: +{
        +  "description": "Keep results with year <= this.",
        +  "type": "integer"
        +}
      • addedInput schema / properties / rank
        Added value: +{
        +  "default": "relevance",
        +  "description": "Result ordering. 'relevance' (default) = upstream/merged order. 'semantic' re-ranks the fetched page by embedding similarity to the query (needs EMBEDDING_API_BASE; degrades to relevance order with an errors['semantic'] note if unconfigured). In semantic mode pagination is window-based (each page consumes its full fetched window).",
        +  "enum": [
        +    "relevance",
        +    "semantic"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / properties / sources / description
        Previous value: -"Restrict fan-out to these sources (default: all). Available: zenodo, datacite, omics, literature"New value: +"Restrict fan-out to these sources (default: all). Available: zenodo, datacite, omics, literature, huggingface"
      • removedInput schema / required
        Removed value: -[
        -  "query"
        -]
      • addedOutput schema / $defs / Creator
        Added value: +{
        +  "properties": {
        +    "name": {
        +      "title": "Name",
        +      "type": "string"
        +    },
        +    "orcid": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Orcid"
        +    }
        +  },
        +  "required": [
        +    "name"
        +  ],
        +  "title": "Creator",
        +  "type": "object"
        +}
      • addedOutput schema / $defs / DataResource / properties / creators / items / $ref
        Added value: +"#/$defs/Creator"
      • removedOutput schema / $defs / DataResource / properties / creators / items / type
        Removed value: -"string"
      • addedOutput schema / $defs / DataResource / properties / funding
        Added value: +{
        +  "items": {
        +    "$ref": "#/$defs/FundingRef"
        +  },
        +  "title": "Funding",
        +  "type": "array"
        +}
      • addedOutput schema / $defs / FundingRef
        Added value: +{
        +  "properties": {
        +    "award": {
        +      "anyOf": [
        +        {
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "default": null,
        +      "title": "Award"
        +    },
        +    "funder": {
        +      "title": "Funder",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "funder"
        +  ],
        +  "title": "FundingRef",
        +  "type": "object"
        +}
  9. 4 tool updatesv0.11.0
    • First observedfetch
    • First observedlist_sources
    • First observedresolve
    • First observedsearch

TDQS

A4.4/5.0

Scored across 6 tools

Disambiguation5/5

Each tool has a distinct role in the pipeline: search discovers resources, resolve retrieves full metadata, fetch downloads files, operate inspects remote tabular data, relate suggests joins, and list_sources describes capabilities. There is no meaningful overlap between the tools.

Naming Consistency4/5

Five tools use a consistent single-verb imperative style (search, resolve, fetch, operate, relate), and list_sources follows the common verb_noun pattern. The only minor inconsistency is that list_sources is compound while the others are single words, but the overall style is clear and predictable.

Tool Count5/5

Six tools is well-scoped for a data aggregation server: discovery, resolution, download, source inspection, remote query, and relation hinting are each represented without redundancy. The count feels neither thin nor bloated.

Completeness5/5

The tool set covers the full aggregation workflow from querying many sources to resolving records, downloading files, inspecting remote tabular data, and understanding dataset relationships. Missing mutation operations are appropriate because this is a read-oriented aggregator, not a repository management system.

Maintenance

ActivityActive
ResponsivenessSlow

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    B
    maintenance
    Enables searching and downloading academic papers from 14 platforms including arXiv, PubMed, Google Scholar, Web of Science, Springer, and Sci-Hub with unified data format and intelligent rate limiting.
    19
    368
    184
    MIT
  • F
    license
    Not graded
    quality
    A
    maintenance
    Enables searching for academic papers and preprints across multiple platforms including Semantic Scholar, arXiv, PubMed, and CrossRef. It provides access to research records, DOI lookups, and journal metadata through a unified interface deployed on Cloudflare Workers.
    -
  • A
    license
    A
    quality
    A
    maintenance
    ▎ Provides 32 tools for plant-genomics locus lookup across 11 free public backends (Ensembl Plants, Phytozome, UniProtKB, Europe PMC, QuickGO, NCBI BLAST, Gramene, KEGG, STRING-DB, ATTED-II, BAR). Takes a TAIR-style locus plus optional organism and returns gene metadata, functional/pathway annotation, interactions, co-expression, and literature — in single-locus, batch, and cross-source synthesis.
    50
    5
    MIT