Zotero-MCP
Provides access to a Zotero library, allowing AI agents to read library items and insert live Zotero citation fields into Word documents that remain linked to the Zotero items.
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., "@Zotero-MCPInsert a live Zotero citation for Vaswani et al. 2017 into my paper.docx"
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.
Zotero-MCP
An MCP server that gives Claude access to your Zotero library and lets it insert live Zotero citations into Word documents — real citation fields that Zotero owns, not text that merely looks like a citation.
That distinction is the whole point of this project, so it is worth being precise about it.
The problem this solves
Ask an assistant to "cite Vaswani et al. 2017" in a Word document and you
normally get a string of characters: (Vaswani et al., 2017). It looks right.
It is also dead. Zotero does not know it exists. Change your citation style
from APA to IEEE and it does not update. Add a source and the bibliography does
not renumber. Delete a reference and nothing tells you the citation is orphaned.
What you actually want is what Zotero's own Word plugin produces: a field that stays linked to the library item. This server writes those.
Related MCP server: zotero-mcp
Why it works this way: the Word integration problem
Zotero's Word plugin talks to Zotero over a private bridge — a COM/DLL channel
on Windows, AppleScript on macOS. It is not a public API, it is not documented
for third parties, and it is not designed to be driven by anything other than
Zotero itself. Calling the plugin's macro (ZoteroInsertCitation) opens the
interactive citation picker and waits for a human to click. There is no
supported, headless way to ask the plugin to insert a citation.
So driving the plugin was off the table. Three options remained:
Approach | Verdict |
Automate the Word plugin via COM / macros | Not viable. The insert path is interactive by design; anything built on it breaks between Word and Zotero versions. |
Generate formatted text with a CSL processor | Easy, but produces exactly the dead citations described above. Rejected. |
Write Zotero's field codes directly into the | ✅ What this project does. |
The third approach works because a Zotero citation in a .docx is not magic.
It is an ordinary Word field whose instruction text looks like this:
ADDIN ZOTERO_ITEM CSL_CITATION {"citationID":"a1b2c3","properties":{…},
"citationItems":[{"id":"…","uris":["http://zotero.org/users/123/items/ABCD1234"],
"itemData":{…CSL-JSON…}}],"schema":"…csl-citation.json"}Plus an ADDIN ZOTERO_BIBL … CSL_BIBLIOGRAPHY field for the bibliography, and
a set of hidden ADDIN ZOTERO_PREF_1…N fields recording which CSL style the
document uses.
Reproduce those payloads exactly — the item URIs, the CSL-JSON, the schema URL, the preference blob's chunking — and Zotero cannot tell the difference. It adopts the citations as its own. Refresh, Add/Edit Bibliography and switching styles all behave normally.
No Word automation. No COM. No open Word instance. Just the file.
What this costs you (read this part)
Being honest about the trade-offs, because they are real:
The document must be closed in Word. Word holds a lock and would overwrite our edits when it saves. The server detects the
~$file.docxlock and refuses rather than losing your work. A.docx.bakbackup is written beside the file on every change..docxonly. Legacy.docand OpenDocument.odtare not supported. LibreOffice uses a different field representation (ReferenceMarks); support could be added but is not there yet.The first Refresh in Word is what makes it exact. We pre-render the visible citation text so the document reads correctly straight away, but multi-source citations, numeric styles and bibliography ordering follow rules only a full CSL processor gets perfectly right. One click of Zotero → Refresh hands that job to Zotero and normalises everything.
Footnote styles are a known limitation. Citations are inserted into the body text. For note-based styles (Chicago notes-bibliography and similar), Zotero will not migrate an in-text field into a real Word footnote. In-text styles — APA, MLA, Harvard, IEEE, Vancouver, Nature, AMA — work properly. The server warns you when it detects a note style.
Google Docs is not supported. It stores citations as links, a different mechanism entirely.
Architecture
Claude ──MCP/stdio──▶ zotero-mcp
├── reads ──▶ Zotero 7 local API (localhost:23119) [fast, no quota]
│ └─ falls back to ──▶ api.zotero.org
├── writes ──▶ Zotero Web API v3 [needs API key]
└── Word ──▶ .docx OOXML, direct field injection [no Word needed]Reads prefer the local API: it is instant, unmetered, and reflects changes you have not synced yet. It is read-only, so every write goes to the Web API. If Zotero is not running, reads transparently fall back to the web.
Quick start
Requires Python 3.10+ and Zotero 7.
1. Install
Windows
git clone https://github.com/RogerAylagas/Zotero-MCP.git
cd Zotero-MCP
.\scripts\setup.ps1macOS / Linux
git clone https://github.com/RogerAylagas/Zotero-MCP.git
cd Zotero-MCP
./scripts/setup.shThe script finds a suitable Python, builds the virtualenv, installs the
package, creates .env, and runs a health check.
Flag | Effect |
| Write the server into |
| Target a different config file. |
| Rebuild the virtualenv from scratch. |
| Skip the health check. |
2. Add your Zotero credentials
Fill in .env — details in Configure below — then run the script
again, or python scripts/doctor.py, until every line is green.
3. Connect it to Claude
These are the values Claude needs, whichever route you take:
Field | Value |
Command |
|
Arguments |
|
Environment |
|
The setup script prints them with your real paths already filled in.
Route A — the app's settings (recent builds). Recent Claude Desktop builds manage MCP servers and extensions through their own settings UI and an extensions marketplace, not through a config file. Look for Extensions or Connectors in Settings and add a local MCP server there using the values above. This is the supported route: nothing external competes for the file.
Route B — claude_desktop_config.json (older builds). Older builds read
the server list from a config file. setup.ps1 -Register writes it for you; see
Register with Claude manually for the JSON.
Quit Claude before using route B. Claude keeps that file in memory and rewrites it periodically, so an edit made while it is running is silently discarded minutes later — it looks like it worked and then quietly undoes itself. The script detects a running Claude and refuses rather than pretending to succeed.
If the entry keeps disappearing even with Claude closed, your build does not read that file at all. Use route A.
Afterwards, restart Claude and ask it to run zotero_check_setup.
A note on "starting" the server
There is no server to start. An MCP stdio server is not a daemon: Claude spawns
it on demand and talks to it over stdin/stdout, then shuts it down. So the
setup script's job is installing it and handing Claude the launch command —
after that the server starts itself whenever Claude needs it. If you launch
python -m zotero_mcp by hand it will just sit there waiting for JSON-RPC on
stdin, which is correct but not useful.
To check the server's health at any time:
.venv\Scripts\python.exe scripts\doctor.py # Windows.venv/bin/python scripts/doctor.py # macOS / LinuxIt tests each layer separately — configuration, local API, Web API, server startup — so a failure points at one specific thing.
Configure
cp .env.example .envThen fill in .env:
API key — create one at https://www.zotero.org/settings/keys/new. Tick Allow library access and Allow write access. Copy it into
ZOTERO_API_KEY.Library ID — the numeric Your userID for use in API calls shown at https://www.zotero.org/settings/keys. Into
ZOTERO_LIBRARY_ID.Local API (recommended) — in Zotero: Settings → Advanced → tick "Allow other applications on this computer to communicate with Zotero".
Your API key is a credential. Keep it in
.env(which is gitignored) and never paste it into a chat.
Register with Claude manually
setup.ps1 -Register does this for you. To do it by hand, add to your MCP
client configuration:
{
"mcpServers": {
"zotero": {
"command": "C:\\path\\to\\Zotero-MCP\\.venv\\Scripts\\python.exe",
"args": ["-m", "zotero_mcp"],
"env": {
"ZOTERO_MCP_ENV_FILE": "C:\\path\\to\\Zotero-MCP\\.env"
}
}
}
}Pointing at the .env file rather than copying ZOTERO_API_KEY into the config
keeps the credential in exactly one place — a gitignored file — instead of
duplicating it into a config file that is easy to share by accident. Individual
ZOTERO_* variables still work here if you prefer them; anything already in the
environment wins over the .env file.
Claude's config lives at:
Client | Path |
Claude Desktop (Windows) |
|
Claude Desktop (macOS) |
|
Claude Desktop (Linux) |
|
Restart Claude completely afterwards, then ask it to run zotero_check_setup —
it reports exactly what is configured, what is reachable, and what is missing.
Installing without the script
python -m venv .venv
.venv/bin/pip install -e . # .venv\Scripts\pip.exe on Windows
cp .env.example .envTools
Library — reading
Tool | Purpose |
| Diagnose configuration and connectivity. Start here. |
| Search by text, type, tag or collection. Returns item keys. |
| One reference in full, with its notes and attachments. |
| Browse collections and sub-collections. |
| Tags in the library. |
| Saved searches defined in Zotero. |
| Indexed full text of a PDF attachment. |
| Personal library plus group libraries. |
| Valid types and their fields. |
Library — writing
Tool | Purpose |
| Add a source from a DOI, arXiv id or ISBN. The fast path. |
| Create a reference field by field. |
| Edit fields, with version checking against concurrent edits. |
| Move to Zotero's trash (recoverable). |
| Child or standalone note. |
| Add tags without clobbering existing ones. |
| Attach a URL to a reference. |
| Organise the library. |
Citations
Tool | Purpose |
| Render citation/bibliography as plain text — for email, markdown, slides. Not for Word. |
| Browse CSL styles. |
Word — live citation fields
Tool | Purpose |
| Paragraph-by-paragraph map with indices. Read before inserting. |
| Insert a live |
| Build the |
| Set the document's CSL style. |
| Inspect the Zotero citations already in a document. |
| Remove a citation field. |
Typical session
You: Add the Vaswani attention paper to Zotero and cite it in
thesis.docxafter the sentence about sequence tasks.
What Claude does:
zotero_import_identifier("10.48550/arXiv.1706.03762")→ the reference is in your library, with proper metadata.word_document_outline("thesis.docx")→ reads the real paragraph text.word_insert_citation(..., anchor_text="…changed how we approach sequence tasks.")→ a live field appears exactly there.word_insert_bibliography("thesis.docx", heading="References").
Then you open thesis.docx in Word and click Zotero → Refresh. The
citations are Zotero's now: switch the style to IEEE and everything renumbers,
including the bibliography.
Development
pip install -e ".[dev]"
pytestThe test suite builds .docx files from scratch, so it runs without Word or
Zotero installed. The tests that matter most are in
tests/test_docx_fields.py: they assert that the field codes we emit parse
back correctly, that the preference blob chunks and reassembles the way Zotero
expects, and that saving a document leaves every package part we did not touch
byte-identical.
Layout
src/zotero_mcp/
├── server.py MCP server and setup diagnostics
├── config.py Environment configuration
├── context.py Shared client, path safety
├── zotero/
│ ├── client.py Hybrid local/web facade
│ ├── web.py Zotero Web API v3
│ └── local.py Zotero 7 local API
├── docxfields/
│ ├── ooxml.py Word field plumbing (fldChar/instrText runs)
│ ├── zotero_fields.py ZOTERO_ITEM / ZOTERO_BIBL / ZOTERO_PREF payloads
│ └── document.py High-level document operations
└── tools/ MCP tool definitions
scripts/
├── setup.ps1 One-command setup + registration (Windows)
├── setup.sh One-command setup + registration (macOS/Linux)
└── doctor.py Layer-by-layer health checkRoadmap
File attachment upload (the three-step Zotero upload protocol)
LibreOffice Writer field support
Real Word footnotes, unlocking note-based styles
Bundled CSL processor so multi-source citations render exactly before Refresh
License
MIT
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityDmaintenanceA server that enables MCP clients like Anthropic Claude App to interact with local Zotero libraries, allowing users to search papers, manage notes, and access research materials through natural language.Last updated1029Apache 2.0
- AlicenseAqualityCmaintenanceRead-only MCP server that lets Claude or any MCP client search and retrieve metadata, notes, full text, citations, and BibTeX from your local Zotero library via its built-in API.Last updated11MIT
- Alicense-qualityCmaintenanceAn MCP server that gives any MCP-compatible assistant access to your Zotero reference library, enabling search, citation, bibliography generation, and .docx processing while keeping Zotero as the ground truth for references.Last updated1MIT
- Alicense-qualityCmaintenanceMCP server that enables Claude Code to control the Zotero browser connector, automatically capturing web page papers into the local Zotero library.Last updatedAGPL 3.0
Related MCP Connectors
The everything Zotero MCP server — Web API v3 + local API, safe writes, citations, search.
Remote MCP server for full read/write access to a Zotero library
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/RogerAylagas/Zotero-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server