zotero-library-mcp
zotero-library-mcp is an MCP server for managing a Zotero library (personal and shared group libraries) over stdio or Streamable HTTP.
Discover libraries and target a library per call.
Add papers by DOI or arXiv ID, books by ISBN, batch-add DOIs, and create items from manual metadata.
Search/browse items, collections, recent/unfiled items, tags, attachments, notes, annotations, full text, and duplicates.
Read item details, full text, BibTeX/BibLaTeX, and export/save BibTeX or PDFs where authorized.
Manage collections: create, nest, rename, move, delete, and add/remove items.
Manage tags: add, remove, delete, rename, set/unset colors.
Manage notes and PDF annotations: add, list, update, delete; create highlights with duplicate/overlap handling.
Attach files; download PDFs as MCP resources or save them to allowed paths.
Verify items against CrossRef, run health checks, update metadata, and trash/restore or permanently delete items/collections.
Provide ChatGPT company-knowledge compatible search/fetch tools.
Allows adding preprints to Zotero by arXiv ID, retrieving metadata via the arXiv API.
Can be configured to use Nextcloud as WebDAV storage for file attachments in Zotero.
Can be configured to use Synology as WebDAV storage for file attachments in Zotero.
Provides tools for managing a Zotero library: adding items by DOI, arXiv ID, or ISBN; searching; managing collections, tags, and annotations; and attaching files.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@zotero-library-mcp add the paper with DOI 10.1038/s41586-023-06478-5 to my library"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
zotero-library-mcp
An MCP server that lets Claude, Codex, and ChatGPT add papers and books to your Zotero library by DOI, arXiv ID, or ISBN — and manage your collections, tags, and items.
The server supports both MCP transports used by these clients:
stdio (default) for Claude Code, Claude Desktop, Codex CLI/IDE, and the ChatGPT desktop app
Streamable HTTP for a hosted ChatGPT app or any remote MCP client
Tools
Adding papers
add_paper_by_doi— Resolve a DOI via CrossRef and add the paper to Zotero (with duplicate detection)add_papers_by_dois— Batch-add up to 50 papers at onceadd_paper_by_arxiv_id— Add a preprint by arXiv ID (uses DOI when available, falls back to arXiv metadata)add_item_from_metadata— Create any supported Zotero item type from validated manual metadata
Adding books
add_book_by_isbn— Resolve an ISBN via Open Library and add the book to Zotero (with duplicate detection)
Searching & browsing
list_libraries— Discover the API key owner's personal library and shared group libraries, with IDs and key permissionssearch_library— Search your Zotero library by title, author, tag, etc., paginated viastart/limit(falls back to fuzzy matching when the exact search returns no results)get_item_details— View full metadata for any itemget_recent_items— List recently added itemsget_unfiled_items— Get items not in any collectionsearch_fulltext— Search Zotero metadata and indexed full textfind_duplicates— Find duplicate items by DOI, ISBN, or normalized titlelist_attachments— List every attachment and choose a specific PDF keyhealth_check— Verify library credentials, access, and storage configuration
Reading & annotating
get_item_fulltext— Return bounded plain text from Zotero's index or a PDF, without leaking temporary pathsget_bibtex— Read-only BibTeX/BibLaTeX export for items, a collection, or the full librarysave_bibtex— Save an export to an authorized local pathget_annotations— List all highlights and annotations on a paper's PDFcreate_annotation— Highlight a text passage in a PDF (searches for the exact text, creates a visible highlight in Zotero's reader, and returns a preview image for verification). Smart overlap handling: exact duplicates update the existing comment; sub-passages get a contrasting highlight color automatically.add_note— Add a note to an itemlist_notes,update_note,delete_note— Manage existing notesupdate_annotation,delete_annotation— Edit or remove annotations
File attachments
attach_file— Attach a local file over stdio or a ChatGPT file input over HTTPdownload_pdf— Return a remote-safe MCP file resourcesave_pdf— Save a PDF to an authorized local path
Collections
list_collections— List all collections (with nesting)create_collection— Create a new collection (optionally nested under a parent)get_collection_items— Browse items in a collection, paginated viastart/limitadd_to_collection— Add an existing item to a collectionremove_from_collection— Remove an item from a collection (keeps it in your library)rename_collection,move_collection— Reorganize collections
Tags
list_tags— List all tags in your libraryadd_tags— Add one or more tags to an item (with optional color)remove_tags— Remove tags from an itemdelete_tags— Delete tags from the entire libraryset_tag_color— Assign a color to a tag (appears in Zotero's tag selector)rename_tag— Rename a tag across all items in your libraryunset_tag_color— Remove a tag color without deleting the tag
Verification
verify_items— Re-check recent items against CrossRef to catch bad DOIs or title mismatches
Deleting
delete_item— Permanently delete an item from your librarydelete_collection— Permanently delete a collectiontrash_item,restore_item— Prefer reversible trash operations for ordinary cleanup
The server also exposes the standard read-only search and fetch tool shapes used by ChatGPT company knowledge and deep research.
Related MCP server: zotero-mcp-lite
Prerequisites
A Zotero API key with write permissions: https://www.zotero.org/settings/keys
Your Zotero library ID (shown on the same page, or in your profile URL)
uv installed
Quick Start
Codex and the ChatGPT desktop app
Codex and the ChatGPT desktop app share MCP configuration on the same Codex host. Add the server once:
codex mcp add zotero \
--env ZOTERO_LIBRARY_ID=your_library_id \
--env ZOTERO_API_KEY=your_api_key \
-- uvx --from git+https://github.com/RaulSimpetru/zotero-library-mcp zotero-mcpThen restart Codex or the ChatGPT desktop app. In Codex, use /mcp to confirm that zotero is connected. In ChatGPT desktop, open Settings → MCP servers to view the same server.
For WebDAV storage, add the three ZOTERO_WEBDAV_* values shown in the WebDAV example. If the desktop app cannot find uvx, replace it with the full path returned by which uvx.
You can also configure the server directly in ~/.codex/config.toml:
[mcp_servers.zotero]
command = "/full/path/to/uvx"
args = ["--from", "git+https://github.com/RaulSimpetru/zotero-library-mcp", "zotero-mcp"]
env_vars = ["ZOTERO_LIBRARY_ID", "ZOTERO_API_KEY", "ZOTERO_LIBRARY_TYPE", "CROSSREF_MAILTO", "ZOTERO_WEBDAV_URL", "ZOTERO_WEBDAV_USER", "ZOTERO_WEBDAV_PASSWORD"]
startup_timeout_sec = 30
tool_timeout_sec = 120With env_vars, start Codex/ChatGPT from an environment that contains those variables. Use [mcp_servers.zotero.env] instead if you intentionally want to store their values in the config file.
Claude Code
Install it as a plugin (recommended):
/plugin install zotero --marketplace RaulSimpetru/zotero-library-mcpOn older Claude Code versions, run /plugin marketplace add RaulSimpetru/zotero-library-mcp
first, then /plugin install zotero@zotero-library-mcp. Claude Code asks for your
library ID and API key (plus optional WebDAV and Unpaywall settings) when you enable
the plugin, and keeps the API key and WebDAV password in your system keychain. To get
a new release, run /plugin marketplace update zotero-library-mcp, or turn on
auto-update for the marketplace in /plugin.
Plugin tools are named mcp__plugin_zotero_zotero__<tool> rather than mcp__zotero__<tool>;
update any permission rules that name the old tools. If you previously added the
server with claude mcp add, remove that entry (claude mcp remove zotero -s user)
so the two copies don't both run.
Or add it as a plain MCP server:
claude mcp add zotero \
-e ZOTERO_LIBRARY_ID=your_library_id \
-e ZOTERO_API_KEY=your_api_key \
-- uvx --from git+https://github.com/RaulSimpetru/zotero-library-mcp zotero-mcpWebDAV setup
To use WebDAV file storage (e.g. Synology, Nextcloud), include the WebDAV variables:
claude mcp add zotero \
-e ZOTERO_LIBRARY_ID=your_library_id \
-e ZOTERO_API_KEY=your_api_key \
-e ZOTERO_WEBDAV_URL=https://your-webdav-server.com \
-e ZOTERO_WEBDAV_USER=your_username \
-e ZOTERO_WEBDAV_PASSWORD=your_password \
-- uvx --from git+https://github.com/RaulSimpetru/zotero-library-mcp zotero-mcpClaude Desktop
Add this to your claude_desktop_config.json:
{
"mcpServers": {
"zotero": {
"command": "/full/path/to/uvx",
"args": ["--from", "git+https://github.com/RaulSimpetru/zotero-library-mcp", "zotero-mcp"],
"env": {
"ZOTERO_LIBRARY_ID": "your_library_id",
"ZOTERO_API_KEY": "your_api_key",
"ZOTERO_WEBDAV_URL": "https://your-webdav-server.com",
"ZOTERO_WEBDAV_USER": "your_username",
"ZOTERO_WEBDAV_PASSWORD": "your_password"
}
}
}
}Note: Claude Desktop doesn't inherit your shell's PATH, so you need the full path to
uvx. Find it withwhich uvxin your terminal.
ChatGPT on the web (Apps SDK / developer mode)
ChatGPT web connects to an HTTPS Streamable HTTP endpoint. Start the server locally with the HTTP transport, then make it reachable through Secure MCP Tunnel or another authenticated HTTPS deployment:
ZOTERO_LIBRARY_ID=your_id ZOTERO_API_KEY=your_key \
uvx --from git+https://github.com/RaulSimpetru/zotero-library-mcp zotero-mcp \
--transport streamable-http \
--host 127.0.0.1 \
--port 8000 \
--allowed-host your-tunnel.example.comThe MCP endpoint is https://your-tunnel.example.com/mcp. Enable developer mode in ChatGPT, create a developer-mode app, and enter that URL as the MCP server URL. See OpenAI's Connect from ChatGPT guide for the current UI flow.
Security: The safest personal setup is OpenAI Secure MCP Tunnel with the MCP server bound to loopback. HTTP mode disables all server-path reads and writes by default.
attach_fileaccepts ChatGPT's authorized file object, whiledownload_pdfreturns an opaque MCP resource link. Safety annotations are approval hints, not an authorization boundary.
For a public deployment, configure an external OAuth 2.1 identity provider. The server validates JWT access tokens against its JWKS endpoint:
export ZOTERO_MCP_OAUTH_ISSUER=https://auth.example.com
export ZOTERO_MCP_OAUTH_RESOURCE=https://zotero.example.com
export ZOTERO_MCP_OAUTH_JWKS_URL=https://auth.example.com/.well-known/jwks.json
export ZOTERO_MCP_OAUTH_SCOPES=zotero:read,zotero:writeThe authorization server must publish OAuth/OIDC discovery metadata, support the MCP OAuth 2.1 flow with PKCE, issue tokens for ZOTERO_MCP_OAUTH_RESOURCE, and include the configured scopes. See OpenAI's authentication guide. For testing behind an already authenticated gateway only, --allow-unauthenticated-http explicitly acknowledges an unauthenticated non-loopback listener.
This process still uses one server-side Zotero API key. Every authenticated MCP client can target libraries available to that key, including shared groups. Use a key scoped to the libraries intended for those clients. A true multi-user service must map the verified OAuth identity to separate Zotero credentials and enforce per-user authorization; that deployment architecture is intentionally outside this personal-server package.
If an HTTP deployment genuinely needs server paths, enable them only inside confined roots:
zotero-mcp --transport streamable-http \
--allow-server-files \
--file-root /srv/zotero-mcp/exportsHTTP launch settings can also be supplied as environment variables:
CLI option | Environment variable | Default |
|
|
|
|
|
|
|
|
|
|
|
|
|
| local hosts |
|
| local origins |
|
|
|
|
|
|
|
|
|
|
| none |
Run standalone
ZOTERO_LIBRARY_ID=your_id ZOTERO_API_KEY=your_key \
uvx --from git+https://github.com/RaulSimpetru/zotero-library-mcp zotero-mcpPersonal and shared group libraries
The environment variables select the default library. Existing calls that omit library arguments continue to use that default.
Call list_libraries() to discover the key owner's personal library and shared
groups. Results include name, library_id, library_type, is_default, and
key_permissions. Group results are paginated with limit and start; follow
next_start until it is null. Discovery also works when the default is a group.
Every other tool accepts optional library_id and library_type arguments:
list_libraries()
list_collections(library_id="123456", library_type="group")
search_library(query="ultrasound", library_id="123456", library_type="group")
get_item_details(item_key="<key from that group>", library_id="123456", library_type="group")
search_library(query="ultrasound") # Uses the configured default againPass both arguments to select a library, or omit both. Use IDs returned by
list_libraries, rather than group names. Selection applies to one call and never
changes the environment or another client's target, including concurrent calls.
Item and collection keys must come from the selected library. Zotero enforces the
API key's permissions and the user's group rights; a denied group request fails
without falling back to the personal library. health_check accepts the same
arguments to verify a specific library without writing to it.
Group attachments use Zotero's built-in storage. WebDAV is used only for the configured personal library, even when the same server accesses shared groups.
Environment Variables
Variable | Required | Description |
| Yes | Default Zotero user or group library ID |
| Yes | API key with read/write permissions |
| No | Default library type: |
| No | Your email for CrossRef polite pool (faster API access) |
| No | Contact email for open-access PDF lookup (defaults to |
| No | WebDAV URL for file storage (e.g. |
| No | WebDAV username |
| No | WebDAV password |
| No | External OAuth/OIDC issuer URL for protected HTTP deployments |
| No | Canonical HTTPS MCP resource/audience URL |
| No | JWKS URL used to verify JWT access tokens |
| No | Comma-separated required scopes (defaults to read and write) |
| No | Comma-separated allowed roots when HTTP server paths are enabled |
Note: If all three
ZOTERO_WEBDAV_*variables are set, attachments in the configured personal library use WebDAV instead of Zotero's built-in storage. Group attachments always use Zotero storage. The server automatically appends/zoteroto the WebDAV base URL, matching Zotero Desktop's behavior.
Version 0.10.2
Install as a Claude Code plugin:
/plugin install zotero --marketplace RaulSimpetru/zotero-library-mcp.An empty
ZOTERO_LIBRARY_TYPEnow means the default (user), as plugin installs pass unset optional settings as empty strings.
Version 0.10.1
Attaching files to Zotero storage works again (group libraries and setups without WebDAV): Zotero rejects the full local path Pyzotero sent as the filename. Uploads are now confirmed, and a rate-limited or failed upload is reported instead of leaving an empty attachment.
list_tagsreturns every tag; Zotero's tag paging metadata is wrong past 200 tags, which made the old listing drop the rest.Leftover query parameters no longer leak between calls (e.g. a duplicate check after fetching an item template only searched items of that type).
Searches and tag renames containing the word "tags" no longer crash.
Tagging, filing, and editing notes or annotations works on trashed items.
Highlights land correctly on rotated pages with offset crop boxes, match whole words, check for duplicates at the same location only, and report a missing
occurrenceinstead of highlighting a different passage.arXiv imports detect existing copies of any version of the paper.
CrossRef imports keep organization authors and editors and map books, edited books, chapters, and dissertations to the right item types; Open Library books get their authors from the work record.
verify_itemshandles DataCite DOIs (arXiv, Zenodo), HTML in CrossRef titles, and subtitles;health_checkreports read-only keys aswrite_access: false.BibTeX exports keep Zotero's order and unique citekeys across pages.
Lists of child items (attachments, notes, annotations) are no longer capped at 100; linked PDFs are skipped, and standalone PDFs can be read.
Removing the last tag color works; deleting tags containing
||is refused.Hardening for hosted HTTP deployments: downloads connect to the validated IP (DNS rebinding), JWKS refetches are rate-limited, and file saves use exclusive temporary files.
DOI imports no longer create duplicates. Zotero's search does not index DOIs, so the old check never matched; imports now search the resolved title and compare DOIs (including
DOI:lines in Extra).ISBN imports no longer create duplicates of books stored with hyphenated ISBNs; ISBN-10 and ISBN-13 forms now match each other.
search_libraryreturns papers instead of matching attachments and notes.Rate-limited writes are never retried (a retry could duplicate the item) and now fail instead of reporting success.
add_papers_by_dois(attach_pdfs=True)downloads PDFs in parallel.search_fulltextandsearchquery top-level items (about 20x faster).Fuzzy search and
find_duplicatesreuse a library cache that is kept current with Zotero's incremental sync (since=), so repeat calls take well under a second.CrossRef requests use
UNPAYWALL_EMAILas the polite-pool contact whenCROSSREF_MAILTOis unset, and retry rate-limited requests.create_annotationhighlights quotes that wrap across lines in full, countsoccurrenceacross pages, and uses the PDF's own page labels.PDFs attached during DOI/arXiv import are named after the item title, and the result now says why a PDF was not attached.
List output shows the correct year for dates like
12/1/1993.health_checkreturnslibrary_typeasuser/groupand reports whether open-access PDF lookup (UNPAYWALL_EMAIL) is configured.New
list_trashtool for finding keys to pass torestore_item.Faster
get_bibtexfor item keys,rename_tag,get_recent_items, fuzzy searches, andfind_duplicates; Zotero API connections are reused across calls.Full-library and collection
get_bibtexexports stop downloading oncemax_charsis exceeded.get_item_fulltextprefers a PDF's index over a web snapshot's.find_duplicatesreportsitems_scannedandscan_capped.searchfalls back to the item's zotero.org link when it has no URL.Shorter tool descriptions; library targeting is explained once in the server instructions.
Version 0.10.0
Discover personal and shared libraries with
list_libraries.Target a library on each tool call using
library_idandlibrary_type; existing calls keep the configured default.Keep concurrent calls and nested exports scoped to the selected library.
Use Zotero storage for shared-library attachments and personal WebDAV only for the configured personal library.
Keep current dependency imports and HTTP logging compatible with MCP stdio.
Restart the MCP connection after upgrading to load the new tool schemas.
Upgrading to 0.8
Two path-writing operations were split from their read-only counterparts so remote clients can apply correct safety approvals:
get_bibtex(save_path=...)is nowsave_bibtex(save_path=...);get_bibtexonly returns data.download_pdf(save_path=...)is nowsave_pdf(save_path=...);download_pdfreturns an opaque MCP resource link.
Existing read-only calls to get_bibtex and download_pdf continue to work.
0.8.1
PDF and annotation-preview resources now keep their precise MIME type when read by clients.
PDF downloads report progress and return a clear WebDAV timeout error.
health_checkreports API-key write permission without modifying the library.Server instructions are shorter, reducing repeated client context usage.
How it works
You provide a DOI, arXiv ID, or ISBN
The server queries the appropriate API to get full metadata:
DOI → CrossRef API
arXiv ID → arXiv API (with CrossRef fallback when a DOI exists)
ISBN → Open Library API
Metadata is mapped to Zotero's item format (title, authors, journal/publisher, date, etc.)
The item is created in your Zotero library via the Zotero Web API
License
MIT
mcp-name: io.github.RaulSimpetru/zotero-library-mcp
Available Tools
51 toolsadd_book_by_isbnAdd Book By IsbnB
Add a book to your Zotero library by its ISBN.
Resolves metadata automatically via Open Library and creates the item in Zotero. Optionally add it to a specific collection.
Args: isbn: The ISBN of the book (e.g. "9780262046824") collection_id: Optional Zotero collection key to add the book to
Inputs: isbn (required), library_id, library_type, collection_id. Returns: result
add_item_from_metadataAdd Item From MetadataB
Add an item from manual, CSL-like, or previously parsed metadata.
The Zotero item template determines which fields are accepted for the requested item type, preventing invalid cross-type metadata.
Inputs: title (required), item_type (required), fields, creators, +3 more. Returns: result
add_noteAdd NoteB
Add a note to a Zotero item.
The note is created as a child of the specified item. Supports HTML formatting (e.g. bold, italic, lists).
Args: item_key: The parent Zotero item key to attach the note to note: The note content (plain text or HTML)
Inputs: note (required), item_key (required), library_id, library_type. Returns: result
add_paper_by_arxiv_idAdd Paper By Arxiv IdA
Add a paper to your Zotero library by its arXiv ID.
Fetches metadata from the arXiv API. If the paper has a DOI, resolves it via CrossRef for richer metadata; otherwise creates a preprint entry directly. Optionally add it to a specific collection.
Args: arxiv_id: The arXiv ID of the paper (e.g. "2301.07041") collection_id: Optional Zotero collection key to add the paper to
Inputs: arxiv_id (required), library_id, library_type, collection_id. Returns: result
add_paper_by_doiAdd Paper By DoiA
Add a paper to your Zotero library by its DOI.
Resolves metadata automatically via CrossRef and creates the item in Zotero. Optionally add it to a specific collection.
Args: doi: The DOI of the paper (e.g. "10.1038/nature12373") collection_id: Optional Zotero collection key to add the paper to
Inputs: doi (required), library_id, library_type, collection_id. Returns: result
add_papers_by_doisAdd Papers By DoisB
Add multiple papers to Zotero by their DOIs (batch, up to 50).
Args: dois: List of DOIs to add collection_id: Optional Zotero collection key to add all papers to
Inputs: dois (required), library_id, attach_pdfs, library_type, +1 more. Returns: result
add_tagsAdd TagsB
Add one or more tags to a Zotero item. Optionally assign a color to all added tags.
Args: item_key: The Zotero item key tags: List of tags to add color: Optional hex color code (e.g. '#FF0000') to assign to the added tags
Inputs: tags (required), item_key (required), color, library_id, +1 more. Returns: result
add_to_collectionAdd To CollectionB
Add an existing Zotero item to a collection.
Args: item_key: The Zotero item key (from search results) collection_id: The collection key to add it to
Inputs: item_key (required), collection_id (required), library_id, library_type. Returns: result
attach_fileAttach FileB
Attach a ChatGPT file input or an authorized local file to an item.
Args: item_key: The Zotero item key to attach the file to file: File object supplied by ChatGPT through openai/fileParams file_path: Local server path; stdio only unless HTTP roots are explicitly enabled
Inputs: item_key (required), file, file_path, library_id, +1 more. Returns: result
create_annotationCreate AnnotationA
Highlight a text passage in a PDF attached to a Zotero item.
Searches the PDF for the quoted text and creates a visible highlight annotation in Zotero's PDF reader. Tries a normalized word match first, then fuzzy matching (for OCR errors, hyphenation differences, or minor transcription mismatches).
Smart overlap handling:
If the same text is already highlighted, appends the new comment to the existing annotation instead of creating a duplicate.
If the new text is a sub-passage of an existing highlight (or vice versa), the new highlight is created in a contrasting color so both are visually distinct.
Args: item_key: The Zotero item key (the parent item, not the attachment) quoted_text: The text passage to highlight in the PDF (fuzzy matching handles minor differences from the actual PDF text) comment: Optional comment to attach to the highlight color: Highlight color as hex (default "#ffd400" yellow) max_l_dist: Maximum Levenshtein distance for fuzzy matching. Default is ~20% of the search text length. Increase if the PDF has many OCR errors; decrease for stricter matching. attachment_key: Optional PDF attachment key when the item has multiple PDFs page_number: Optional one-based page number to search occurrence: One-based occurrence to highlight when text repeats
Inputs: item_key (required), quoted_text (required), color, comment, +6 more. Returns: result
create_collectionCreate CollectionC
Create a new collection in your Zotero library.
Args: name: Name for the new collection parent_collection_id: Optional parent collection key to nest under
Inputs: name (required), library_id, library_type, parent_collection_id. Returns: result
delete_annotationDelete AnnotationCDestructive
Permanently delete a Zotero annotation.
Inputs: annotation_key (required), library_id, library_type. Returns: result
delete_collectionDelete CollectionADestructive
Permanently delete a collection from your Zotero library.
Items in the collection are NOT deleted — they remain in your library.
Args: collection_id: The collection key to delete
Inputs: collection_id (required), library_id, library_type. Returns: result
delete_itemDelete ItemBDestructive
Permanently delete an item from your Zotero library.
Args: item_key: The Zotero item key to delete
Inputs: item_key (required), library_id, library_type. Returns: result
delete_noteDelete NoteCDestructive
Permanently delete a Zotero note.
Inputs: note_key (required), library_id, library_type. Returns: result
delete_tagsDelete TagsBDestructive
Delete tags from the entire Zotero library. This removes the tags from all items.
Args: tags: List of tag names to delete from the library
Inputs: tags (required), library_id, library_type. Returns: result
download_pdfDownload PdfARead-onlyIdempotent
Return a PDF as a remote-safe MCP resource link.
Useful when Zotero's fulltext index is incomplete (e.g. for books) and you need to read the PDF directly with other tools.
Args: item_key: The Zotero item key (the parent item, not the attachment) attachment_key: Optional PDF attachment key when the item has multiple PDFs
Inputs: item_key (required), library_id, library_type, attachment_key. Returns: result
fetchFetchCRead-onlyIdempotent
Company-knowledge compatible fetch for one Zotero item key.
Inputs: id (required), library_id, library_type. Returns: object
find_duplicatesFind DuplicatesBRead-onlyIdempotent
Find duplicate top-level items by DOI, ISBN, or normalized title.
Inputs: field, limit, library_id, library_type. Returns: object
get_annotationsGet AnnotationsBRead-onlyIdempotent
List all highlights and annotations on a paper's PDF.
Args: item_key: The Zotero item key (the parent item, not the attachment) limit: Maximum number of annotations to return (default 100)
Inputs: item_key (required), limit, library_id, library_type. Returns: result
get_bibtexGet BibtexARead-onlyIdempotent
Export BibTeX entries from your Zotero library.
Can export specific items, an entire collection, or your whole library. Use save_bibtex when the export should be written to a local file.
Args: item_keys: Optional list of item keys to export. If omitted, exports collection or full library. collection_id: Optional collection key to export all items from. include_abstract: Include abstracts in BibTeX output (default False to save tokens). biblatex: Convert output to BibLaTeX format (default False). Remaps fields like journal→journaltitle, address→location, and merges year+month into date. max_chars: Maximum response size; use save_bibtex for larger full-library exports
Inputs: biblatex, item_keys, max_chars, library_id, +3 more. Returns: result
get_collection_itemsGet Collection ItemsBRead-onlyIdempotent
Get items in a specific collection, one page at a time.
Args: collection_id: The collection key to browse limit: Maximum number of items to return per page (default 25, max 100) start: Offset of the first item; pass the value suggested by the previous call's footer to fetch the next page (default 0)
Inputs: collection_id (required), limit, start, library_id, +1 more. Returns: result
get_item_detailsGet Item DetailsCRead-onlyIdempotent
Get full details of a Zotero item by its key.
Args: item_key: The Zotero item key
Inputs: item_key (required), library_id, library_type. Returns: result
get_item_fulltextGet Item FulltextARead-onlyIdempotent
Get bounded plain text from a paper's PDF or Zotero full-text index.
Unlike download_pdf, this returns readable text directly and never exposes a server-local temporary path.
Args: item_key: The Zotero item key (the parent item, not the attachment) attachment_key: Optional PDF attachment key when an item has several PDFs max_chars: Maximum number of characters to return (1,000-200,000)
Inputs: item_key (required), max_chars, library_id, library_type, +1 more. Returns: result
get_recent_itemsGet Recent ItemsCRead-onlyIdempotent
Get recently added items from your Zotero library.
Args: limit: Maximum number of items to return (default 10)
Inputs: limit, library_id, library_type. Returns: result
get_unfiled_itemsGet Unfiled ItemsBRead-onlyIdempotent
Get items that are not in any collection (unfiled items).
Args: limit: Maximum number of items to return (default 25)
Inputs: limit, library_id, library_type. Returns: result
health_checkHealth CheckARead-onlyIdempotent
Check Zotero credentials, library access, and optional file storage setup.
Inputs: library_id, library_type. Returns: object
list_attachmentsList AttachmentsCRead-onlyIdempotent
List attachment keys, filenames, MIME types, links, and sizes for an item.
Inputs: item_key (required), limit, library_id, library_type. Returns: object
list_collectionsList CollectionsCRead-onlyIdempotent
List all collections in your Zotero library.
Inputs: library_id, library_type. Returns: result
list_librariesList LibrariesARead-onlyIdempotent
List the key owner's personal library and a page of shared group libraries.
Use the returned library_id and library_type on subsequent tool calls. This does not change the default library. Pagination applies to groups; the personal library is included on each page. Key permissions are not a guarantee of group membership rights; Zotero enforces access on each call.
Inputs: limit, start. Returns: object
list_notesList NotesCRead-onlyIdempotent
List child notes for an item with bounded note content.
Inputs: item_key (required), limit, library_id, library_type. Returns: object
list_tagsList TagsCRead-onlyIdempotent
List all tags in your Zotero library.
Args: limit: Maximum number of tags to return (default 100)
Inputs: limit, library_id, library_type. Returns: result
list_trashList TrashARead-onlyIdempotent
List items in Zotero's trash, e.g. to find a key for restore_item.
Args: limit: Maximum number of items per page (default 25, max 100) start: Offset of the first item; use the footer's suggestion for the next page
Inputs: limit, start, library_id, library_type. Returns: result
move_collectionMove CollectionC
Move a collection under another collection, or to the library root.
Inputs: collection_id (required), library_id, library_type, parent_collection_id. Returns: result
remove_from_collectionRemove From CollectionA
Remove an item from a collection without deleting it from the library.
Args: item_key: The Zotero item key collection_id: The collection key to remove it from
Inputs: item_key (required), collection_id (required), library_id, library_type. Returns: result
remove_tagsRemove TagsC
Remove one or more tags from a Zotero item.
Args: item_key: The Zotero item key tags: List of tags to remove
Inputs: tags (required), item_key (required), library_id, library_type. Returns: result
rename_collectionRename CollectionB
Rename a Zotero collection without changing its parent.
Inputs: new_name (required), collection_id (required), library_id, library_type. Returns: result
rename_tagRename TagB
Rename a tag across all items in the Zotero library.
Args: old_name: The current tag name new_name: The new tag name to replace it with
Inputs: new_name (required), old_name (required), library_id, library_type. Returns: result
restore_itemRestore ItemC
Restore an item from Zotero's trash.
Inputs: item_key (required), library_id, library_type. Returns: result
save_bibtexSave BibtexBDestructive
Export BibTeX or BibLaTeX and atomically write it to a local file.
Path writes are available by default over local stdio. HTTP deployments must explicitly allow a confined file root.
Inputs: save_path (required), biblatex, item_keys, library_id, +3 more. Returns: result
save_pdfSave PdfCDestructive
Save a Zotero PDF to an authorized local server path.
Inputs: item_key (required), save_path (required), library_id, library_type, +1 more. Returns: result
searchSearchCRead-onlyIdempotent
Company-knowledge compatible search over Zotero items and full text.
Inputs: query (required), library_id, library_type. Returns: object
search_fulltextSearch FulltextCRead-onlyIdempotent
Search Zotero metadata and indexed full text using qmode=everything.
Inputs: query (required), limit, library_id, library_type. Returns: object
search_librarySearch LibraryARead-onlyIdempotent
Search your Zotero library. Falls back to fuzzy matching if the exact search returns no results.
Args: query: Search query matched against titles, creators, and year (use search_fulltext for abstracts, notes, and PDF text) limit: Maximum number of results per page (default 10, max 100) start: Offset of the first result; pass the value suggested by the previous call's footer to fetch the next page (default 0)
Inputs: query (required), limit, start, library_id, +1 more. Returns: result
set_tag_colorSet Tag ColorB
Assign a color to a tag in the Zotero library. Colored tags appear in the tag selector and item lists.
Args: tag: The tag name to colorize color: Hex color code (e.g. '#FF0000' for red, '#3366CC' for blue) position: Sort position for the colored tag (0-8, lower = higher priority)
Inputs: tag (required), color (required), position, library_id, +1 more. Returns: result
trash_itemTrash ItemB
Move an item to Zotero's trash so it can be restored later.
Inputs: item_key (required), library_id, library_type. Returns: result
unset_tag_colorUnset Tag ColorA
Remove a tag's assigned library color without deleting the tag.
Inputs: tag (required), library_id, library_type. Returns: result
update_annotationUpdate AnnotationC
Update the comment and/or highlight color of an annotation.
Inputs: annotation_key (required), color, comment, library_id, +1 more. Returns: result
update_item_metadataUpdate Item MetadataB
Update selected bibliographic fields and optionally replace creators.
Immutable/internal fields such as item type, key, version, parent item, collections, tags, and deletion state cannot be changed through this tool.
Inputs: updates (required), item_key (required), creators, library_id, +1 more. Returns: result
update_noteUpdate NoteC
Replace the content of an existing Zotero note.
Inputs: note (required), note_key (required), library_id, library_type. Returns: result
verify_itemsVerify ItemsARead-onlyIdempotent
Verify that recently added items have valid DOIs that match CrossRef metadata.
Re-resolves each item's DOI via CrossRef and compares the title. Reports items that have no DOI, DOIs that don't resolve, or title mismatches.
Args: limit: Number of recent items to check (default 10)
Inputs: limit, library_id, library_type. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 51 tools
Most tools target distinct Zotero resources and actions, but search_library, search_fulltext, and search overlap heavily, and fetch duplicates get_item_details. An agent could struggle to choose the right search or retrieval tool without trial and error.
Predominantly snake_case verb_noun (add_paper_by_doi, list_collections, delete_item). Minor deviations like health_check and bare verbs search/fetch are readable but slightly inconsistent.
51 tools is far beyond the 25+ threshold and qualifies as an extreme mismatch for a single MCP server. While the domain is broad, many tools could be consolidated, such as search variants, batch/single adds, and attachment operations.
The surface covers items, collections, tags, notes, annotations, imports/exports, trash, search, and libraries very thoroughly. Minor gaps remain, such as explicit attachment deletion/update and batch item operations.
Maintenance
Related MCP Connectors
Zotero MCP server for Claude and ChatGPT: search, citations, safe writes, PDF passages and pages.
Remote MCP server for full read/write access to a Zotero library
Hosted MCP server connecting AI assistants to 9,000+ apps and 40,000+ actions via Zapier.
An MCP server that gives your AI access to the source code and docs of all public github repos
Related MCP Servers
- AlicenseAqualityCmaintenanceA lightweight MCP server that connects AI agents to a local Zotero library for paper management and metadata retrieval. It enables users to search titles and abstracts, browse collections, and automatically ingest papers via arXiv ID or DOI with PDF attachments.821MIT
- AlicenseAqualityCmaintenanceA lightweight and customizable MCP server for Zotero that enables AI research tools to access and manage references through a simple API.96MIT
- AlicenseAqualityBmaintenanceMCP server that lets AI assistants search, create, organize, and cite from a Zotero library.394MIT
- AlicenseNot gradedqualityDmaintenanceMCP server that connects AI assistants to your Zotero library, enabling full-text PDF extraction and metadata search.MIT