Skip to main content
Glama

zotero-mcp

Portable MCP stdio server for Zotero Desktop. It keeps Local API reading, adds an authenticated in-process Bridge for Zotero 9.0.6 writes, and never edits Zotero SQLite or storage files directly.

This package intentionally excludes paper-reading queues, worker pools, reading-note templates, and the Codex zotero-reader skill.

Requirements

  • Windows, macOS, or Linux

  • Zotero Desktop 7, 8, or 9 running locally

  • Python 3.10+

  • An MCP host that supports stdio servers

Related MCP server: @xbghc/zotero-mcp

Start the MCP server

Windows hosts can use run.cmd:

{
  "mcpServers": {
    "zotero-mcp": {
      "command": "cmd.exe",
      "args": ["/d", "/c", "C:\\Tools\\zotero-mcp\\run.cmd"],
      "env": {
        "ZOTERO_LOCAL_BASE_URL": "http://127.0.0.1:23119",
        "ZOTERO_BRIDGE_CONFIG": "C:\\Users\\<user>\\AppData\\Roaming\\zotero-mcp\\bridge.json",
        "NO_PROXY": "localhost,127.0.0.1,::1",
        "PYTHONUTF8": "1"
      }
    }
  }
}

Unix hosts can run run.sh or use the Unix example configuration. Replace all paths for the target computer.

Local API

Zotero normally exposes the read service at http://127.0.0.1:23119. See LOCAL-API-GUIDE.md for enabling local communication, checking the service, proxy handling, and read-only troubleshooting.

Local API reads do not need an API key. Zotero 9.0.6 may omit Zotero-Server-ID; that means Local API writes are unavailable, not that the MCP should bypass capability detection.

Zotero Bridge

Zotero 9.0.6 can expose the Local API for reading without the older Local API write authorization header. The optional zotero-bridge/ legacy bootstrap extension runs inside Zotero and calls Zotero internal object APIs (saveTx, trashTx, eraseTx, and relinkAttachmentFile). It is the write transport for this build.

Install and pair

The current Bridge package is 1.4.4 and declares compatibility with Zotero 9.0.x. If Zotero rejects an older XPI as incompatible, rebuild and install the newly generated zotero-mcp-bridge.xpi. Zotero Debug Bridge is a different extension and cannot replace this Bridge.

  1. Keep Zotero open and run powershell -ExecutionPolicy Bypass -File .\zotero-bridge\build-xpi.ps1 to create the XPI with manifest.json, bootstrap.js, bridge-server.js, and PROTOCOL.md at the archive root.

  2. In Zotero choose Tools -> Add-ons -> gear -> Install Add-on From File, select the XPI, and restart Zotero if requested.

  3. When the extension is running it creates %APPDATA%\zotero-mcp\bridge.json with a random token, loopback host, port 23120, and protocol zotero-bridge/1.

  4. Point ZOTERO_BRIDGE_CONFIG to that file only when using a non-default location. Do not commit or share the file: the token grants write access to the local Zotero instance.

  5. Call zotero_capabilities or run run.ps1 -Check. A working Zotero 9 Bridge reports bridgeOnline=true, bridgeWrite=true, and writeTransport=bridge.

The Bridge binds only to 127.0.0.1. It removes its config file on shutdown if the file still belongs to that instance. GET /v1/capabilities is unauthenticated for health detection; every PATCH, POST, and DELETE request requires Authorization: Bearer <token>.

Bridge protocol

Implemented routes are documented in zotero-bridge/PROTOCOL.md: item metadata, tags, collections, notes, attachment replacement, trash, restore, and permanent erase. The Bridge validates field whitelists, parent-child relationships, expected versions, confirmation phrases, attachment paths, and file sizes before calling Zotero.

Capabilities and fallback

zotero_capabilities reports Local API and Bridge state separately: localApiRead, localApiWrite, bridgeOnline, bridgeWrite, bridgeTrash, bridgePermanentDelete, bridgeAttachmentWrite, bridgeNoteWrite, and the active writeTransport.

  • Bridge online and writable: metadata, tags, collections, notes, attachments, trash, restore, and permanent deletion use the Bridge.

  • Bridge unavailable but an older Local API exposes Zotero-Server-ID: existing Local API write paths remain available.

  • Neither transport writable: only read tools are listed.

  • tools/list and tools/call both re-check capabilities, so an old client cannot call a tool after the Bridge goes offline.

Edit and delete safety

All mutating MCP tools require confirm=true. Metadata fields are whitelisted; creators, tags, collections, notes, and attachments use dedicated validation. Edit tools may resolve the current version when omitted; destructive delete and restore tools require the caller to supply expectedVersion and reject conflicts.

zotero_delete_item defaults to mode="trash". A parent with child notes or attachments, including already-trashed descendants and PDF annotations, is rejected unless cascadeChildren=true is explicit. Trash cascades through the discovered descendants; permanent deletion additionally requires mode="permanent", confirm=true, and the exact phrase DELETE <itemKey>. When targeting a child item through the item route, pass its parentItem key so the Bridge can verify the relationship. zotero_restore_item restores a trashed item and can explicitly restore descendants.

Attachment replacement accepts only an absolute path to a regular source file outside Zotero data storage, enforces maxBytes, checks optional MD5/version preconditions, and lets Zotero copy it into managed storage. MCP never receives a storage path operation.

Tools

  • Read: zotero_status, zotero_capabilities, zotero_probe, collections, inventory, search, batch item lookup, children, full text, file URLs, tags, groups, BibTeX, citations, and Connector selection.

  • Edit: zotero_update_item, zotero_update_tags, zotero_move_item, zotero_create_note, zotero_update_note, zotero_replace_attachment.

  • Delete/restore: zotero_delete_note, zotero_delete_item, zotero_restore_item.

  • Legacy Local API only: zotero_authorize_writes and zotero_import_records.

List tools support start/limit pagination. zotero_get_items batches keys in chunks.

Tests

py -3.13 -m py_compile server.py zotero_client.py
node --check zotero-bridge/bridge-server.js
node --check zotero-bridge/bootstrap.js
py -3.13 -m unittest discover -s tests -v
git diff --check

Unit tests use mocks and never modify formal Zotero data. Real integration tests must use a disposable Zotero item. The live read-only checks are opt-in with ZOTERO_MCP_LIVE=1; Bridge write integration should be run only after pairing the extension and creating a temporary test item. The opt-in destructive MCP runner is tests/live_bridge_smoke.py and requires the acknowledgement I_HAVE_A_TEMPORARY_ZOTERO_ITEM.

Limitations

The Bridge must be installed and Zotero must remain running for Zotero 9.0.6 writes. Group-library permissions, read-only libraries, locked files, linked URL attachments, and unsupported attachment types can still be rejected by Zotero. When the Bridge is offline, the MCP intentionally degrades instead of modifying SQLite or storage directly.

For setup details see LOCAL-API-GUIDE.md, zotero-bridge/PROTOCOL.md, and the Chinese guide README.zh-CN.md.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables LLM clients to browse and query your Zotero library through tool calls. Provides access to Zotero-specific functions like listing open tabs, searching items, and browsing collections via a local MCP server running inside Zotero.
    1
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    MCP server for interacting with a Zotero library via the local API. Enables searching, retrieving, creating, updating, and deleting Zotero items, managing collections and tags, and generating citations.
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables Zotero 10 library management via MCP, allowing search, metadata retrieval, annotation and collection management, and optional write operations (notes, tags, metadata, items) through a local Streamable HTTP endpoint.
    MIT