Allows for the ingestion of academic papers by arXiv ID, including automatic metadata retrieval and PDF downloads.
Supports adding research papers to a library using Digital Object Identifiers (DOIs) to automate metadata lookup and file attachment.
Connects AI agents to a local Zotero library to search items, browse collections, retrieve metadata, and manage academic papers.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@zotysearch my library for papers about reinforcement learning"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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.enabledtotrueZoty Bridge plugin installed (for PDF attachment and collection assignment)
Install
# Install as a uv tool (recommended)
uvx --from git+https://github.com/etramel/zoty zoty
# Or from a local checkout
uv tool install .Claude Code
Add to .mcp.json or ~/.claude/settings.json:
{
"mcpServers": {
"zoty": {
"command": "zoty"
}
}
}Claude Desktop
Add to your Claude Desktop MCP config:
{
"mcpServers": {
"zoty": {
"command": "uvx",
"args": ["--from", "git+https://github.com/etramel/zoty", "zoty"]
}
}
}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
Download
zoty-bridge.xpifrom releases, or build it yourself:make buildIn Zotero: Tools > Add-ons > gear icon > Install Add-on From File > select the
.xpiRestart Zotero
The bridge runs an HTTP server on localhost:24119 when Zotero is open. No configuration needed.
Tools
Tool | Description |
| BM25-ranked search over item titles and abstracts |
| List all collections with keys, names, and item counts |
| List items in a specific collection |
| Full metadata for a single item by key |
| Recently added items, sorted by date |
| 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 testsLicense
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 8000The shared MCP endpoint will be:
http://127.0.0.1:8000/mcpIf you want a different endpoint path:
zoty \
--transport streamable-http \
--host 127.0.0.1 \
--port 8000 \
--streamable-http-path /zoty-mcpThen point every client at the same URL:
http://127.0.0.1:8000/zoty-mcpFor 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:
Boot Zotero and make sure the Zotero connector and
zoty-bridgeplugin are available.Start one shared zoty server with
--transport streamable-http.Configure each agent or MCP client to connect to that existing server URL instead of launching its own copy.
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.
Resources
Looking for Admin?
Admins can modify the Dockerfile, update the server description, and track usage metrics. If you are the server author, to access the admin panel.