Skip to main content
Glama
adolinjonathan-bot

zotero-mcp-server

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

  1. Go to https://www.zotero.org/settings/keys

  2. Click Create new private key

  3. Tick Allow library access, and tick Allow write access if you want Claude to create/edit items (needed for this server)

  4. Save the key somewhere safe - Zotero only shows it once

  5. 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 build

This 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 vars

verify 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

Missing ZOTERO_API_KEY

The key isn't reaching the server process - check the env block in your MCP config.

403 ... Invalid key

Key is wrong, revoked, or lacks library access.

403 on writes only

The key was created without Allow write access.

400 ... Bad Request

Key is malformed - re-copy it; it should be 24 letters and digits.

429

Zotero rate limit; wait and retry.

Tools provided

Read

  • zotero_search_items - full-text/title/creator search, with type/tag/collection filters

  • zotero_get_item - fetch one item's full metadata

  • zotero_get_item_children - list an item's attachments and notes

  • zotero_list_collections - list top-level or nested collections

  • zotero_get_collection_items - list items filed under a collection

  • zotero_list_tags - list/search tags in use

Write

  • zotero_create_item - add a new reference

  • zotero_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 note

  • zotero_create_collection - add a new collection/folder

  • zotero_add_items_to_collection - file existing items into a collection

Notes

  • Update and delete require the item's current version (returned by zotero_get_item/zotero_search_items) so Claude can't silently clobber a change made elsewhere since it last read the item.

  • zotero_update_item replaces array fields (tags, collections) wholesale rather than merging - fetch the item first if you want to append rather than overwrite.

  • zotero_delete_item moves items to the Zotero trash by default (recoverable), by flagging them as deleted the way the desktop client does. Passing permanent: true uses the API's DELETE endpoint 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_items takes an optional query. Omit it to browse by item_type, tag, or collection_key alone (e.g. every item tagged "AI literacy").

  • The API key is sent in Zotero's own Zotero-API-Key header, 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 ABCD1234

Add --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.

Install Server
A
license - permissive license
A
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

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

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