Tool reference¶
Every tool both servers expose, with its arguments and the scope it needs. The
descriptions here are the same strings the servers hand to the model — they come out
of locales/en.json, so this page cannot drift from what a client actually sees.
- http — the 33 tools of the HTTP server
- stdio — the 12 tools of the stdio server
A tool with no scope reads public information and works unauthenticated. See Authorization for what each scope means.
Reading records¶
search_records¶
| Available in | both servers |
| Scope | none (unauthenticated) |
Search published records (works unauthenticated).
With a token the search runs as that user, so their own drafts are included too.
The stdio version differs:
Search published records. query is an Invenio search expression (empty matches everything). Returns summary fields only.
get_record¶
| Available in | both servers |
| Scope | none (unauthenticated) |
Fetch a single record (works unauthenticated). draft=True fetches the draft (authentication required).
The stdio version differs:
Fetch one record. draft=True fetches the draft.
my_records¶
| Available in | HTTP server only |
| Scope | mcp:read |
List your own records and drafts (mcp:read).
Unpublished drafts are included, not just published records, so it can answer "what am I still working on".
list_versions¶
| Available in | HTTP server only |
| Scope | none (unauthenticated) |
List every version of a record (works unauthenticated). Versions made by new_version show up here.
list_revisions¶
| Available in | HTTP server only |
| Scope | mcp:read |
List a record's revision history — what changed and when (mcp:read).
Different from versions (list_versions): this is the edit history of the same
record. Authentication is required even for published records.
export_record¶
| Available in | HTTP server only |
| Scope | none (unauthenticated) |
Export a published record in another metadata format (works unauthenticated).
fmt is one of json / inveniordm / jsonld / datacite-json / datacite-xml / dublincore / marcxml / dcat / csl / bibtex / citation / geojson. Not available for drafts (published records only).
Vocabularies¶
list_vocabulary_types¶
| Available in | HTTP server only |
| Scope | none (unauthenticated) |
List the vocabulary types this repository has (works unauthenticated).
Pass one of the returned ids to list_vocabulary to read its entries.
list_vocabulary¶
| Available in | HTTP server only |
| Scope | none (unauthenticated) |
Read the entries of a vocabulary (works unauthenticated).
vocab_type is an id returned by list_vocabulary_types (resourcetypes / licenses /
languages / subjects / removalreasons / creatorsroles / descriptiontypes /
relationtypes / titletypes / datetypes and so on).
Check the right id here before writing any metadata.
Creating and updating¶
create_record¶
| Available in | both servers |
| Scope | mcp:write |
create_record(metadata: dict, access: dict = None, files_enabled: bool = False, publish: bool = False) # stdio
Create a record (mcp:write).
publish=True publishes it as well.
files=True makes a draft that can carry files (put them in with upload_file).
Leave publishing until after the files are in — once published, files can only be
added through a new version.
The stdio version differs:
Create a new record. metadata is an Invenio metadata object (required: resource_type{id}, title (>= 3 chars), publication_date (EDTF), creators[{person_or_org{type,family_name,given_name}}]). files_enabled=False makes it metadata-only. publish=True publishes it right away. The result contains recid.
update_record¶
| Available in | both servers |
| Scope | mcp:write |
Update a record's metadata (mcp:write). For a published record this does edit -> update -> publish.
The stdio version differs:
Update an existing record's metadata. For a published record this does edit (back to draft) -> update -> (publish). metadata is the complete metadata object (a replacement, not a patch). publish=False leaves it as a draft.
publish_record¶
| Available in | both servers |
| Scope | mcp:write |
Publish a draft (mcp:write).
The stdio version differs:
Publish a draft.
new_version¶
| Available in | both servers |
| Scope | mcp:write |
new_version(recid: str, import_files: bool = True, publication_date: str | None = None, version: str | None = None) # http
Create a draft of a new version of a published record (mcp:write).
InvenioRDM cannot rewrite a published record. To add or replace files you make a new version, work in it, and publish again.
recid ... the original (published) record ID
import_files ... True carries the previous version's files over
(InvenioRDM's files-import; default True).
False starts from a draft with no files.
publication_date ... the new version's publication date (YYYY-MM-DD).
InvenioRDM does not carry the publication date into a new version
draft, so today's date is filled in when this is omitted. Without
it, publishing fails with
metadata.publication_date: Missing data for required field.
version ... the version label (v2 and the like). Optional.
The id in the result is the new draft's ID. Run upload_file and friends against
that ID, then publish with publish_record.
The stdio version differs:
Create a draft of a new version. Passing metadata replaces it; publish=True publishes right away.
delete_draft¶
| Available in | both servers |
| Scope | mcp:write |
Discard a draft (mcp:write).
The stdio version differs:
Discard a draft (unpublished, or the draft of an edit in progress).
Withdrawing and restoring¶
delete_record¶
| Available in | both servers |
| Scope | mcp:curate |
delete_record(recid: str, confirm: bool = False, reason_id: str = 'out-of-scope', note: str = 'removed via MCP')
Soft-delete a published record, leaving a tombstone that returns HTTP 410 (mcp:curate).
Destructive, so it does nothing without confirm=True. restore_record brings it back.
reason_id is an id from the removalreasons vocabulary (list them with
list_vocabulary("removalreasons"); the stock twelve are out-of-scope / copyright /
disputed-authorship / duplicate / fraud / misconduct / personal-data / retracted /
spam / replaced / take-down-request / test-record). note is a public remark left on
the tombstone.
Fails with 403 unless the user holds the admin role in InvenioRDM.
The stdio version differs:
Soft-delete a published record, leaving a tombstone that returns HTTP 410. Requires an admin token. Does nothing without confirm=True. restore_record brings it back. reason_id comes from the removalreasons vocabulary (out-of-scope / duplicate / spam / retracted and so on).
restore_record¶
| Available in | both servers |
| Scope | mcp:curate |
Restore a soft-deleted published record (mcp:curate).
The tombstone is lifted and the record is published again. Fails with 403 unless the user holds the admin role in InvenioRDM.
The stdio version differs:
Restore a soft-deleted published record. Requires an admin token.
Files¶
upload_file¶
| Available in | HTTP server only |
| Scope | mcp:write |
upload_file(recid: str, filename: str, content_base64: str | None = None, content_text: str | None = None, overwrite: bool = True) # http
Register a file on a draft (mcp:write).
recid ... the draft's ID (the id returned by create_record)
filename ... the name to register it under (it becomes the key)
content_base64 ... the content as base64; use this for binaries
content_text ... the content as plain text; easier for text (encoded as UTF-8)
overwrite ... replace a file of the same name if one exists (default True). False reports that it already exists and does nothing.
Files cannot be added to a published record (an InvenioRDM rule — make a new version instead). If the draft has files disabled, they are enabled automatically.
add_file¶
| Available in | stdio server only |
add_file(recid: str, key: str, text: str = None, content_base64: str = None, source_path: str = None) # stdio
Add a file to a draft (init -> content -> commit). The record must have files_enabled=True. Give the content as one of text (UTF-8), content_base64, or source_path (a path on the server).
list_files¶
| Available in | both servers |
| Scope | none (unauthenticated) |
List a record's files (published records are visible unauthenticated).
draft=True lists the draft's files (requires the owner's authentication).
The stdio version differs:
List the files of a record or draft.
download_file¶
| Available in | HTTP server only |
| Scope | none (unauthenticated) |
Retrieve a file's contents (works unauthenticated for published records).
InvenioRDM answers with a redirect to an S3 presigned URL. That URL's host is an
in-cluster name (minio:9000), so it cannot be followed from outside the cluster.
The MCP server therefore fetches it instead and returns the bytes as base64. Anything
that decodes as UTF-8 is also returned in text.
draft=True fetches the draft's file (requires the owner's authentication).
delete_file¶
| Available in | both servers |
| Scope | mcp:write |
Delete a file from a draft (mcp:write). Files cannot be removed from a published record.
The stdio version differs:
Delete a file from a draft.
upload_file_from_url¶
| Available in | HTTP server only |
| Scope | mcp:write |
Hand InvenioRDM a URL and let it fetch the file itself (mcp:write).
upload_file carries the bytes as base64, and since MCP responses are JSON that does
not suit large files (default limit 16MB). This tool only registers a URI; the
bytes are downloaded asynchronously by InvenioRDM's Celery worker (InvenioRDM
transfer type F = FETCH). There is no size limit.
Ordinary users cannot use this on InvenioRDM v14. The default permission policy
(RDMRecordPermissionPolicy.can_draft_create_files) admits ordinary users only for
transfer types L and M; F (and R) are limited to SystemProcess(), meaning
system processes and superusers. Making the server fetch an arbitrary URL is a
potential SSRF, hence the restriction. Without the permission this returns 403.
The target must also be within InvenioRDM's allowed domains
(RECORDS_RESOURCES_FILES_ALLOWED_DOMAINS). A URL outside them fails with
Domain not allowed.
Because it is asynchronous, the fetch may still be running when this returns
(status is pending). Confirm completion by checking that list_files reports
status as completed.
A file on your own machine has no URL and cannot take this path. Use
start_multipart_upload for that (no size limit, and ordinary write permission is
enough).
start_multipart_upload¶
| Available in | HTTP server only |
| Scope | mcp:write |
start_multipart_upload(recid: str, filename: str, size: int, part_size: int | None = None, overwrite: bool = True) # http
Issue presigned URLs for sending a large local file (mcp:write).
upload_file carries the bytes as base64, so it is bounded by what fits in JSON
(default 16MB). upload_file_from_url only works for files that have a URL.
A large file on your own machine goes this way (InvenioRDM transfer type
M = MULTIPART). The bytes pass through neither the MCP server nor InvenioRDM: they
are PUT straight from the client to S3 (MinIO). There is effectively no size limit.
recid ... the draft's ID filename ... the name to register it under size ... the file's exact byte count (required; it is declared to S3 up front) part_size ... bytes per part. Default 64MiB. Every part but the last must be at least 5MiB and all of them the same size
PUT the file to each url under parts in the result, cutting it into part_size
chunks from the beginning. Call complete_multipart_upload once every part is sent,
or abort_multipart_upload to give up.
Splitting and sending, as an example (the same text is in hint in the result):
split -b <part_size> ./big.bin part_
curl -X PUT --data-binary @part_aa "<parts[0].url>"
curl -X PUT --data-binary @part_ab "<parts[1].url>"
complete_multipart_upload¶
| Available in | HTTP server only |
| Scope | mcp:write |
Finalise a multipart upload once every part has been sent (mcp:write).
S3 joins the parts into a single object and the transfer type changes from M to L
(an ordinary file). It fails if even one part is missing.
The checksum right afterwards has the form
multipart:<ETag>-<part count>-<part size>, which is the composite ETag S3 returns
(the per-part MD5s rolled together). InvenioRDM recomputes the MD5 of the whole file
in a background job.
abort_multipart_upload¶
| Available in | HTTP server only |
| Scope | mcp:write |
Discard a multipart upload that was given up partway (mcp:write).
The incomplete upload on the S3 side is aborted too, so half-sent parts do not linger and keep costing storage.
Communities¶
search_communities¶
| Available in | HTTP server only |
| Scope | none (unauthenticated) |
Search communities (works unauthenticated).
get_community¶
| Available in | HTTP server only |
| Scope | none (unauthenticated) |
Fetch a single community (works unauthenticated). community is an id (UUID) or a slug.
list_community_records¶
| Available in | HTTP server only |
| Scope | none (unauthenticated) |
List the published records belonging to a community (works unauthenticated).
create_community¶
| Available in | HTTP server only |
| Scope | mcp:curate |
create_community(slug: str, title: str, community_type: str = 'topic', visibility: str = 'public', review_policy: str = 'closed') # http
Create a community (mcp:curate).
Creating an organisational unit sits under curate rather than write. slug is the identifier that appears in URLs (lowercase letters, digits, hyphens). community_type comes from the communitytypes vocabulary (organization / event / topic / project). review_policy=closed puts submissions through review; open lets them publish directly.
Reviews and requests¶
list_requests¶
| Available in | HTTP server only |
| Scope | mcp:read |
List the requests visible to you (mcp:read).
status is one of submitted / expired / accepted / declined / cancelled.
Pending review is status="submitted" — there is no "open" state.
Omit it for everything. query also takes Lucene-style filters
(e.g. type:community-submission).
get_request¶
| Available in | HTTP server only |
| Scope | mcp:read |
Fetch a single request (mcp:read). timeline=True also returns its comments and events.
submit_to_community¶
| Available in | HTTP server only |
| Scope | mcp:write |
Submit a draft to a community for review (mcp:write).
Does both steps at once (set the review target, then submit). The target must be an
unpublished draft. Acceptance publishes it. Accepting and declining are
request_action (mcp:curate).
comment_on_request¶
| Available in | HTTP server only |
| Scope | mcp:write |
Comment on a request (mcp:write).
request_action¶
| Available in | HTTP server only |
| Scope | mcp:curate |
Accept or decline a request (mcp:curate).
action is one of accept / decline / cancel / expire. accept publishes the submission, which is a curator's decision, hence curate.
Session¶
whoami¶
| Available in | HTTP server only |
| Scope | mcp:read |
Return the authenticated subject of this session and the identity resolved on the InvenioRDM side (mcp:read).
When the login came through a federation such as GakuNin, this shows that eppn, affiliation (from the issuer) and groups (from mAP) are carried on both the token addressed to this MCP server and the exchanged token addressed to InvenioRDM.
When invenio.email_pending_setup is true the user has not yet set an email address
in InvenioRDM (the federation does not release mail, so a placeholder is in place).
Notification mail cannot reach them in that state, so point them at
profile_settings_url and ask them to set one.