Skip to main content
Glama
zotero-mcp-server

zotero-mcp-server

Zotero Toolkit

Tools for Zotero: MCP servers, Zotero plugins and agent skills for reference management and systematic/scoping review workflows.

Built for real review work - screening decisions, exclusion logging, PRISMA record accounting - rather than as a demo.

What's here

Component

Runs where

Status

mcp/zotero-mcp-server

Any MCP client, or as a standalone CLI

v1.3.0

plugins/pdf-file-attacher (AutoAttach)

Inside the Zotero desktop app (.xpi, Zotero 7–10)

v1.5.0

agent-skills/

Loaded by an AI agent

3 skills

core/

Shared libraries

not yet needed

docs/

Cross-package documentation

in progress

zotero-toolkit/
├── mcp/                      # MCP servers (npm workspaces)
│   └── zotero-mcp-server/    # 25 tools + 4 prompts over the Zotero Web API, plus a CLI
├── plugins/                  # Zotero .xpi add-ons, using Zotero's internal API
├── agent-skills/             # research workflows for AI agents (SKILL.md)
├── core/                     # shared libraries, once >1 package needs them
└── docs/                     # cross-package documentation

AutoAttach matches downloaded PDFs to the items you already have by reading what is inside each file — DOI, arXiv ID, embedded metadata, first-page text — rather than comparing filenames. It also verifies titles, abstracts, and document languages offline against attached PDFs, and online against Crossref, OpenAlex, and Europe PMC (plus retraction screening). Every match or repair carries the evidence it was made on, with filter tabs, live search, and a side-by-side Further Review Inspector (Inspect ▸) so nothing is written until you confirm:

The AutoAttach v1.5 review dialog: filter tabs, live search, score badges,
confidence bars, and close-call warnings

The Further Review Inspector: side-by-side comparison of current Zotero
metadata, extracted PDF text preview, and proposed changes

Online DOI lookup against Crossref and OpenAlex with strict title, author,
and year corroboration

It runs inside Zotero, and every command ends in that same reviewed dialog:

The review dialog open over the Zotero library
window

The item context menu, with the online commands carrying a globe icon and an
Online label

Two different integration points, deliberately:

  • MCP servers talk to the Zotero Web API over HTTPS. They work from any machine against your synced library and need no desktop app, but only see items that have synced.

  • Plugins run inside Zotero using its internal API. They work offline and can touch local files and attachments, but must be installed in the app.

Related MCP server: zotero-api-mcp

Quick start

The MCP server is the finished piece. Requires Node.js 18+.

git clone https://github.com/adolinjonathan-bot/zotero-toolkit.git
cd zotero-toolkit
npm install
npm run build
npm run verify     # 11 checks, no credentials needed

Then follow mcp/zotero-mcp-server/README.md to create a Zotero API key and connect a client - Claude Desktop, Claude Code, Cursor, Zed, Continue, VS Code, LM Studio, or a local open-source model.

It also runs as a plain CLI with no AI involved at all:

node mcp/zotero-mcp-server/dist/cli.js search "youth employability" --limit 10

