Skip to main content
Glama

zotero-mcp

zotero-mcp is a local, read-only Model Context Protocol (MCP) server for a configured Zotero library. A coding agent such as Codex CLI or Claude Code starts it as a child process and communicates over standard input/output. The process reads synchronized library data from the Zotero Web API over HTTPS; this project does not operate a hosted relay or account service.

Codex CLI, Claude Code, or another MCP client  <-- local stdio -->  zotero-mcp
                                                                    |
                                                                    +-- HTTPS --> api.zotero.org

Pre-release: this package is not published to npm and will remain source-only for now. Clone the repository, install its dependencies, and build it locally by following the instructions below.

Supported tools

zotero_list_collections

List and paginate the configured library's collection hierarchy in deterministic depth-first order. Results include stable collection keys, names, full paths, parent keys, depths, and Zotero-reported item and subcollection counts. When collection focus is configured, only that collection tree is listed.

zotero_search_items

Search and paginate top-level items in the configured Zotero library or focused collection tree. Inputs include text, metadata or everything search mode, item type, tag, page size, and offset. Results contain compact item metadata and pagination information. This uses Zotero API search, not semantic or vector search.

zotero_get_item

Get complete data for an item by its Zotero item_key, together with compact descriptors for child notes and attachments. A child item can also be requested directly by its own key.

zotero_get_fulltext

Read text that Zotero has already indexed for a PDF attachment. Pass a parent item key or attachment key, and optionally an attachment key, character offset, and chunk size. If a parent has exactly one PDF, it is selected automatically; if it has several, the tool returns candidates. Results include truncation, next_offset, and Zotero indexing coverage when available.

All four tools are read-only.

Related MCP server: zotero-mcp

Pre-release installation

Git, npm, and Node.js 20 or newer are required.

Download the source

git clone https://github.com/ZhongxuanWu/zotero-mcp.git
cd zotero-mcp

Install and build

Install the locked dependencies, compile TypeScript into dist, and verify the built command:

npm ci
npm run build
node dist/cli.js --help

Coding-agent configurations must use an absolute path to dist/cli.js. On macOS or Linux, run pwd from the repository root to get the checkout path. On PowerShell, run Resolve-Path ..

Update an existing checkout

Pull the latest source, synchronize dependencies, and rebuild:

git pull --ff-only
npm ci
npm run build

Rebuilding updates the existing dist/cli.js; coding-agent configuration does not need to change while the checkout stays at the same path.

Zotero configuration

Library selection and authentication are separate:

  • With no --library option, ZOTERO_API_KEY is required. The server asks Zotero which user owns the key and reads that user's personal library. This preserves the original key-only behavior.

  • --library user:<positive-id> selects a user library directly.

  • --library group:<positive-id> selects a group library directly.

  • With an explicit selector, the API key is optional. Omit it for a library that Zotero exposes publicly, or provide a key that can read a restricted library. The server sends an API-key header only when a non-empty key is present.

Run node dist/cli.js --help from the checkout for the complete CLI syntax. Invalid selectors, such as unknown library types, zero, negative, or non-numeric IDs, are rejected before the MCP server starts.

Private personal library

Create a dedicated read-only key in Zotero's API key settings. Enable personal-library read access, enable note access only if you need note bodies, and leave write access disabled. Put the key in the process environment:

export ZOTERO_API_KEY="your-read-only-key"

PowerShell:

$env:ZOTERO_API_KEY = "your-read-only-key"

No numeric user ID is needed in this mode.

Credential-free public library

For a public user or group library, pass its numeric Zotero ID explicitly and do not set ZOTERO_API_KEY:

node /absolute/path/to/zotero-mcp/dist/cli.js \
  --library "group:<public-group-id>"
node /absolute/path/to/zotero-mcp/dist/cli.js \
  --library "user:<public-user-id>"

Replace the angle-bracketed value with a positive integer. Whether a library can be read without credentials is controlled by its owner in Zotero; selecting it does not make a private library public. See Zotero's documentation for Web API access and group library settings.

Focus on a collection

Use zotero_list_collections without collection focus to discover stable collection keys. Then add --collection <key> and restart the MCP server:

node /absolute/path/to/zotero-mcp/dist/cli.js \
  --collection ABCD1234
node /absolute/path/to/zotero-mcp/dist/cli.js \
  --library "group:<group-id>" \
  --collection ABCD1234

The first form uses the personal library discovered from ZOTERO_API_KEY; the second selects a group library. Collection keys are eight alphanumeric characters and are normalized to uppercase.

Focus includes the selected collection and every nested subcollection. Search results are merged and deduplicated when an item belongs to multiple included collections. zotero_get_item and zotero_get_fulltext reject keys outside the focused tree; child notes and attachments remain accessible when their parent item is in scope. zotero_list_collections lists only the focused tree after the option is configured.

The commands above start an MCP stdio process directly. Waiting silently for protocol input is normal; in regular use, let a configured coding agent start the process.

Coding agent configuration

The examples below use the locally built entry point. Replace /absolute/path/to/zotero-mcp with the absolute path to your checkout, <user-id> or <group-id> with a positive numeric Zotero library ID, and ABCD1234 with an eight-character collection key.

For a private library, export ZOTERO_API_KEY before starting the coding agent. For a public library, use an explicit --library selector and omit the key.

Codex CLI

Codex stores MCP servers in ~/.codex/config.toml. For a private user library focused on one collection, add:

