Skip to main content

Lightweight Zotero MCP server for AI agent interaction

Project description

zoty

Lightweight Zotero MCP server for AI agents.

What it does

MCP server that connects AI agents to your local Zotero library. Provides 6 tools: BM25-ranked search over titles and abstracts, collection browsing, item lookup, and paper ingestion by arXiv ID or DOI with automatic PDF attachment.

Requirements

  • Python 3.10+
  • Zotero 7 desktop running
  • Zotero local API enabled: Zotero Settings > Advanced > Config Editor > set extensions.zotero.httpServer.localAPI.enabled to true
  • Zoty Bridge plugin installed (for PDF attachment and collection assignment)

Add to Your Agent

Claude Code

Add from the command line:

claude mcp add zoty -- uvx zoty

Add to your .mcp.json or ~/.claude/settings.json:

{
  "mcpServers": {
    "zoty": {
      "command": "uvx",
      "args": ["zoty"]
    }
  }
}

Codex

Add from the command line:

codex mcp add zoty -- uvx zoty

Add to your ~/.codex/config.toml:

[mcp_servers.zoty]
command = "uvx"
args = ["zoty"]

Installation

Requires uv.

Run without installing (recommended for MCP setups):

uvx zoty

Install persistently:

uv tool install zoty

Upgrade an installed copy:

uv tool upgrade zoty

If you run zoty with uvx instead of installing it, refresh to the latest published version with:

uvx --refresh zoty

From a local checkout:

uv run zoty

# Or install from source as a tool
uv tool install .

Zoty Bridge Plugin

A tiny Zotero 7 plugin that lets zoty execute JavaScript inside Zotero's privileged context. This is needed for operations that can't go through the REST API: PDF attachment and collection assignment both require writing to Zotero's SQLite database, which locks out external processes. The bridge sidesteps this by running JS inside Zotero itself.

Install the plugin

  1. Download zoty-bridge.xpi from releases, or build it yourself:
    make build
    
  2. In Zotero: Tools > Add-ons > gear icon > Install Add-on From File > select the .xpi
  3. Restart Zotero

The bridge runs an HTTP server on localhost:24119 when Zotero is open. No configuration needed.

Tools

Tool Description
search_library BM25-ranked search over item titles and abstracts
list_collections List all collections with keys, names, and item counts
list_collection_items List items in a specific collection
get_item Full metadata for a single item by key
get_recent_items Recently added items, sorted by date
add_paper Add a paper by arXiv ID or DOI with automatic PDF download

How it works

Read operations go through pyzotero against Zotero's local API (localhost:23119). The BM25 search index builds in a background thread at startup so the MCP handshake completes immediately.

Write operations use the Zotero connector endpoint (/connector/saveItems) to create metadata items. PDF attachment and collection assignment go through the zoty-bridge plugin, which executes JavaScript in Zotero's privileged context. This two-path design exists because Zotero's SQLite database uses exclusive locking -- external processes can read it (immutable mode) but not write to it while Zotero is running.

arXiv traffic is throttled internally to respect arXiv's access policy. Concurrent add_paper calls queue transparently: metadata requests serialize with a 3-second gap, and arXiv PDF downloads are rate-limited separately.

Development

make build   # build zotero-plugin/dist/zoty-bridge.xpi
make test    # run Python unit tests

License

MIT

Rate Limiting Across Sessions

zoty rate-limits arXiv traffic inside the running MCP server process. If several add_paper calls reach the same server at once, zoty queues them and drains metadata requests at arXiv-safe speed.

That limiter is not shared across separate zoty processes. If you start one zoty instance per agent, session, or editor window, each process will enforce its own limit and the combined request rate can still exceed arXiv policy.

If you expect multiple sessions to pull papers at the same time, start one long-lived zoty server and point all clients at that same instance.

Start one shared local server:

zoty --transport streamable-http --host 127.0.0.1 --port 8000

The shared MCP endpoint will be:

http://127.0.0.1:8000/mcp

If you want a different endpoint path:

zoty \
  --transport streamable-http \
  --host 127.0.0.1 \
  --port 8000 \
  --streamable-http-path /zoty-mcp

Then point every client at the same URL:

http://127.0.0.1:8000/zoty-mcp

For clients that support remote MCP servers by URL, the config should look like this:

{
  "mcpServers": {
    "zoty": {
      "url": "http://127.0.0.1:8000/mcp"
    }
  }
}

Avoid this pattern when multiple sessions may import papers in parallel, because it starts a separate zoty process per client:

{
  "mcpServers": {
    "zoty": {
      "command": "zoty"
    }
  }
}

Recommended boot sequence:

  1. Boot Zotero and make sure the Zotero connector and zoty-bridge plugin are available.
  2. Start one shared zoty server with --transport streamable-http.
  3. Configure each agent or MCP client to connect to that existing server URL instead of launching its own copy.
  4. Let the shared server serialize arXiv metadata lookups and rate-limit arXiv PDF downloads for everyone.

This keeps the agent-side behavior simple: tool calls may take a bit longer under load, but they will queue naturally instead of hammering export.arxiv.org.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zoty-0.1.3.tar.gz (89.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zoty-0.1.3-py3-none-any.whl (16.3 kB view details)

Uploaded Python 3

File details

Details for the file zoty-0.1.3.tar.gz.

File metadata

  • Download URL: zoty-0.1.3.tar.gz
  • Upload date:
  • Size: 89.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for zoty-0.1.3.tar.gz
Algorithm Hash digest
SHA256 22678eaaf92703aa3cf00d9f66074d3102de6c5c1b25fd2c82592314deaa2bd3
MD5 39a881e98b7ea31a6eb4b2eaf84c1140
BLAKE2b-256 768d59686998989c2f9ad7d66420dca4dd61bec75af0ddb8223ffe269ca1da85

See more details on using hashes here.

Provenance

The following attestation bundles were made for zoty-0.1.3.tar.gz:

Publisher: publish.yml on eric-tramel/zoty

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file zoty-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: zoty-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 16.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for zoty-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 9c7e4fccf69b018102f4d6320249a028abfb964dd1d541e2be0ad166ac8f5283
MD5 e28a00dac46cbcb2d11e242135e34402
BLAKE2b-256 b3d21dfe2da64df1949f3f6e1820a8e7285e398198becdb6919d915dbd3b83a8

See more details on using hashes here.

Provenance

The following attestation bundles were made for zoty-0.1.3-py3-none-any.whl:

Publisher: publish.yml on eric-tramel/zoty

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page