Skip to main content
Glama
README.md
# cordis-mcp

MCP server for **CORDIS** — EU-funded research projects, including European
Research Council (ERC) grants.

```
npx -y github:MCP-Hive/cordis-mcp
```

No API key, no registration, no cost. Data is CC BY 4.0.

## What it covers

The [EURIO knowledge graph](https://op.europa.eu/en/web/eu-vocabularies/eurio),
which holds CORDIS data for Horizon Europe, H2020 and FP7:

| | |
|---|---|
| Projects | 80,208 |
| Grants | 80,222 |
| Project publications | 419,740 |
| Project deliverables | 211,188 |
| Organisation roles | 398,584 |

## Tools

### `search_projects`

Search EU-funded projects by keyword with server-side filters.

| Parameter | Type | Purpose |
|---|---|---|
| `query` | string | Keywords, ANDed. Quote a run of words to require them adjacent |
| `search_abstracts` | boolean | Match titles and abstracts. Default true; false is titles only, and much faster |
| `erc_only` | boolean | Restrict to ERC grants (ERC-STG, ERC-COG, ERC-ADG, ERC-POC, …) |
| `funding_scheme` | string | Scheme code prefix, e.g. `ERC-ADG` or `MSCA`. Overrides `erc_only` |
| `country` | string | ISO-2 country code of the coordinating organisation |
| `min_funding` | number | Minimum EC contribution in EUR |
| `start_date_from` / `start_date_to` | string | Start-date window, `YYYY-MM-DD` |
| `limit` | number | 1–50, default 10 |

Filters are applied **in SPARQL, not after the fact**, so a narrow request does
not have its recall capped by whatever an unfiltered first page happened to
contain.

**How `query` matches.** Each keyword is required independently, in the title or
the abstract; the query is not matched as a phrase. `quantum computing control
electronics qubit` therefore finds projects that mention all five words
anywhere, rather than the handful of titles containing that exact string —
which is none of them. Stopwords are dropped, at most 8 keywords are used, and
`"like this"` requires the quoted words adjacent.

**An empty result explains itself.** When nothing matches every keyword, the
response carries `keywordMatches` — how many projects each keyword matches on
its own — and a `hint`. Where one over-specific keyword is the problem, the
search is retried without the least selective one and the response says so in
`relaxed.droppedKeywords`. This recovery work is bounded to ~20s; the ordinary
path is ~4s.

### `get_project`

Full record for one project by grant agreement number: abstract, funding,
dates, scheme, DOI, and participating organisations (coordinator first).

### `list_erc_schemes`

The ERC scheme codes present in CORDIS with grant counts, to feed
`funding_scheme`.

## Notes on the data

**`totalCost` is often zero.** For many schemes — MSCA fellowships especially —
CORDIS records `hasTotalCost` as 0 while the real figure lives on the grant as
`hasFundingAmount`. This server reports that as `ecContribution` and suppresses
the misleading zero rather than passing it through. `min_funding` filters on the
EC contribution for the same reason.

**Errors are never silently empty.** A failed or rejected query returns a tool
error, not `[]`. A caller billed per request must be able to tell "no matches"
from "upstream broke".

## Attribution

CORDIS data is CC BY 4.0 and permits commercial reuse with attribution. Every
response carries an `attribution` field:

> Data: CORDIS, © European Commission, CC BY 4.0

Keep it attached to anything derived from these results.

## Implementation notes

The server queries the CORDIS SPARQL endpoint:

```
POST https://cordis.europa.eu/datalab/sparql/query
```

Two things about that endpoint are worth knowing before changing queries:

1. **It is undocumented.** CORDIS's published services page describes SPARQL
   access without naming a query URL; this path was found by probing. It
   works and returns proper `application/sparql-results+json`, but nothing
   commits CORDIS to keeping it. If it moves, the JSON search API at
   `https://cordis.europa.eu/search?format=json` is the documented fallback
   (note: its `num` parameter caps at 50, and `num=100` silently returns 10).
2. **The default graph does not union the named graphs.** Every pattern must be
   wrapped in an explicit `GRAPH <...>` block. Forgetting this does not error —
   it silently matches nothing.

Similarly, a `FILTER` only sees variables bound in its own group. Filters on
`?ecContribution`, which comes from the grants graph, must sit in the outer
group, not inside the projects block.

## Development

```
npm install        # dev dependencies only
npm run typecheck
npm run bundle     # rebuild server/bundle.mjs
npm run smoketest  # live end-to-end check against CORDIS
```

Verify the published one-liner:

```
npm run smoketest -- github:MCP-Hive/cordis-mcp
```

`server/bundle.mjs` is committed — it is the artifact `npx` executes, and the
package declares no runtime dependencies and no `prepare` script so that
`npx -y github:...` clones and runs with nothing to install or compile. Commit
the rebuilt bundle with any source change.

## Roadmap

Scoped but not yet built: `search_organisations` (institution portfolios) and
`get_project_outputs` (the 420k-node publications and deliverables graph).

## License

MIT — see [LICENSE](LICENSE). The CORDIS data itself is CC BY 4.0,
© European Commission.

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clear, distinct role: search_projects for querying multiple projects, get_project for a single project's full record, and list_erc_schemes for available filter values. No two tools overlap in purpose.

Naming Consistency5/5

All tool names follow a consistent verb_noun snake_case pattern: search_projects, get_project, list_erc_schemes. The pattern is predictable and easy to infer.

Tool Count5/5

Three tools is a well-scoped set for a read-only EU research project database: search, retrieve details, and list filter options. Each tool earns its place without redundancy.

Completeness4/5

The core workflow of searching for projects and retrieving full records is covered, with list_erc_schemes supporting filtering. Minor gaps like organization-level search or pagination controls may exist, but the essential surface is complete for the apparent domain.

Maintenance

ActivityMaintained
ResponsivenessNo issues