zotero-mcp-server
Provides read and write access to a Zotero library, enabling searching items, reading notes and attachments, browsing collections, and creating/updating/deleting items, notes, and collections.
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-mcp-serverFind recent items about climate change in my library"
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 Server
Gives Claude read and write access to your Zotero library: search items, read notes and attachments, browse collections, and create/update/delete items, notes, and collections.
Talks to the Zotero Web API (api.zotero.org), so it works with your synced online library from any machine - it does not need the Zotero desktop app running.
Requires Node.js 18 or newer (uses the built-in fetch).
Writes are live. This server can create, edit and delete items in a real Zotero library, and Zotero syncs, so changes reach every device signed into the account. Deletions go to the Zotero trash by default and are recoverable, but if you only want Claude to read your library, create an API key without write access - the six write tools will then fail cleanly with a 403 and nothing can be modified.
1. Get your Zotero API credentials
Click Create new private key
Tick Allow library access, and tick Allow write access if you want Claude to create/edit items (needed for this server)
Save the key somewhere safe - Zotero only shows it once
On the same page, note your user ID (a number), shown near the top
For a shared group library instead of your personal one, use the group's numeric ID (visible in the group's URL on zotero.org) and set ZOTERO_LIBRARY_TYPE=group.
Related MCP server: zotero-mcp
2. Build the server
npm install
npm run buildThis produces dist/index.js.
3. Point an MCP client at it
MCP is an open standard, so this works with any MCP-capable client - Claude Desktop, Claude Code, Cursor, Zed, Continue, VS Code, LM Studio, or your own, including setups running local open-source models. Nothing here is vendor-specific.
Most clients use the same JSON shape; consult yours for the file location
(commonly claude_desktop_config.json, .mcp.json, ~/.claude.json, or an
equivalent settings file):
{
"mcpServers": {
"zotero": {
"command": "node",
"args": ["/absolute/path/to/zotero-mcp-server/dist/index.js"],
"env": {
"ZOTERO_API_KEY": "your-api-key-here",
"ZOTERO_LIBRARY_ID": "your-numeric-user-id",
"ZOTERO_LIBRARY_TYPE": "user"
}
}
}
}Use an absolute path to dist/index.js. On Windows either escape the backslashes
(C:\\path\\to\\dist\\index.js) or use forward slashes.
Restart the client fully after saving, then ask it something like "search my Zotero library for items on AI and youth mentorship" to confirm the connection.
4. Verify it works
npm run verify # protocol + error handling; no credentials needed
npm run verify:live # also queries the real library, using the ZOTERO_* env varsverify launches the server over stdio exactly as an MCP client does, completes the
handshake, checks all 12 tools are exposed with valid schemas, and confirms that a
missing API key produces a readable error rather than a crash. verify:live additionally
lists tags and collections and runs both a text search and a filter-only search.
Troubleshooting:
Symptom | Cause |
| The key isn't reaching the server process - check the |
| Key is wrong, revoked, or lacks library access. |
| The key was created without Allow write access. |
| Key is malformed - re-copy it; it should be 24 letters and digits. |
| Zotero rate limit; wait and retry. |
Tools provided
Read
zotero_search_items- full-text/title/creator search, with type/tag/collection filterszotero_get_item- fetch one item's full metadatazotero_get_item_children- list an item's attachments and noteszotero_list_collections- list top-level or nested collectionszotero_get_collection_items- list items filed under a collectionzotero_list_tags- list/search tags in use
Write
zotero_create_item- add a new referencezotero_update_item- partially edit an existing item (version-checked)zotero_delete_item- delete an item (version-checked)zotero_create_note- add a standalone or child notezotero_create_collection- add a new collection/folderzotero_add_items_to_collection- file existing items into a collection
Notes
Update and delete require the item's current
version(returned byzotero_get_item/zotero_search_items) so Claude can't silently clobber a change made elsewhere since it last read the item.zotero_update_itemreplaces array fields (tags,collections) wholesale rather than merging - fetch the item first if you want to append rather than overwrite.zotero_delete_itemmoves items to the Zotero trash by default (recoverable), by flagging them as deleted the way the desktop client does. Passingpermanent: trueuses the API'sDELETEendpoint instead, which bypasses the trash and is irreversible.The library is synced. Any create, update, or delete made here propagates to zotero.org and down to the desktop app on its next sync. There is no "web only" change.
This server does not download or extract PDF file contents; it works with Zotero's bibliographic metadata, notes, and full-text search index.
zotero_search_itemstakes an optionalquery. Omit it to browse byitem_type,tag, orcollection_keyalone (e.g. every item tagged "AI literacy").The API key is sent in Zotero's own
Zotero-API-Keyheader, and is whitespace-trimmed, so a key pasted with a stray space still gives a clear "Invalid key" error rather than an opaque HTTP 400.
Using it without an MCP client
The same code is available as a plain command-line tool, so the project is useful with no MCP client, no AI model, and no network calls to anyone but Zotero. Read-only - nothing here can modify a library.
export ZOTERO_API_KEY=... # Windows PowerShell: $env:ZOTERO_API_KEY="..."
export ZOTERO_LIBRARY_ID=...
node dist/cli.js collections
node dist/cli.js search "youth employability" --type journalArticle --limit 10
node dist/cli.js items --collection ABCD1234
node dist/cli.js tags --filter TVET
node dist/cli.js item ABCD1234
node dist/cli.js children ABCD1234Add --json to any command for machine-readable output, so it composes with jq
or feeds a script:
node dist/cli.js search "TVET" --json | jq -r '.[].data.DOI'Contributing
Issues and pull requests are welcome. Please run npm run build && npm run verify
before opening a PR; verify needs no credentials and guards the tool schemas
against regressions.
Licence
MIT - see LICENSE.
Credits
Initial implementation generated with Claude, then debugged, hardened and tested against a live 290-item research library.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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/adolinjonathan-bot/zotero-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server