An MCP server that allows LLM agents to query and interact with Zenodo repositories using the Zenodo REST API.
- Unauthenticated access – search and inspect public records without an API key
- Session API key – supply a personal access token at runtime via the
set_api_keytool - Persistent service account – set
ZENODO_API_KEYenvironment variable for a long-lived key - Optional write access – create, update, and publish depositions (enabled via
ZENODO_ALLOW_WRITE=true) - Search records with full Elasticsearch query syntax, pagination, and filtering
- Browse and filter Zenodo communities
- Retrieve record metadata, files, and file content (text or binary)
- List, create, update, publish, and version depositions (write tools require
ZENODO_ALLOW_WRITE=true) - Configurable Zenodo base URL for sandbox or self-hosted instances
- Optional default community filter via
ZENODO_COMMUNITY
- Node.js 18 or later
- npm
git clone https://github.com/eic/zenodo-mcp-server.git
cd zenodo-mcp-server
npm install
npm run build# Without authentication (public records only)
node build/src/index.js
# With a persistent API key (service account)
ZENODO_API_KEY=your_token node build/src/index.js
# Against the Zenodo sandbox
ZENODO_BASE_URL=https://sandbox.zenodo.org ZENODO_API_KEY=your_sandbox_token node build/src/index.jsZenodo uses personal access tokens for authentication.
After connecting to the server, call the set_api_key tool:
{ "name": "set_api_key", "arguments": { "api_key": "your_personal_access_token" } }The token is stored in memory for the lifetime of the server process and is never written to disk.
export ZENODO_API_KEY=your_personal_access_token
node build/src/index.js- Log in to zenodo.org
- Go to Account → Settings → Applications → Personal access tokens
- Click New token and select the required scopes:
deposit:write– create and update depositionsdeposit:actions– publish depositionsuser:email– verify identity (optional)
- Save the token securely – it is shown only once
| Tool | Description | Auth required | Write required |
|---|---|---|---|
get_auth_status |
Check authentication status and get setup guidance | No | No |
set_api_key |
Set a personal access token for the current session | No | No |
search_records |
Search Zenodo records with Elasticsearch query syntax | No | No |
get_community |
Get details about a specific Zenodo community | No | No |
list_communities |
Search or list Zenodo communities | No | No |
get_record |
Get full metadata for a record by ID or DOI | No | No |
list_record_files |
List files attached to a record | No | No |
get_file_content |
Download file content (text or base64) | No | No |
list_depositions |
List your own depositions (drafts + published) | Yes | No |
create_deposition |
Create a new empty deposition (draft) | Yes | Yes |
get_deposition |
Retrieve a single deposition by ID | Yes | Yes |
update_deposition |
Update metadata of a draft deposition | Yes | Yes |
delete_deposition |
Delete an unpublished draft deposition | Yes | Yes |
upload_file |
Upload a file to a deposition | Yes | Yes |
delete_deposition_file |
Delete a file from an unpublished deposition | Yes | Yes |
publish_deposition |
Publish a deposition and register a DOI | Yes | Yes |
edit_deposition |
Unlock a published deposition for metadata edits | Yes | Yes |
discard_deposition |
Discard edits and revert to published state | Yes | Yes |
new_version |
Create a new version of a published deposition | Yes | Yes |
Write tools are only available when
ZENODO_ALLOW_WRITE=true(orZENODO_ALLOW_WRITE=1) is set. See docs/TOOLS.md for full parameter details.
{
"name": "search_records",
"arguments": {
"query": "electron ion collider",
"size": 10,
"page": 1,
"sort": "mostrecent",
"type": "publication",
"subtype": "article",
"communities": "zenodo",
"all_versions": false,
"bounds": "143.37,-38.99,146.90,-37.35"
}
}Sort options: bestmatch, mostrecent, mostviewed, mostdownloaded (prefix - for descending).
Resource types: publication, poster, presentation, dataset, image, video, software, lesson, other.
bounds — optional geolocation bounding box: "west,south,east,north" in decimal degrees.
When ZENODO_COMMUNITY is set, the communities parameter defaults to that value if not supplied.
Accepts a numeric ID or a DOI:
{ "name": "get_record", "arguments": { "id": "1234567" } }
{ "name": "get_record", "arguments": { "id": "10.5281/zenodo.1234567" } }{
"name": "get_file_content",
"arguments": {
"id": "1234567",
"filename": "data.csv",
"max_bytes": 1048576
}
}Text files are returned as UTF-8 strings. Binary files are returned as base64. The truncated field indicates whether the file was cut at max_bytes.
| Variable | Default | Description |
|---|---|---|
ZENODO_BASE_URL |
https://zenodo.org |
Base URL of the Zenodo instance |
ZENODO_API_KEY |
(none) | Personal access token for persistent authentication |
ZENODO_ALLOW_WRITE |
(unset) | Set to true or 1 to enable write tools (depositions) |
ZENODO_COMMUNITY |
(none) | Default community identifier applied to searches |
ZENODO_MAX_UPLOAD_BYTES |
52428800 (50 MiB) |
Maximum file size for upload_file |
Add the server to your MCP client configuration (e.g. Claude Desktop claude_desktop_config.json):
{
"mcpServers": {
"zenodo": {
"command": "node",
"args": ["/path/to/zenodo-mcp-server/build/src/index.js"],
"env": {
"ZENODO_API_KEY": "your_token_here"
}
}
}
}npm run build # Compile TypeScript
npm run watch # Watch mode
npm test # Build and run tests
npm run test:coverage # Tests with coverage reportMIT