Guide · v0.13.1

Install and set up

Install the package, let your AI app reach Zotero, choose local or web access, then connect your client. Most people are done after step 2 and zotero-mcp setup.

Requirements

  • Python 3.10 or newer
  • Zotero 7 or newer for local access and full text. Zotero 10 or newer for local writes.
  • An MCP client such as Claude Desktop, Claude Code, ChatGPT (Developer Mode), Cherry Studio, or Chorus. Or an agent with shell access for the skill.

New to the command line? The community-built Zotero MCP Setup has a macOS installer (DMG), one-click install scripts for Mac and Windows, and a step-by-step guide.

1Install

The base install includes search, metadata, annotations, and write tools, with no ML dependencies. The package is zotero-mcp-server on PyPI. It installs the zotero-mcp and zotero-cli commands.

uv (recommended)
$ uv tool install zotero-mcp-server
$ zotero-mcp setup
pip or pipx
$ pip install zotero-mcp-server
$ pipx install zotero-mcp-server

Optional extras

Larger dependencies are optional extras, so the base install stays small.

ExtraAdds
semanticSemantic search: ChromaDB, sentence-transformers, OpenAI and Gemini embeddings
pdfPDF outlines and figure detection (PyMuPDF), EPUB annotation support
sciteScite citation counts and retraction alerts, no account needed
allAll of the above
$ uv tool install "zotero-mcp-server[all]"
$ pip install "zotero-mcp-server[semantic]"

2Enable Zotero’s local API

Local mode reads from the Zotero app running on your computer, so Zotero must accept connections from other apps.

  1. Open Zotero, then Settings → Advanced. On macOS it’s under Zotero → Settings, on Windows and Linux under Edit → Settings.
  2. Check Allow other applications on this computer to communicate with Zotero.
  3. Keep Zotero open while you use your assistant.

In local mode, read tools query zotero.sqlite directly, and fall back to Zotero’s API for anything SQLite can’t answer. The database is found automatically. Set ZOTERO_DB_PATH if yours is somewhere unusual.

3Choose a connection

Local, read-only

ZOTERO_LOCAL=true is all you need. No credentials.

Local, read-write

On Zotero 10+, run zotero-mcp authorize-local once.

Hybrid

Local reads, web API writes. Add ZOTERO_API_KEY and ZOTERO_LIBRARY_ID.

Web API

No desktop app needed. Use an API key and library ID.

Local writes on Zotero 10+

Local writes need a local API key. It isn’t a zotero.org API key, and you can’t create one ahead of time: Zotero grants it through a dialog.

$ zotero-mcp authorize-local

In the dialog, choose Always Allow. The key is saved to ~/.config/zotero-mcp/config.json, readable only by you, and used from then on. Allow grants a key for a single write, and it isn’t saved.

$ zotero-mcp authorize-local --status   # what can write right now
$ zotero-mcp authorize-local --revoke   # forget the stored key
$ zotero-mcp authorize-local --print    # print it for ZOTERO_LOCAL_API_KEY

You can also do this from inside your AI app: the zotero_authorize_local_writes tool opens the same dialog, and zotero_write_capabilities shows which way writes can currently go. Set ZOTERO_LOCAL_WRITE=false to send writes through the web API even if you have a local key.

Hybrid and web API

Create a key at zotero.org/settings/keys. Your numeric user ID is shown on the same page. For a group library, use the group’s ID and set ZOTERO_LIBRARY_TYPE=group.

Web API only
$ zotero-mcp setup --no-local --api-key YOUR_API_KEY --library-id YOUR_LIBRARY_ID

For hybrid mode, keep ZOTERO_LOCAL=true and add the two credentials. Reads stay local and writes go through the web. In web mode, ZOTERO_WEBDAV_URL, ZOTERO_WEBDAV_USERNAME, and ZOTERO_WEBDAV_PASSWORD let the server download attachments straight from your WebDAV storage.

4Connect a client

Claude Desktop

zotero-mcp setup finds every claude_desktop_config.json on your computer, writes to each one, and prints their paths. To configure it yourself, add:

claude_desktop_config.json
{
  "mcpServers": {
    "zotero": {
      "command": "zotero-mcp",
      "env": { "ZOTERO_LOCAL": "true" }
    }
  }
}

On macOS the file is at ~/Library/Application Support/Claude/, on Windows at %APPDATA%\Claude\. Restart Claude Desktop after editing it. If Claude can’t find the zotero-mcp command, use the full path instead: zotero-mcp setup-info prints it.

Claude Code

Add the same mcpServers entry to ~/.claude.json, then run /mcp to check that the server is connected. Claude Code can also run commands, so the agent skill is usually the cheaper option in context. Environment variables set in the shell where you run claude override the config values.

ChatGPT

ChatGPT connects to MCP servers over the web, so it needs Developer Mode and a tunnel (such as ngrok) to a server running on your computer.

$ zotero-mcp serve --transport streamable-http --port 8000
$ ngrok http 8000