Repository conventions

  • npm install once at the root; workspaces cover mcp/* and core/*. agent-skills/ is documentation, not code, and is deliberately excluded.

  • npm run build and npm run verify fan out across every package.

  • Build output (dist/, build/, *.xpi) is not committed. Plugin .xpi files ship as GitHub Release assets so each download traces to a source commit.

  • Every package carries its own README; this file stays an index.

Licence

MIT - see LICENSE.

Credits

Initial implementation generated with Claude, then debugged, hardened and tested against a live research library.

Available Tools

12 tools
zotero_add_items_to_collectionAdd Items To Zotero CollectionA
Idempotent

Add one or more existing items to a Zotero collection, without needing to fetch or manage version numbers.

Args:

  • collection_key (string, required)

  • item_keys (string[], required, max 50)

This adds to the collection; it does not remove the items from any collection they're already in, and does not affect other items already in the target collection.

Inputs: item_keys (required), collection_key (required).

zotero_create_collectionCreate Zotero CollectionA

Create a new collection (folder) in the Zotero library.

Args:

  • name (string, required)

  • parent_collection_key (string, optional): nest under this collection; omit for a top-level collection

Returns the new collection's key, for use with zotero_add_items_to_collection.

Inputs: name (required), parent_collection_key.

zotero_create_itemCreate Zotero ItemA

Create a new top-level item (reference) in the Zotero library.

Args:

  • item_type (string, required): Zotero item type, e.g. "journalArticle", "book", "report", "webpage"

  • title, creators, date, abstract_note, url, doi (optional)

  • tags (string[], optional): tag labels to attach

  • collection_keys (string[], optional): file the item into these collections immediately

  • extra_fields (object, optional): any other valid Zotero field for the item type, e.g. {"publicationTitle": "Journal of X", "volume": "12", "issue": "3", "pages": "1-10"}

Returns the created item's key and version. This is a destructive/write operation - it permanently adds to the user's library.

Examples:

  • Use when: "Add this journal article to my Zotero library" -> item_type="journalArticle", title=..., creators=[...], extra_fields={publicationTitle: ..., volume: ...}

  • Don't use when: the item might already exist (search first with zotero_search_items to avoid duplicates)

Inputs: item_type (required), doi, url, date, +6 more.

zotero_create_noteCreate Zotero NoteA

Create a standalone note or a child note attached to an existing item.

Args:

  • note_html (string, required): note content as HTML (sanitised automatically by Zotero)

  • parent_item_key (string, optional): attach as a child note under this item; omit for a standalone note

  • tags (string[], optional)

Use for recording reading notes, screening decisions, or extraction summaries against a reference.

Inputs: note_html (required), tags, parent_item_key.

zotero_delete_itemDelete Zotero ItemA
DestructiveIdempotent

Delete an item from the Zotero library.

Args:

  • item_key (string, required)

  • current_version (number, required): the item's version from zotero_get_item, to confirm you're deleting the version you expect

  • permanent (boolean, default false): false moves the item to the trash (recoverable); true erases it irreversibly

This is a destructive operation, and the library is synced - the deletion propagates to the user's desktop Zotero and any other synced device. Always confirm with the user before calling this. Never pass permanent=true unless the user has explicitly asked for irreversible deletion; the default trash behaviour leaves them able to undo it.

Inputs: item_key (required), current_version (required), permanent.

zotero_get_collection_itemsGet Items In Zotero CollectionA
Read-onlyIdempotent

List the items filed under a specific Zotero collection.

Args:

  • collection_key (string, required)

  • limit (number, default 50, max 100)

  • start (number, default 0): pagination offset

  • response_format ('markdown' | 'json', default 'markdown')

Returns the items in the collection (not sub-collections). For a broader text search restricted to a collection, use zotero_search_items with collection_key instead.

Inputs: collection_key (required), limit, start, response_format.

zotero_get_itemGet Zotero ItemA
Read-onlyIdempotent

Fetch full metadata for a single Zotero item by its key.

Args:

  • item_key (string, required)

  • response_format ('markdown' | 'json', default 'markdown')

Returns all fields for the item, including the current 'version' number, which is required for zotero_update_item and zotero_delete_item to avoid overwriting concurrent changes.

Error Handling:

  • Returns "Error: ... Not Found (404)" if the key does not exist in this library

Inputs: item_key (required), response_format.

zotero_get_item_childrenGet Zotero Item ChildrenA
Read-onlyIdempotent

List the child items (attachments and notes) of a parent Zotero item.

Args:

  • item_key (string, required): the parent item's key

  • response_format ('markdown' | 'json', default 'markdown')

Returns attachments (PDFs, links) and notes attached to the item, each with its own key. Use this to find a PDF attachment's key or to read existing notes before adding a new one.

Inputs: item_key (required), response_format.

zotero_list_collectionsList Zotero CollectionsA
Read-onlyIdempotent

List collections (folders) in the Zotero library.

Args:

  • parent_collection_key (string, optional): list sub-collections of this collection; omit for top-level collections

  • response_format ('markdown' | 'json', default 'markdown')

Returns each collection's key, name, and item count. Use a collection's key with zotero_get_collection_items or zotero_add_items_to_collection.

Inputs: response_format, parent_collection_key.

zotero_list_tagsList Zotero TagsA
Read-onlyIdempotent

List tags used in the Zotero library, optionally filtered by substring.

Args:

  • filter (string, optional): only return tags containing this text

  • limit (number, default 100, max 200)

Useful for discovering the exact tag spelling before using it in zotero_search_items or zotero_update_item.

Inputs: limit, filter.

zotero_search_itemsSearch Zotero ItemsA
Read-onlyIdempotent

Search the Zotero library for items (references), matching against title, creator names, and full text of attached PDFs.

Args:

  • query (string, optional): search text. Omit it to browse by filter alone.

  • item_type (string, optional): filter to one Zotero item type (e.g. "journalArticle")

  • tag (string, optional): filter to items carrying this exact tag

  • collection_key (string, optional): search within one collection only

  • limit (number, default 25, max 100)

  • start (number, default 0): pagination offset

  • response_format ('markdown' | 'json', default 'markdown')

Returns matching items with key, title, creators, date, tags, and abstract. Use the item 'key' with zotero_get_item, zotero_update_item, or zotero_get_item_children for further work.

Does NOT create or modify anything - read-only.

Examples:

  • Use when: "Find items in my library about digital youth mentorship" -> query="digital youth mentorship"

  • Use when: "Show journal articles tagged 'AI literacy'" -> omit query, item_type="journalArticle", tag="AI literacy"

  • Don't use when: you already have the item key (use zotero_get_item instead)

Inputs: tag, limit, query, start, +3 more.

zotero_update_itemUpdate Zotero ItemA
Idempotent

Apply a partial update to an existing Zotero item.

Args:

  • item_key (string, required)

  • current_version (number, required): the item's version at the time you last read it (from zotero_get_item). Prevents accidentally overwriting a concurrent edit.

  • fields (object, required): the fields to change, e.g. {"title": "Corrected Title", "date": "2026"}. Array-valued fields (tags, collections) are REPLACED entirely, so include the full desired array, not just the additions.

Returns the updated item. Fails with a version-mismatch error if the item changed since current_version was read - in that case, call zotero_get_item again and retry.

Don't use when: adding the item to a collection is the only goal - zotero_add_items_to_collection is simpler and avoids the version-conflict risk.

Inputs: fields (required), item_key (required), current_version (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.3/5.0

    Scored across 12 tools

    Disambiguation5/5

    Each tool targets a distinct action on a specific resource (collections, items, tags, notes). The descriptions clearly differentiate purposes, and there is no overlap or ambiguity.

    Naming Consistency5/5

    All tool names follow a consistent 'zotero_verb_noun' pattern in snake_case, such as 'zotero_create_collection' and 'zotero_search_items'. No mixing of conventions.

    Tool Count5/5

    12 tools cover the core operations for a Zotero library (CRUD for items, collections, notes, search, tags). Each tool is justified and well-scoped for the domain.

    Completeness3/5

    The tool set is mostly complete but lacks delete/update operations for collections and a remove-items-from-collection tool. These gaps can hinder certain workflows.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      C
      quality
      D
      maintenance
      Enables interaction with Zotero libraries for searching, managing collections, items, tags, and attachments, plus optional semantic search across PDFs via local embeddings.
      38
      20 PyPI
      2
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables managing Zotero libraries via the official Web API v3, including searching, creating, editing, and deleting items, collections, tags, notes, attachments, and performing batch operations, syncs, and file uploads/downloads.
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables searching, paging, and fetching items from a personal Zotero library, issuing Zotero Web API v3 requests, uploading files to attachments, and replacing citation markers in Word documents with Zotero fields the plugin can refresh.
      7
      MIT