Skip to content

Install

Installing zotero-agent is two parts: the zot CLI (a Python package) and the bridge plugin (a one-click XPI you load from Zotero’s UI — no restart needed). The plugin is what makes local writes possible; without it, zot can only read.

  • Zotero 7+ (tested through 9.x) running, with its local API enabled (the default).
  • Python 3.10+. The CLI core is stdlib-only; the MCP server needs the [mcp] extra and the PDF outline commands need [toc].
  • macOS or Linux. Windows works too — see OS paths below.
Terminal window
uv tool install zotero-agent # CLI only
uv tool install "zotero-agent[mcp]" # CLI + MCP server (for AI agents)
uv tool install "zotero-agent[toc]" # CLI + PDF engine (zot toc)
uv tool install "zotero-agent[mcp,toc]" # everything
# or, with pipx:
pipx install zotero-agent
pipx install "zotero-agent[mcp]"

The core is stdlib-only; the two extras are the only dependencies, and each is optional:

ExtraPulls inEnables
mcpmcpzot mcp, the Model Context Protocol server
tocpymupdfzot toc, reading and writing PDF outlines

zot toc without the extra exits with the exact command that fixes it, so installing it later is fine. Note that PyMuPDF is a multi-megabyte binary wheel — that, not licensing, is why it is not a hard dependency (this project is AGPL-3.0, the same licence).

This puts zot on your PATH.

Terminal window
brew install alex-roc/tap/zotero-agent

One command, and unlike the uv/pipx routes it ships both extraszot mcp and zot toc work immediately. That is not generosity: Homebrew replaces a keg wholesale on every upgrade, so an extra added afterwards would vanish at the next brew upgrade. Budget ~35 MB of downloads and ~100 MB installed, most of it PyMuPDF.

Terminal window
brew upgrade zotero-agent # the CLI; the Zotero plugin updates itself

Installed by two routes at once (uv first, then Homebrew)? PATH order decides which one runs — on macOS /opt/homebrew/bin normally precedes ~/.local/bin, so the Homebrew one wins. command -v zot tells you which; both share the same config and state, so neither needs reconfiguring.

The bridge is a small plugin that exposes one token-protected endpoint, POST /zotero-agent, inside Zotero. Install it through the standard Zotero flow — you do not need to close Zotero:

  1. Download the XPI. It is published in one place only, and this link always resolves to the newest one:

    zotero-agent-bridge.xpi

  2. In Zotero: Tools → Plugins, click the gear icon (top-right) → “Install Plugin From File…”.

  3. Select the .xpi. “Zotero Agent Bridge” appears in the list, enabled. The endpoint registers on load — no restart required.

You do this once: from then on Zotero keeps the plugin updated itself (see Updating).

Terminal window
zot init # generate a token, write config (0600), auto-detect your userID
zot ping # verify all three layers are live

A healthy zot ping looks like this:

Terminal window
$ zot ping
Zotero local API : up (HTTP 200)
bridge endpoint : up (/zotero-agent, 1+1 == 2)
bridge plugin : 0.5.0
userID : 2960998
zot version : 0.5.0
zot source : ~/.local/share/uv/tools/zotero-agent/lib/python3.13/site-packages/zotero_agent

If the bridge endpoint shows FAIL, the plugin is not loaded — reinstall the .xpi via Tools → Plugins → gear → Install Plugin From File… and confirm it is enabled. bridge plugin is the version the installed plugin reports; when it differs from zot version, ping tells you which side to update.

zot source says which install answered, which matters when more than one route is present — they all report the same version. ~/.local/share/uv/… is uv, /opt/homebrew/Cellar/… is Homebrew, and a path outside any site-packages is a checkout, which zot --version also marks as (dev). Please include this line in bug reports.

The CLI and the plugin ship together and share a version number.

Terminal window
uv tool upgrade zotero-agent # or: pipx upgrade zotero-agent
brew upgrade zotero-agent # if you installed it with Homebrew

If zot --version still shows the previous release, uv is using cached index metadata — force a refresh:

Terminal window
uv tool install --force --refresh --with mcp zotero-agent

The plugin updates itself. Its manifest points at an update_url (updates.json in the repo), so Zotero picks up new releases like it does for any other plugin — the manual XPI install happens exactly once.

Zotero checks once a day (extensions.update.interval = 86400s), so straight after a release zot ping may still show the previous plugin version. To pull it in now:

Tools → Plugins → the gear icon (top-right of the Plugins window) → Check for Updates

Then run zot ping: bridge plugin and zot version should agree. If Zotero never offers the update, see the troubleshooting snippet in docs/install.md, which asks Zotero’s own AddonManager what it sees.

The Claude Code skill is bundled in the package too — no clone required:

Terminal window
zot skill install # -> ~/.claude/skills/zotero
zot skill install --project # -> ./.claude/skills/zotero (one project only)
zot skill install --force # replace an existing install
zot skill path # where the bundled copy lives
zot skill agents-md > AGENTS.md # portable instructions for any shell agent

Start a new Claude Code session to pick it up, then just ask about your library. Prefer MCP instead? claude mcp add zotero-agent -- zot mcp (needs the [mcp] extra).

From a git checkout, ./install.sh wires up everything for local development: it puts a dev zot on your PATH, runs zot skill install --link (so edits to skill/ take effect immediately), runs zot init, and builds a local XPI into dist/ — the same artifact releases publish. You still install it in Zotero as in step 2.

zot init writes a random token to ~/.config/zotero-agent/config.json with 0600 permissions. The plugin reads that same file, so rotating the token needs no Zotero restart — just edit the file. If you prefer a Zotero pref, set extensions.zotero-agent.token; it takes precedence over the config file. See Configuration and the security model.

zot completion <shell> prints a completion script for bash, zsh, or fish — it completes subcommand names and global flags, with no extra dependency:

Terminal window
eval "$(zot completion bash)" # in ~/.bashrc
eval "$(zot completion zsh)" # in ~/.zshrc
zot completion fish > ~/.config/fish/completions/zot.fish

zot init detects your Zotero profile automatically; these are only for manual checks:

OSProfile location
macOS~/Library/Application Support/Zotero/Profiles/<random>.default*
Linux~/.zotero/zotero/<random>.default*
Windows%APPDATA%\Zotero\Zotero\Profiles\<random>.default*
  1. The plugin — remove “Zotero Agent Bridge” from Tools → Plugins. No restart needed; the XPI leaves your profile’s extensions/.

  2. The CLI — however you installed it:

    Terminal window
    uv tool uninstall zotero-agent # or: pipx uninstall zotero-agent
    brew uninstall zotero-agent # if you installed it with Homebrew
    rm ~/.local/bin/zot ~/.claude/skills/zotero # the ./install.sh dev symlinks
  3. State on disk — two directories, neither removed by uninstalling the package:

    Terminal window
    rm -rf ~/.config/zotero-agent # config.json (token, userID) + backups/
    rm -rf ~/.local/state/zotero-agent # audit.jsonl + undo/ snapshots

    Deleting undo/ discards the snapshots zot undo restores from — keep it if you may still want to reverse a past zot apply.

  4. Agent wiring, if you added it — claude mcp remove zotero-agent, plus any entry you made in claude_desktop_config.json, ~/.codex/config.toml, ~/.gemini/settings.json or .cursor/mcp.json, and the eval "$(zot completion …)" line in your shell rc.

To confirm nothing is left (e.g. before testing a fresh install):

Terminal window
command -v zot # nothing
ls -d ~/.config/zotero-agent ~/.local/state/zotero-agent # No such file
ls ~/Library/Application\ Support/Zotero/Profiles/*/extensions | grep zotero-agent