zotero-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| XDG_DATA_HOME | No | Standard XDG override for the default graph DB location | |
| ZOTERO_API_KEY | Yes | Zotero Web API key — get at zotero.org/settings/keys | |
| ZOTERO_USER_ID | Yes | Zotero user/group ID — same page as the API key | |
| ZOTERO_DATA_DIR | No | Override path to Zotero desktop data directory (default: ~/Zotero) | |
| OPENALEX_API_KEY | No | Required for analysis and knowledge graph tools — free at openalex.org/users/me | |
| ZOTERO_MCP_EMAIL | No | Your email address sent in User-Agent headers to CrossRef/OpenAlex polite pools and required for Unpaywall PDF lookup | |
| ZOTERO_MCP_GRAPH_DB | No | Override path for the knowledge-graph SQLite database | |
| PARENT_WATCHDOG_DISABLE | No | Set to 1 to disable the orphan-process watchdog | |
| SEMANTIC_SCHOLAR_API_KEY | No | Improves rate limits for find_related_papers — free at semanticscholar.org |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| logging | {} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| extensions | {
"io.modelcontextprotocol/ui": {}
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| server_statusA | Check which Zotero MCP operating modes are available and get fix instructions for any that are misconfigured. Use this first when tools return 'unavailable' errors or when starting a new session to verify connectivity. |
| search_itemsA | Search Zotero library items by keyword. Use this when the user asks to find papers, look up references, or search their library. Supports title, author, and tag matching. Filter by item_type (e.g. 'journalArticle', 'book') or tag (exact tag name). |
| get_itemA | Get detailed metadata for a single Zotero item by its key. Use this when you need full bibliographic details (title, authors, DOI, abstract, dates) for a specific item. Set format='bibtex' for BibTeX export. |
| get_collectionsA | List all collections (folders) in the Zotero library with their keys, names, parent relationships, and item counts. Use this when the user asks about their library organization or wants to browse/find a collection. |
| get_notesA | Get all notes attached to a Zotero item. Use this when the user wants to read their annotations, reading notes, or comments on a paper. |
| get_item_attachmentsA | List file attachments (PDFs, etc.) on a Zotero item with availability status. Use this to check whether a paper HAS a PDF before fetching it; to actually read the content, use get_pdf_content. Returns {items, count} where each item's availability is one of: stored_remote_available, stored_local_available, linked_local_available, or metadata_only. |
| get_pdf_contentA | Get the full text of a paper in the library. Routes to the best available source: PubMed Central, local PDF, web PDF download, or free open-access PDF. Use this when the user wants to read a paper's content; to only CHECK whether a PDF exists without fetching it, use get_item_attachments first. Set extract_text=true to extract and return the text inline; otherwise returns a file path or PMCID for the caller to read. The response always includes a content_source field (one of: pmc, local_pdf, web_pdf, free_pdf_, extracted_text, not_found) that determines which other fields are present. |
| check_retractionsA | Check whether papers have been retracted or corrected. Uses CrossRef (authoritative) and OpenAlex. Use this when the user asks about paper validity, before citing papers, or as part of a literature audit. Accepts one or more item keys. |
| get_citation_graphA | Get papers that cite or are cited by a Zotero item, via OpenAlex. Use this when the user wants to explore a paper's citation network, find related work, or trace the influence of a paper. Each result is flagged with in_library (true/false). Direction: 'cited_by', 'references', or 'both'. |
| get_collection_itemsA | List all items in a specific Zotero collection by its key. Use this when the user wants to see what's in a particular folder/collection. |
| create_itemA | Add a paper to Zotero from any identifier: DOI, PMID, or URL (PubMed, bioRxiv, arXiv, publisher pages). Resolves metadata automatically and checks for duplicates. Use this when the user wants to save a paper to their library. Optional title is only used for bare URLs that can't be scraped. If you only have structured fields (title/authors/etc.) and no DOI/PMID/URL to resolve, use create_item_manual instead. The result includes dedup_check_failed=true if the duplicate check could not be completed. |
| create_item_manualA | Create a Zotero item with manually provided metadata fields. Use this instead of create_item when you have structured metadata already (e.g. from a conversation) rather than a DOI/URL to resolve. Checks for duplicates. |
| create_noteA | Create a note attached to a Zotero item. Use this to save reading notes, summaries, or annotations on a paper. Supports HTML or plain text content. |
| batch_organizeA | Add tags and/or move multiple items to a collection in one operation. Use this for bulk organization — e.g. tagging a set of search results or grouping papers into a collection. Handles rate limiting and version conflicts. |
| find_duplicatesA | Scan the Zotero library for duplicate items using DOI match and title similarity (>85%). Use this when the user wants to clean up their library or after bulk imports. Optionally scoped to a single collection. |
| create_collectionA | Create a new collection (folder) in Zotero, optionally nested under a parent. Use this when the user wants to organize papers into a new group. |
| check_ssl_healthA | Diagnose Python SSL/TLS certificate configuration. Use when any tool reports CERTIFICATE_VERIFY_FAILED, SSL errors, or HTTPS failures (OpenAlex, CrossRef, PubMed, etc). Returns Python/OpenSSL versions, resolved cert bundle paths, CA count, env-var overrides (flagging any pointing at missing paths), certifi version, live probes against canonical endpoints, a verdict (HEALTHY/DEGRADED/BROKEN), and concrete remediation steps. Safe, read-only. Set probe=False for offline config-only diagnostics. |
| audit_local_keysA | Audit the local Zotero SQLite database for collection/item keys that contain forbidden characters (0, 1, I, O). Such keys are rejected by the Zotero sync server with 'not a valid collection/item key' and halt sync with 'Made no progress during upload -- stopping'. Use this as a diagnostic when the user reports sync errors, or proactively after any bulk library operation. Reads ~/Zotero/zotero.sqlite read-only (override with the ZOTERO_DATA_DIR env var). Returns a summary with the offending keys, their names, and sync state so they can be rekeyed manually before the next sync. |
| add_to_collectionA | Add an existing Zotero item to a collection. Use this to organize a paper into a folder without moving it from other collections. |
| update_itemA | Update metadata fields on an existing Zotero item. Use this to correct titles, authors, dates, DOIs, or other bibliographic fields. Uses optimistic locking to prevent overwriting concurrent changes. |
| trash_itemsA | Move Zotero items to trash (reversible). Use this when the user wants to delete papers. Accepts one or more item keys. Items can be restored from trash in Zotero. Confirm with user before trashing. |
| empty_trashA | Permanently delete ALL items in the Zotero trash. THIS IS IRREVERSIBLE. This is a GLOBAL operation — it destroys everything in the trash, not just items you recently trashed. Call inspect_trash first to see what is in there, and always confirm with the user before calling this tool. |
| inspect_trashA | List everything currently in the Zotero trash, with item type and title. Use this BEFORE empty_trash so the user can see exactly what would be permanently destroyed — empty_trash is global and irreversible. |
| plan_attachment_migrationA | Plan a migration of Zotero imported (cloud-stored) attachments to linked files, which keeps every PDF on local disk but frees Zotero cloud storage quota. READ-ONLY: inventories the library, reports which attachments would be converted, which must be downloaded from the cloud first, and which are skipped and why. Nothing is written, downloaded, or trashed. Run this before migrate_attachments. |
| migrate_attachmentsA | Convert Zotero imported (cloud-stored) attachments into linked files: copy or download each file to local disk, hash-verify it, create a linked_file attachment, then move the original to the trash. Frees cloud storage quota while keeping every file locally. DEFAULTS TO A DRY RUN — pass apply=true to make changes, and only after showing the user plan_attachment_migration output. Never empties the trash; use inspect_trash then empty_trash for that, so the user can review what would be permanently destroyed. |
| manage_tagsA | Manage tags in your Zotero library. Use this when the user asks about tags, wants to list/filter tags, remove a tag from all items, or rename a tag. Actions: 'list' (browse tags, optional prefix filter), 'remove' (DESTRUCTIVE: deletes the tag from every item in the library, not reversible — requires tag), 'rename' (rewrites the tag on every item library-wide — requires tag and new_tag). Confirm with the user before 'remove' or 'rename'. |
| check_published_versionsA | Check if preprints have been formally published in a peer-reviewed journal. Use this when the user has bioRxiv/medRxiv/arXiv papers and wants to know if a final journal version exists. Reports published DOI, journal name, and whether the published version is already in the library. Uses CrossRef and OpenAlex. |
| attach_pdfA | Attach a PDF to a Zotero item. Can auto-download a free PDF via Unpaywall/PMC/bioRxiv, or accept a local file path. Use this when the user wants to add a PDF to a paper that doesn't have one. |
| insert_citationsA | Insert live Zotero citation field codes into an existing Word document. Finds [@ITEM_KEY] markers in the .docx and replaces them with Zotero field codes. Use this to add citations to a document the user already has; to create a NEW .docx from markdown instead, use write_cited_document. Preserves existing formatting, styles, images, and layout. |
| write_cited_documentA | Create a new Word document from markdown text with live Zotero citations. Use [@ITEM_KEY] markers in the content for citations. Use this when writing a new document from scratch (e.g. literature review, manuscript draft). For adding citations to an existing document, use insert_citations instead. |
| build_indexA | Build or update indexes for your Zotero library. Use this after adding new papers to enable graph queries and full-text search. Types: 'graph' (citation network + analytics via OpenAlex — enables query_knowledge_graph, query_authors, export_knowledge_graph), 'fulltext' (PDF text extraction + FTS5 index — enables search_fulltext), 'both' (runs graph then fulltext). Auto-detects full build vs incremental sync. Set full_rebuild=true to force a complete rebuild. |
| query_knowledge_graphA | Query the knowledge graph for insights about your library's citation network. Use this when the user asks about influential papers, research clusters, publication trends, or relationships between papers. Query types: 'influential' (PageRank-ranked papers), 'clusters' (research topic groupings), 'bridges' (papers connecting different clusters), 'path' (shortest citation path between two DOIs — requires doi_a and doi_b), 'neighborhood' (papers within N hops of a DOI — requires doi and optional depth), 'stats' (graph summary), 'timeline' (papers per month — optional topic filter, start_year, end_year), 'topic_evolution' (per-subfield paper counts by month — optional start_year, end_year), 'citation_velocity' (month-by-month citation count for a DOI — requires doi), 'trending' (papers with accelerating citation rates — optional limit, years window). Requires build_index(type='graph') to be run first. |
| find_related_papersA | Find papers related to items in your library via Semantic Scholar recommendations (similar to Connected Papers or ResearchRabbit). Use this when the user wants to discover new papers on a topic. Provide one or more item keys as seeds — the more seeds, the better the recommendations. Each result is flagged with in_library (true/false). |
| search_fulltextA | Search the full text of indexed PDFs in your library. Use this when the user wants to find papers that mention a specific term, method, drug, or concept in their body text (not just titles/abstracts). Returns matching papers with highlighted text snippets. Requires build_index(type='fulltext') to be run first. |
| query_authorsA | Query the author co-authorship network in your knowledge graph. Use this when the user asks about who publishes most, who collaborates with whom, or wants to map out an author's network. Query types: 'prolific' (authors by paper count), 'influential' (authors by summed PageRank of their papers), 'coauthors_of' (co-authors of a named author, ranked by shared papers), 'network' (ego network for an author within N hops — requires author_name, optional depth), 'clusters' (author community groupings). Requires build_index(type='graph') to be run first. |
| export_knowledge_graphA | Export the knowledge graph as an interactive HTML visualization that opens in any browser. Use this when the user wants to see their citation network visually, explore research clusters, or share a graph. Views: 'citations' (paper nodes + citation edges, colored by cluster), 'authors' (author nodes + co-authorship edges), 'full' (both layers, papers capped at 200 by PageRank). Requires build_index(type='graph') to have been run first. |
| get_unextracted_abstractsA | Get papers that have abstracts but no extracted biomedical entities yet. Use this to find papers needing entity extraction, then extract entities (conditions, drugs, genes, biomarkers, methods, outcomes) from the returned abstracts and save them with store_entities. |
| store_entitiesA | Store extracted biomedical entities for papers. Call this after extracting entities from abstracts (via get_unextracted_abstracts or any paper reading). Entity types: condition, biomarker, drug, method, gene, organism, outcome, dataset. Input: list of {doi, entities: [{name, type}]}. |
| search_entitiesA | Search the biomedical entity graph. Use this when the user asks about which papers mention a condition/drug/gene, what entities co-occur, or what two papers have in common. Query types: 'by_name' (papers mentioning an entity), 'by_type' (common entities of a type, or list all types if no type given), 'co_occurrence' (entities that co-occur with a given entity), 'shared_entities' (entities shared by two papers — requires doi_a and doi_b), 'paper_entities' (all entities extracted from a paper — requires doi). |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| literature_audit | Run a full literature audit on selected papers: check for retractions, verify preprint publication status, and scan for duplicates. |
| build_and_explore | Build the knowledge graph and fulltext index, then explore the library's research landscape with influential papers, clusters, and trends. |
| add_and_verify | Add a paper to the library by DOI/PMID/URL, then verify it: check for retractions, find related work, and attach a PDF. |
| extract_entities | Extract biomedical entities from papers that haven't been processed yet, then store them for search and co-occurrence analysis. |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 39 tools
Most tools target a distinct resource+action pair, and potentially confusing clusters are well-differentiated in descriptions (search_items is metadata search, search_fulltext is PDF text, search_entities is the entity graph). A few adjacent pairs — check_retractions vs check_published_versions and get_citation_graph vs find_related_papers vs query_knowledge_graph — occupy overlapping territory and could cause misselection without careful reading.
Nearly all 39 tools follow a consistent verb_noun pattern (get_item, create_collection, trash_items, query_knowledge_graph, export_knowledge_graph), with modifiers like manual and cited_document kept predictable. Two deviations stand out: batch_organize inverts to adverb_verb, and add_to_collection uses a prepositional form rather than a verb_noun structure like add_item_to_collection.
At 39 tools, this is a heavy surface that exceeds the 25+ threshold for comfortable agent navigation. The count is inflated by several niche sub-domains tacked onto core library management — SSL diagnostics, SQLite key auditing, attachment migration planning, and a full biomedical entity extraction pipeline — making the toolset feel bloated even though each individual tool has a defined purpose.
The core item lifecycle is well covered (create, search, get, update, trash, inspect trash, empty trash), and advanced features like citation graphs, full-text search, and retraction checks are solid. Notable gaps remain: notes can be read and created but not updated or deleted, collections cannot be deleted or have items removed from them, duplicates can be found but not merged, and there is no tool to restore trashed items.