In ChatGPT, open Settings → Connectors, turn on Developer Mode under Advanced, and create a connector pointing at https://<your-tunnel>/mcp. Over HTTP, the server adds the search and fetch tools that ChatGPT deep research needs.

The tunnel URL works like a password. zotero-mcp serve has no authentication of its own, so anyone with the URL can use every tool, including writes if credentials are configured. Keep the URL private, stop the tunnel when you’re not using it, and leave --host at its default.

The getting started guide covers the full connector steps, the older sse fallback, and the OpenAI Platform setup.

Cherry Studio

Open Settings → MCP Servers → Edit MCP Configuration, then save:

{
  "mcpServers": {
    "zotero": {
      "name": "zotero", "type": "stdio", "isActive": true,
      "command": "zotero-mcp", "args": [],
      "env": { "ZOTERO_LOCAL": "true" }
    }
  }
}

Chorus, Autohand Code, and other clients

Chorus uses a form rather than a config file. Enter the full path to zotero-mcp as the command, leave the arguments empty, and paste the environment as one line of JSON, for example {"ZOTERO_LOCAL": "true"}.

Autohand Code adds a local read-only server with one command:

$ autohand mcp add zotero env ZOTERO_LOCAL=true zotero-mcp

Any other MCP client can start the server over stdio, or connect to it over streamable HTTP:

$ zotero-mcp serve --transport stdio
$ zotero-mcp serve --transport streamable-http --host localhost --port 8000

Agent skill

If your agent can run shell commands, one command teaches it to use zotero-cli. Run it inside your project. It detects which agent tools are set up there and installs in each one’s format.

$ zotero-mcp install-skill
$ zotero-mcp install-skill --list-targets   # what is detected here
$ zotero-mcp install-skill --target cursor  # install one explicitly
AgentDetected byInstalls
Claude Code (project).claude/.claude/skills/zotero-cli/
Claude Code (user)~/.claude/~/.claude/skills/zotero-cli/
Cursor.cursor/.cursor/rules/zotero-cli.mdc
Windsurf.windsurf/.windsurf/rules/zotero-cli.md
Codex, Amp, OpenCode, JulesAGENTS.mdA short pointer block in AGENTS.md
Gemini CLIGEMINI.md or .gemini/A short pointer block in GEMINI.md

It never overwrites your changes without --force. In shared files like AGENTS.md, it only edits the text between its own markers. The skill costs 98 tokens until the agent uses it. An MCP server with the default tools costs 13,448 on every request.

Semantic search

Install the [semantic] extra, choose an embedding model, then build the index.

$ zotero-mcp setup --semantic-config-only
$ zotero-mcp update-db              # fast, metadata only
$ zotero-mcp update-db --fulltext   # also index extracted full text
$ zotero-mcp db-status
ModelNotes
Default (all-MiniLM-L6-v2)Free and runs locally
OpenAItext-embedding-3-small or -large. Can use the Batch API for large libraries.
Geminigemini-embedding-001. Can use the Batch API.
OllamaRuns locally, for example nomic-embed-text or bge-m3

The index can update manually, every time the server starts, daily, or every N days. PDFs are parsed with pdf-inspector, which keeps the document’s headings. Full text can optionally be split into passages (semantic_search.chunking). If you change embedding models, rebuild with zotero-mcp update-db --force-rebuild. With OpenAI or Gemini a rebuild is billed again, so try a plain update-db first.

Docker

Multi-architecture images are published to GitHub Container Registry. -core has no extras. -all includes [semantic,pdf,scite], as do tags without a suffix.

# MCP server over stdio (default)
$ docker run --rm --env-file .env ghcr.io/54yyyu/zotero-mcp:latest

# zotero-cli instead of the server
$ docker run --rm -e ZOTERO_APP=cli ghcr.io/54yyyu/zotero-mcp:latest search "machine learning"

# keep config and the semantic index between runs
$ docker run --rm -v zotero-mcp-data:/home/app/.config/zotero-mcp \
    --env-file .env ghcr.io/54yyyu/zotero-mcp:latest

Tags: vX.Y.Z, vX.Y, vX for releases, latest for the main branch, and sha-<shortsha> for a fixed build. Each also comes in -core and -all.

Updating

The updater detects whether you installed with uv, pipx, or pip, and keeps your configuration.

$ zotero-mcp update --check-only
$ zotero-mcp update
$ zotero-mcp version

Troubleshooting

No results, or the library can’t be reached

Make sure Zotero is running and Allow other applications on this computer to communicate with Zotero is checked. In web mode, check your API key permissions, library ID, and library type.

Writes fail in local mode

On Zotero 10+, run zotero-mcp authorize-local. On older versions the local API is read-only, so add web credentials to use hybrid mode. zotero-mcp authorize-local --status shows which way writes can go.

Semantic search returns nothing

Build the index with zotero-mcp update-db and check it with zotero-mcp db-status. For better results, index full text with --fulltext.

Errors after changing embedding models or install method

zotero-mcp update-db --force-rebuild recreates the index with your current model. Back up ~/.config/zotero-mcp/chroma_db/ first.

Still stuck? Ask in Discussions or on Discord, or open an issue.