[mcp_servers.zotero]
command = "node"
args = [
  "/absolute/path/to/zotero-mcp/dist/cli.js",
  "--library",
  "user:<user-id>",
  "--collection",
  "ABCD1234",
]
env_vars = ["ZOTERO_API_KEY"]

When the key belongs to the personal library you want to use, you may omit the --library pair and let the server discover the user ID from the key. To use a private group, change the selector to group:<group-id> and retain env_vars = ["ZOTERO_API_KEY"].

For a credential-free public group and collection, add a separate server and omit env_vars:

[mcp_servers.zotero_public]
command = "node"
args = [
  "/absolute/path/to/zotero-mcp/dist/cli.js",
  "--library",
  "group:<group-id>",
  "--collection",
  "ABCD1234",
]

Export the key before launching Codex for a private library:

export ZOTERO_API_KEY="your-read-only-key"
codex

PowerShell:

$env:ZOTERO_API_KEY = "your-read-only-key"
codex

Restart an active Codex session after changing config.toml. Run codex mcp list from the shell or /mcp inside Codex to verify the connection. See the official Codex MCP documentation for additional configuration options.

Claude Code

The following command adds a private, collection-focused server at user scope, making it available across your local Claude Code projects. Export ZOTERO_API_KEY first, as shown above:

claude mcp add \
  --env ZOTERO_API_KEY="$ZOTERO_API_KEY" \
  --transport stdio \
  --scope user \
  zotero \
  -- node /absolute/path/to/zotero-mcp/dist/cli.js \
  --library "user:<user-id>" \
  --collection ABCD1234

The --env option records the expanded key in Claude Code's private user configuration at ~/.claude.json; protect that file and never commit the key. As with Codex, you may omit the --library pair for key-based personal-library discovery, or use group:<group-id> with a key for a private group.

For a credential-free public group and collection, omit --env:

claude mcp add \
  --transport stdio \
  --scope user \
  zotero-public \
  -- node /absolute/path/to/zotero-mcp/dist/cli.js \
  --library "group:<group-id>" \
  --collection ABCD1234

Run claude mcp list or claude mcp get zotero from the shell, or /mcp inside Claude Code, to verify the connection. See the official Claude Code MCP documentation for scope and server-management details.

Other MCP clients can use the same node command, absolute entry-point path, arguments, and environment in their local stdio-server configuration format.

Privacy and security

  • The MCP process runs locally. It communicates with Zotero's Web API over HTTPS and returns results to the MCP client that launched it.

  • The server does not intentionally persist API keys or library content. A key is sent only to Zotero, and only when one is configured.

  • Tool results may be sent onward to the model or service used by your MCP client. Review that client's data policy before exposing sensitive content.

  • Prefer a dedicated read-only key, keep it out of source control and logs, and revoke it from Zotero's settings if it is exposed.

  • Standard output is reserved for MCP protocol messages. Diagnostics go to standard error and must not contain credentials.

  • Public-library mode removes the need for a credential; it does not change the visibility of the source library or the sensitivity of retrieved content.

Limitations

  • Read-only: there are no create, update, delete, upload, or annotation-writing tools.

  • No OAuth flow. Restricted libraries require ZOTERO_API_KEY.

  • No semantic search, local database integration, or persistent local content cache.

  • For authenticated libraries, note bodies require the API key's separate note-read permission.

  • Full text is limited to content already indexed and synced by Zotero. The server does not download or parse PDFs itself. See Zotero's full-text API documentation.

  • The server uses stdio only and does not expose an HTTP endpoint.

  • Live behavior depends on Zotero API availability, public-library settings, and Zotero's search and full-text indexes.

Development and testing

npm ci
npm run check

npm run check runs formatting, linting, type checking, mocked tests, a build, and a package-tarball smoke test. The mocked suite covers protocol and tool behavior without an API key or network access and remains the fast pull-request check.

The separate public-library test exercises the packed npm artifact through a real MCP stdio connection:

npm run test:e2e:public

It packs the project into an operating-system temporary directory, installs the tarball in a clean consumer project, removes ZOTERO_API_KEY from the child environment, and connects to the installed zotero-mcp executable. The test performs the MCP handshake and verifies collection listing and isolation, search, item retrieval, attachment discovery, indexed-PDF search, chunked full text, and direct attachment access. It requires outbound HTTPS access and a responsive Zotero API, so it runs only on a weekly schedule or by manual workflow dispatch. It is intentionally not a required pull-request check; run it manually as a release prerequisite until publishing is automated.

Public test fixture

The live suite reads the public Systems and Computational Neuroscience 2021 group (4445743) without credentials. It pins one uniquely searchable journal article in the Systems Neuroscience collection, its sole stored PDF attachment, and one item outside that collection so the test remains deterministic.

test/e2e/public-library-fixture.json is the committed contract. It records the collection scope, an outside item, the expected parent and attachment keys, metadata filters, stored-attachment details, a PDF-only search query, and text fragments in the first two 256-character chunks. The fixture and test contain no API key or private-library data, and the test makes no Zotero write requests.

The group is not controlled by this project. A failure can indicate a Zotero outage, indexing delay, rate limit, or external-library change as well as a package regression. Confirm the pinned public item, child, searches, and full-text API response before refreshing the fixture.

Acknowledgement

This project was inspired by yilewang/llm-for-zotero. llm-for-zotero uses LLMs in Zotero. zotero-mcp uses Zotero in LLMs.

License

MIT

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (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.

Related MCP Servers

View all related MCP servers

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

  • Agentic search over your Dewey document collections from any MCP-compatible client.

View all MCP Connectors

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/ZhongxuanWu/zotero-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server