Skip to main content
Glama
Jayaram-Nambiar

zotero-mcp

zotero-mcp

Tests Python 3.10+ License: MIT

zotero-mcp connects AI agents such as Claude, Cursor, VS Code, ChatGPT, and Codex to your Zotero library through the Model Context Protocol (MCP). Once it is set up, you can ask an agent to:

  • search your library and read item details, abstracts, and formatted references;

  • list collections and page through their items;

  • create, edit, tag, or delete items through the Zotero Web API v3;

  • upload PDFs and other files as attachments;

  • turn citation markers in a Word document into real Zotero citations that the Zotero Word plugin can refresh and restyle.

You set it up once: install one command, store your Zotero user ID and API key once, and point every agent at that command.

Contents

Related MCP server: zotero-mcp

How it works

flowchart LR
    agent["AI agent"] -- "MCP over standard input and output" --> server["zotero-mcp"]
    server -- "reads" --> desktop["Zotero desktop app (local API)"]
    server -- "reads when the app is closed, and every write" --> web["api.zotero.org"]
    web -- "Zotero sync" --> desktop
  • Each agent starts zotero-mcp by itself whenever it needs it and talks to it over standard input and output. You never run the server by hand, and it opens no network port.

  • Reads go to the Zotero desktop app first, at http://127.0.0.1:23119/api. That is fast and works offline. If the app is closed, or its library has no items yet, reads use https://api.zotero.org instead. Writes always go to api.zotero.org, and Zotero syncs them back to the desktop app.

  • The server needs two values from you: your numeric Zotero user ID and a Zotero API key. You store them once, as environment variables, in Step 2.

Before you start

You need

Notes

Windows, macOS, or Linux

Each step shows the commands for each system.

The Zotero desktop app, version 7 or later

Step 1 turns on the setting this server uses.

A zotero.org account

Needed for syncing and for the API key.

An AI agent that supports MCP

Claude Desktop, Claude Code, Cursor, VS Code with GitHub Copilot, the ChatGPT desktop app or Codex, Google Antigravity, opencode, or another MCP client.

Git and uv

Step 3 installs them if you do not have them.

Microsoft Word with the Zotero Word plugin

Only for Word citations. Step 1 shows how to install the plugin.

Running commands. Several steps use a terminal:

  • Windows: open PowerShell: press Start, type PowerShell, and press Enter.

  • macOS: open Terminal from Applications → Utilities.

  • Linux: open your terminal app.

Copy one code block at a time, paste it into the terminal, and press Enter. Text that starts with YOUR_, such as YOUR_USER_ID, is a placeholder: replace all of it with your own value. Example paths that contain you, such as C:\Users\you\..., stand for paths on your computer; Step 3 prints yours.

Step 1: Set up Zotero

  1. Install Zotero. Download it from zotero.org/download, install it, and open it.

  2. Sign in and sync. Open Zotero's settings (Edit → Settings on Windows and Linux, Zotero → Settings on macOS), choose Sync, sign in with your zotero.org account, and let the library sync. If you have no account yet, create one at zotero.org/user/register.

  3. Turn on the local API. In the same settings window, choose Advanced and select Allow other applications on this computer to communicate with Zotero. The server then reads your library from the desktop app, quickly and without the internet.

  4. Create an API key. Sign in at zotero.org and open Create a new private key.

    • Enter a name you will recognize, such as zotero-mcp.

    • Under Personal Library, allow library access. Allow write access only if agents should be able to create, edit, upload, or delete items.

    • Save the key and copy it right away. Zotero shows it only once.

  5. Copy your user ID. The API keys page shows your user ID for API calls. It is a number, not your username.

  6. Optional: install the Word plugin. For Word citations, open Zotero's settings, choose Cite → Word Processor Plugins, and install the Microsoft Word add-in. Restart Word; a Zotero tab appears. Installing the word processor plugin has more detail.

Treat the API key like a password: it opens your library. Never paste it into a chat, an issue, a screenshot, or a file you share.

Step 2: Store your user ID and API key

The server reads two environment variables:

Variable

Value

ZOTERO_USER_ID

The user ID you copied in Step 1

ZOTERO_API_KEY

The API key you created in Step 1

Store them once for your user account, and every agent can find them. On Windows, the key never has to be pasted into an agent's settings. On macOS and Linux, a few apps need the values in their own config; Step 4 says which. The server does not read .env files; .env.example only lists the names.

Windows

  1. Open PowerShell.

  2. Save your user ID. Replace YOUR_USER_ID with the number, and keep the quotation marks:

    [Environment]::SetEnvironmentVariable("ZOTERO_USER_ID", "YOUR_USER_ID", "User")
  3. Save your API key. This command asks for the key and hides it while you paste, so the key never appears on screen or in PowerShell's history. It is one long line; copy all of it:

    $key = Read-Host "Paste your Zotero API key" -AsSecureString; [Environment]::SetEnvironmentVariable("ZOTERO_API_KEY", [System.Net.NetworkCredential]::new("", $key).Password, "User"); Remove-Variable key
  4. Check both values. The first line prints your user ID; the second prints True:

    [Environment]::GetEnvironmentVariable("ZOTERO_USER_ID", "User")
    [bool][Environment]::GetEnvironmentVariable("ZOTERO_API_KEY", "User")

Prefer a window to commands? Press Start, type environment variables, open Edit environment variables for your account, and add both variables under User variables.

On Windows, the server also reads these two variables directly from Windows whenever an agent does not pass them. They therefore work in every agent at once, including Claude Desktop and apps installed from the Microsoft Store, without restarting anything.

macOS and Linux

Run steps 2 to 5 in the same terminal window.

  1. Open a terminal.

  2. Tell the next commands which startup file your shell reads. macOS uses zsh by default:

    RC=~/.zshrc

    Most Linux systems use bash:

    RC=~/.bashrc

    echo $SHELL shows your shell. If you use bash on macOS, run RC=~/.bash_profile instead.

  3. Save your user ID. Replace YOUR_USER_ID with the number:

    echo 'export ZOTERO_USER_ID="YOUR_USER_ID"' >> "$RC"
  4. Save your API key. This command asks for the key without showing it, so the key never appears on screen or in your shell history. It is one long line; copy all of it:

    printf "Paste your Zotero API key: "; read -rs key; echo; echo "export ZOTERO_API_KEY=\"$key\"" >> "$RC"; unset key
  5. Load the new values and check them. The second line prints your user ID; the third prints API key is set:

    source "$RC"
    echo "$ZOTERO_USER_ID"
    [ -n "$ZOTERO_API_KEY" ] && echo "API key is set"

Agents started from a new terminal see these values. Apps opened from the Dock or an application menu usually do not read your shell's startup file; Step 4 shows what to do for those agents.

Step 3: Install zotero-mcp

Install Git

uv downloads zotero-mcp from GitHub with Git. Check whether Git is installed:

git --version

If that prints a version number, continue with Install uv. Otherwise, install Git:

System

Command

Windows

winget install --id Git.Git -e --source winget

macOS

xcode-select --install (installs Apple's command line tools, which include Git)

Debian, Ubuntu

sudo apt install git

Fedora

sudo dnf install git

Close the terminal, open a new one, and run git --version again.

Install uv

uv installs Python programs in their own environments, and downloads Python itself if needed. Check whether it is installed:

uv --version

If that does not print a version number, install uv.

Windows (PowerShell):

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

macOS and Linux:

curl -LsSf https://astral.sh/uv/install.sh | sh

Close the terminal, open a new one, and run uv --version again. The uv installation guide lists other ways to install it, such as WinGet and Homebrew.

Install the server

uv tool install git+https://github.com/Jayaram-Nambiar/zotero-mcp.git

The output includes Installed 1 executable: zotero-mcp. uv may then warn that its bin folder is not on your PATH; that is fine, because agents use the full path from the next step. Run uv tool update-shell only if you also want to type zotero-mcp in a terminal.

Check the installed version:

uv tool list

It lists zotero-mcp v1.0.2 or newer.

Copy the full path of the command

Agents start the server by its full path. Print it.

Windows (PowerShell):

Join-Path (uv tool dir --bin) "zotero-mcp.exe"

This prints a path such as C:\Users\you\.local\bin\zotero-mcp.exe.

macOS and Linux:

echo "$(uv tool dir --bin)/zotero-mcp"

This prints a path such as /Users/you/.local/bin/zotero-mcp. Keep the path at hand for Step 4.

Step 4: Connect your agents

Add the server to every agent you use, always under the name zotero. Set up only the agents you have; skip the rest.

Paths in config files

The examples write the command as /path/to/zotero-mcp. Replace it with the full path from Step 3, written for the kind of file you are editing:

Where the path goes

Windows

macOS

A terminal command

"C:\Users\you\.local\bin\zotero-mcp.exe"

/Users/you/.local/bin/zotero-mcp

A JSON file: double every backslash

"C:\\Users\\you\\.local\\bin\\zotero-mcp.exe"

"/Users/you/.local/bin/zotero-mcp"

A TOML file: use single quotes on Windows

'C:\Users\you\.local\bin\zotero-mcp.exe'

"/Users/you/.local/bin/zotero-mcp"

On Linux, the path usually starts with /home/you/ instead of /Users/you/.

Edit a JSON config file safely

Most agents keep their servers in a JSON file, in a block named mcpServers; VS Code names the block servers, and opencode names it mcp. Each agent's section below gives the commands to open and to check its file. When you add zotero:

  1. The file is empty or new: paste the agent's whole example.

  2. The file has other settings but no server block: keep everything that is already there. Put a comma after the last setting, then paste the server block inside the outer braces:

    {
      "preferences": {
        "example-setting": true
      },
      "mcpServers": {
        "zotero": {
          "command": "/path/to/zotero-mcp"
        }
      }
    }
  3. The file already has a server block: add only the "zotero": { ... } entry inside it, with a comma after the entry before it:

    {
      "mcpServers": {
        "other-server": {
          "command": "other-command"
        },
        "zotero": {
          "command": "/path/to/zotero-mcp"
        }
      }
    }

Paste the examples rather than typing them: some editors turn straight quotation marks into curly ones, which breaks JSON. After saving, run the agent's check command. If it reports an error, a comma, quotation mark, or brace is missing. If it says it cannot find the file, the path in the command is wrong, not the JSON.

Claude Desktop

Claude Desktop, the Claude chat app, reads this file:

System

File

Windows

%APPDATA%\Claude\claude_desktop_config.json

macOS

~/Library/Application Support/Claude/claude_desktop_config.json

IMPORTANT

Quit Claude Desktop completely before you edit this file. Closing the window is not enough: Claude keeps running in the background and can save its own copy of the file over your change.

Claude can also show you the file: open its Settings from the Claude menu, choose Developer, and click Edit Config. Claude creates the file if it does not exist yet. Then quit Claude before you edit it.

  1. Quit Claude Desktop.

    • Windows: right-click the Claude icon in the notification area at the right end of the taskbar (click ^ if the icon is hidden) and choose Quit.

    • macOS: choose Claude → Quit Claude in the menu bar, or press ⌘Q.

  2. Open the file.

    Windows (PowerShell). If Notepad asks whether to create the file, choose Yes:

    notepad "$env:APPDATA\Claude\claude_desktop_config.json"

    macOS (Terminal):

    mkdir -p "$HOME/Library/Application Support/Claude"
    touch "$HOME/Library/Application Support/Claude/claude_desktop_config.json"
    open -e "$HOME/Library/Application Support/Claude/claude_desktop_config.json"
  3. Add the server, following Edit a JSON config file safely.

    Windows. Claude Desktop does not pass your variables to servers, but on Windows the server reads them from Windows itself, so the entry needs only the command:

    {
      "mcpServers": {
        "zotero": {
          "command": "C:\\Users\\you\\.local\\bin\\zotero-mcp.exe"
        }
      }
    }

    macOS. The entry has to carry your two values, because Claude Desktop does not pass your variables to servers. Keep this file private:

    {
      "mcpServers": {
        "zotero": {
          "command": "/Users/you/.local/bin/zotero-mcp",
          "env": {
            "ZOTERO_USER_ID": "YOUR_USER_ID",
            "ZOTERO_API_KEY": "YOUR_API_KEY"
          }
        }
      }
    }
  4. Save the file and check it.

    Windows (PowerShell):

    Get-Content "$env:APPDATA\Claude\claude_desktop_config.json" -Raw | ConvertFrom-Json

    macOS (Terminal):

    python3 -m json.tool "$HOME/Library/Application Support/Claude/claude_desktop_config.json"
  5. Close the editor and start Claude Desktop again.

  6. Check the connection: in a chat, click + (Add files, connectors, and more) at the bottom left of the message box, point to Connectors, choose Manage connectors, and select zotero to see its tools.

Claude Code

Claude Code keeps its servers in its own settings, shared by the terminal, the Code tab of the Claude desktop app, and the IDE extensions.

  1. Open a terminal.

  2. Add the server for all your projects, with the full path from Step 3:

    claude mcp add --scope user --transport stdio zotero -- "/path/to/zotero-mcp"

    On Windows, for example:

    claude mcp add --scope user --transport stdio zotero -- "C:\Users\you\.local\bin\zotero-mcp.exe"
  3. Check the connection: claude mcp get zotero shows Status: ✔ Connected. Inside a Claude Code session, /mcp lists the connected servers.

Claude Code passes its environment to the server, so the entry needs no env block.

Cursor

Cursor reads ~/.cursor/mcp.json (%USERPROFILE%\.cursor\mcp.json on Windows) for every project, or .cursor/mcp.json inside a single project. See Cursor's Model Context Protocol guide.

  1. Open the file.

    Windows (PowerShell):

    New-Item -ItemType Directory -Force "$env:USERPROFILE\.cursor" | Out-Null; notepad "$env:USERPROFILE\.cursor\mcp.json"

    macOS (Terminal):

    mkdir -p ~/.cursor && touch ~/.cursor/mcp.json && open -e ~/.cursor/mcp.json

    Linux:

    mkdir -p ~/.cursor && nano ~/.cursor/mcp.json
  2. Add the server:

    {
      "mcpServers": {
        "zotero": {
          "type": "stdio",
          "command": "/path/to/zotero-mcp",
          "env": {
            "ZOTERO_USER_ID": "${env:ZOTERO_USER_ID}",
            "ZOTERO_API_KEY": "${env:ZOTERO_API_KEY}"
          }
        }
      }
    }

    ${env:NAME} copies each variable from Cursor's environment when the server starts, so the key is not stored in the file.

  3. Save the file and check it.

    Windows (PowerShell):

    Get-Content "$env:USERPROFILE\.cursor\mcp.json" -Raw | ConvertFrom-Json

    macOS and Linux:

    python3 -m json.tool ~/.cursor/mcp.json
  4. Restart Cursor.

  5. Check the connection: Customize in Cursor's sidebar lists zotero with its tools and lets you turn it on or off. If it does not connect, open the Output panel (Ctrl+Shift+U, or ⌘⇧U on macOS) and choose MCP Logs.

On macOS and Linux, ${env:...} finds the values only if Cursor has them, which is usually the case only when you start Cursor from a terminal. If the server reports Unconfigured, replace the two ${env:...} references with your values, and keep the file private.

VS Code with GitHub Copilot

  1. Open the Command Palette (Ctrl+Shift+P, or ⌘⇧P on macOS) and run MCP: Open User Configuration.

  2. Add the server. VS Code uses servers, not mcpServers:

    {
      "servers": {
        "zotero": {
          "type": "stdio",
          "command": "/path/to/zotero-mcp"
        }
      }
    }
  3. Save the file. VS Code underlines any JSON error in the editor.

  4. Check the connection: run MCP: List Servers, choose zotero, and start it if it is not running.

On macOS and Linux, if the server reports Unconfigured, add an env object with your two values to this entry, as in the macOS example for Claude Desktop, and keep the file private. The MCP configuration reference describes every field.

ChatGPT desktop app and Codex

The ChatGPT desktop app, the Codex CLI, and the Codex IDE extension share ~/.codex/config.toml (%USERPROFILE%\.codex\config.toml on Windows). See OpenAI's MCP guide.

  1. Open the file.

    Windows (PowerShell):

    New-Item -ItemType Directory -Force "$env:USERPROFILE\.codex" | Out-Null; notepad "$env:USERPROFILE\.codex\config.toml"

    macOS (Terminal):

    mkdir -p ~/.codex && touch ~/.codex/config.toml && open -e ~/.codex/config.toml

    Linux:

    mkdir -p ~/.codex && nano ~/.codex/config.toml
  2. Add these lines at the end of the file:

    [mcp_servers.zotero]
    command = "/path/to/zotero-mcp"
    env_vars = ["ZOTERO_USER_ID", "ZOTERO_API_KEY"]
    startup_timeout_sec = 30

    On Windows, write the path in single quotes, for example command = 'C:\Users\you\.local\bin\zotero-mcp.exe'.

  3. Save the file and restart the app, or start a new Codex session.

  4. Check the connection: in the Codex CLI, codex mcp list shows the server. In any of the apps, the check in Step 5 works too.

env_vars forwards the two variables from the app's environment, so the key stays out of the file. On macOS and Linux, the app may not have the variables, for example when you start it from the Dock. If the server reports Unconfigured, add your values below the entry instead, and keep the file private:

[mcp_servers.zotero.env]
ZOTERO_USER_ID = "YOUR_USER_ID"
ZOTERO_API_KEY = "YOUR_API_KEY"

ChatGPT in a web browser cannot start programs on your computer, so it cannot use this server.

Google Antigravity

Antigravity reads ~/.gemini/config/mcp_config.json (%USERPROFILE%\.gemini\config\mcp_config.json on Windows). See Antigravity's MCP guide.

  1. Open the file.

    Windows (PowerShell):

    New-Item -ItemType Directory -Force "$env:USERPROFILE\.gemini\config" | Out-Null; notepad "$env:USERPROFILE\.gemini\config\mcp_config.json"

    macOS (Terminal):

    mkdir -p ~/.gemini/config && touch ~/.gemini/config/mcp_config.json && open -e ~/.gemini/config/mcp_config.json

    Linux:

    mkdir -p ~/.gemini/config && nano ~/.gemini/config/mcp_config.json
  2. Add the server:

    {
      "mcpServers": {
        "zotero": {
          "command": "/path/to/zotero-mcp"
        }
      }
    }
  3. Save the file and check it.

    Windows (PowerShell):

    Get-Content "$env:USERPROFILE\.gemini\config\mcp_config.json" -Raw | ConvertFrom-Json

    macOS and Linux:

    python3 -m json.tool ~/.gemini/config/mcp_config.json
  4. Restart Antigravity.

  5. Check the connection: Additional Options (…) → MCP Servers lists zotero and its tools.

Antigravity passes its environment to the server, so the entry needs no env block. On macOS and Linux, if the server reports Unconfigured, add an env object with your two values, as in the macOS example for Claude Desktop. Antigravity's config does not expand variable references, so write the values themselves, and keep the file private.

opencode

opencode reads ~/.config/opencode/opencode.json (%USERPROFILE%\.config\opencode\opencode.json on Windows). If you already keep your settings in opencode.jsonc in the same folder, edit that file instead. See opencode's MCP servers guide.

  1. Open the file.

    Windows (PowerShell):

    New-Item -ItemType Directory -Force "$env:USERPROFILE\.config\opencode" | Out-Null; notepad "$env:USERPROFILE\.config\opencode\opencode.json"

    macOS (Terminal):

    mkdir -p ~/.config/opencode && touch ~/.config/opencode/opencode.json && open -e ~/.config/opencode/opencode.json

    Linux:

    mkdir -p ~/.config/opencode && nano ~/.config/opencode/opencode.json
  2. Add the server inside mcp:

    {
      "mcp": {
        "zotero": {
          "type": "local",
          "command": ["/path/to/zotero-mcp"],
          "enabled": true,
          "environment": {
            "ZOTERO_USER_ID": "{env:ZOTERO_USER_ID}",
            "ZOTERO_API_KEY": "{env:ZOTERO_API_KEY}"
          }
        }
      }
    }

    opencode replaces {env:NAME} with the variable's value when it loads the file.

  3. Save the file and check it. (A .jsonc file that contains comments fails this check even when it is correct.)

    Windows (PowerShell):

    Get-Content "$env:USERPROFILE\.config\opencode\opencode.json" -Raw | ConvertFrom-Json

    macOS and Linux:

    python3 -m json.tool ~/.config/opencode/opencode.json
  4. Restart opencode, then run the check in Step 5.

Other MCP clients

Any client that can start a local MCP server needs these settings:

Setting

Value

Name

zotero

Transport

stdio

Command

The full path from Step 3

Arguments

None

Environment

ZOTERO_USER_ID and ZOTERO_API_KEY. Optional on Windows, where the server reads them itself.

Perplexity's MCP documentation covers connecting other clients to Perplexity, not starting a local server from the Perplexity app.

Step 5: Check that it works

  1. Open a new chat in an agent you set up. In VS Code, use Copilot Chat in Agent mode.

  2. Ask: Search my Zotero library for <a word from a title you know>.

  3. If the agent asks for permission to use a Zotero tool, allow it.

  4. The agent calls search_zotero and lists matching items. Each comes with an eight-character item key, such as ABCD1234.

If the agent does not list Zotero tools, or a tool reports Unconfigured, see Troubleshooting.

Use the tools

Ask in plain language; the agent picks the tool. Some examples:

You ask

The agent uses

"Find papers by Vaswani in my Zotero library."

search_zotero

"List my Zotero collections."

list_zotero_collections

"Show the items in my Thesis collection."

list_zotero_collections, then list_zotero_items

"Give me the abstract of item ABCD1234."

get_zotero_item

"Add the tag to-read to item ABCD1234."

zotero_api (needs a key with write access)

"Attach C:\papers\smith2020.pdf to item ABCD1234."

zotero_api to create the attachment item, then upload_zotero_file

"Turn the citation markers in C:\drafts\paper.docx into Zotero citations."

embed_zotero_word_fields

Tool

What it does

search_zotero

Search title, creator, or year. The query argument is one Zotero quick-search phrase.

list_zotero_items

Page through the library, or one collection when collection_key is set.

list_zotero_collections

List collections.

get_zotero_item

Fetch one item, including its abstract and a Vancouver line.

zotero_api

Send any other Web API v3 request. DELETE requires confirm_delete true.

upload_zotero_file

Upload a file onto an attachment item that already exists.

embed_zotero_word_fields

Replace citation markers in a .docx with Zotero Word fields.

Search results and item lists come one page at a time. To get the next page, call again with start set to the returned next_start, until next_start is null; list_zotero_collections returns your collections in one result. Item keys are eight letters or digits. Zotero documents write requests in Write Requests and File Uploads.

The tools that take a file need its full path, such as C:\drafts\paper.docx on Windows or /Users/you/Documents/paper.docx on macOS. A path that starts with ~ is not expanded.

The tools are also plain Python functions. Install the package into a Python environment (python -m pip install git+https://github.com/Jayaram-Nambiar/zotero-mcp.git), then:

from zotero_mcp.server import search_zotero

page = search_zotero("vaswani attention")
for match in page.matches:
    print(match.item_key, match.title)

Create Word citations

Plain text such as (Smith, 2020) or a pasted reference is not a Zotero citation: the Word plugin works with Word fields. Zotero explains how it stores them in Why do I see ADDIN ZOTERO_ITEM CSL_CITATION?. This server writes those fields for you from simple markers.

  1. Find the item keys. Ask your agent, for example: Search my Zotero library for "Attention is all you need" and give me the item key.

  2. Write markers in your document where each citation belongs, and one marker where the bibliography belongs:

    {{zotero:ABCD1234}}
    {{zotero:ABCD1234+EFGH5678}}
    {{zotero:ABCD1234|locator=12|label=page}}
    {{zotero:ABCD1234|prefix=see|suffix=.}}
    {{zotero:ABCD1234|suppress-author=true}}
    {{zotero:bibliography}}
    • ABCD1234 is an item key. A plus sign joins several items into one citation.

    • locator adds a page or other location. label names it and defaults to page; other CSL labels include chapter, figure, paragraph, and volume.

    • prefix adds text before the citation, and suffix adds text right after it. Spaces at the start and end of an option's value are ignored.

    • suppress-author=true leaves the author's name out of the citation.

    • {{zotero:bibliography}} marks where the reference list goes.

    • Spaces are allowed just inside the braces, as in {{ zotero:ABCD1234 }}. Write zotero in lowercase, directly followed by a colon. A marker that does not follow this pattern stays in the document as plain text.

  3. Save the document as .docx.

  4. Ask the agent to convert it, with the document's full path, for example: Turn the citation markers in C:\drafts\paper.docx into Zotero citations using the apa style. The agent calls embed_zotero_word_fields, which writes a new file, paper.zotero.docx, next to the original, and reports how many citations it wrote. If that number is smaller than the number of citation markers, a marker was mistyped and left as plain text.

  5. Open the new file in Word, go to the Zotero tab, and choose Refresh. Refresh formats every citation and the bibliography in the chosen style. Until then, the citations show a readable stand-in, such as 1 or (Smith, 2020).

  6. Change the style later with Zotero → Document Preferences.

style is a Zotero style name such as vancouver (the default) or apa, or a full https://www.zotero.org/styles/... URL. locale defaults to en-US. From Python:

from zotero_mcp.server import embed_zotero_word_fields

print(embed_zotero_word_fields(r"C:\drafts\paper.docx", style="apa"))

What to know before you convert:

  • A paragraph that contains a marker is rebuilt from its plain text plus the new citation fields. Everything else in that paragraph is lost:

    • formatting such as bold and italics;

    • hyperlinks (their text stays);

    • images, footnote and endnote references, and comments;

    • tracked changes and the text inside them;

    • content controls;

    • other fields. A citation inserted earlier with the Zotero plugin becomes plain text.

    Accept or reject tracked changes first, and put markers in plain paragraphs of text.

  • Markers are found in body paragraphs, table cells, and each section's main header and footer. Footnotes, text boxes, and first-page or even-page headers are not scanned.

  • The fields are Word fields. LibreOffice stores Zotero citations as reference marks, which this server does not write.

  • Citations link to your personal library through your user ID. zotero_api can still reach a group library with a groups/GROUPID/... path. A collaborator on another Zotero account sees the embedded citation data and can restyle it, but Refresh updates the live item data only for the account that owns the user ID.

Update, pin, or remove

Update

  1. Update to the newest version on GitHub:

    uv tool upgrade zotero-mcp

    This installs the newest commit on the main branch. To stay on a specific release instead, pin a version.

  2. Restart your agents so that they start the new version. Quit Claude Desktop from the notification area or menu bar, as in Claude Desktop.

  3. Run uv tool list to see the installed version.

On Windows, a running server keeps its files open. If the upgrade stops with Failed to install entrypoint or being used by another process, quit every agent, then install again:

uv tool install --force git+https://github.com/Jayaram-Nambiar/zotero-mcp.git

Pin a version

Each release has a tag, such as v1.0.2; CHANGELOG.md lists them. To install one release and stay on it:

uv tool install --force git+https://github.com/Jayaram-Nambiar/zotero-mcp.git@v1.0.2

uv tool upgrade leaves a pinned version alone. To move to another release, run the same command with that release's tag. To follow the newest version again, run the install command from Step 3 with --force.

Remove

  1. Uninstall the server:

    uv tool uninstall zotero-mcp
  2. Delete the zotero entry from each agent's config file from Step 4, and run that agent's check command afterwards. Quit Claude Desktop before you edit its file. For Claude Code, run claude mcp remove zotero -s user.

  3. Optional: delete the two variables.

    Windows (PowerShell):

    [Environment]::SetEnvironmentVariable("ZOTERO_USER_ID", $null, "User")
    [Environment]::SetEnvironmentVariable("ZOTERO_API_KEY", $null, "User")

    macOS and Linux: delete the two export ZOTERO_... lines from your shell's startup file, such as ~/.zshrc or ~/.bashrc.

  4. Optional: revoke the API key on the API keys page.

Keep a single installation of the server. Agents that point at different copies run different versions.

Troubleshooting

Problem

What to do

The agent does not list Zotero tools

Check that the command is the full path from Step 3, that the config file passes its check command, and that the agent was restarted. Quit Claude Desktop from the notification area or menu bar; closing its window does not restart it.

Claude Desktop loses the zotero entry

Claude Desktop was running while the file was edited and saved its own copy over the change. Quit it completely, edit the file again, then start it.

A tool reports Unconfigured

The server found no usable user ID or API key. Repeat Step 2. On Windows the next request picks the values up. On macOS and Linux, restart the agent, or put the values in its config as its section in Step 4 describes.

Requests fail after you replaced the API key

Store the new key as in Step 2, update any config file that holds the key itself, and restart your agents. A value an agent passes takes precedence over the stored one.

uv or git is not recognized after installing it

Close the terminal and open a new one.

The install fails with Git executable not found

Install Git, as in Install Git, then open a new terminal and repeat the install.

The upgrade fails with Failed to install entrypoint

An agent is still running the old version. Quit every agent, then run uv tool install --force git+https://github.com/Jayaram-Nambiar/zotero-mcp.git.

An agent seems to run an older version

Run uv tool list. Remove any other copy of the server, point every agent at the full path from Step 3, and restart the agent.

Reads are slow, or say the local Zotero app is not answering

Start the Zotero desktop app and turn on its local API (Step 1). Until then, reads use zotero.org.

Search finds nothing, but the website shows the item

The desktop app has a library that does not contain the item yet. Sync Zotero. The server does not fall back to the website for an item that the desktop library is missing, because the desktop library is the copy you are editing.

zotero_api returns HTTP 403

The API key does not allow that request. Create a key with the permission it needs, such as write access, and store it as in Step 2.

Converting a Word document fails on Windows

Word locks open files. Close the converted document, such as paper.zotero.docx, in Word, then convert again.

On macOS, the agent cannot read a document in Documents or Desktop

Allow the agent's access to that folder when macOS asks, or turn it on in System Settings → Privacy & Security → Files and Folders.

Word shows ADDIN ZOTERO_ITEM text

Word is showing field codes. Press Alt+F9 (Option+Fn+F9 on a Mac), or see the field-code article.

Zotero asks you to choose a citation style

The document has no Zotero document preferences. Run embed_zotero_word_fields again on the original document.

Refresh does not pick up a title you changed in Zotero

The user ID in the citations does not match the account signed in to the desktop app, or the item is not in that library.

Connection status and logs

Agent

Where to look

Claude Desktop

The log file %APPDATA%\Claude\logs\mcp-server-zotero.log on Windows, or ~/Library/Logs/Claude/mcp-server-zotero.log on macOS

Claude Code

claude mcp get zotero for the status; /mcp inside a session

Cursor

Output panel → MCP Logs

VS Code

MCP: List Servers → zotero → Show Output

Other agents

The agent's own MCP settings or documentation

For more detail, add LOG_LEVEL with the value DEBUG to the server's environment in the agent's config. The server writes its log to standard error, never to the protocol stream.

Ask for help

Open an issue with your operating system, the agent, the output of uv tool list, and the exact error message. Never include your API key, and write YOUR_USER_ID in place of your user ID, which also appears in logs.

Security

  • The API key is the key to your library. Use a key with only the access agents need, and leave write access off unless they must change your library.

  • Prefer environment variables and config references (${env:...}, env_vars, {env:...}) over pasting the key into config files. Keep any file that holds the key itself private.

  • The server sends the key only to api.zotero.org, as a request header. It never returns the key in a tool result and removes it from error messages.

  • If the key leaks, revoke it on the API keys page, create a new one, store it as in Step 2, and update any config file that holds the old key.

SECURITY.md explains how to report a vulnerability and lists the server's safeguards.

Contributing

Bug reports and pull requests are welcome. CONTRIBUTING.md explains how to set up a development environment, run the tests, and prepare a change. The test suite runs automatically on Windows, macOS, and Linux for every push to main and every pull request.

Acknowledgements

Disclaimer

This project is not affiliated with, endorsed by, or supported by Zotero or the Corporation for Digital Scholarship. Zotero is a trademark of the Corporation for Digital Scholarship. Use of the Zotero API is subject to Zotero's own terms and documentation. You are responsible for the API key you create and for the library changes an agent makes with it.

The Word fields follow the field format that Zotero documents and that its Word plugin reads. Refresh the document in Word before you rely on the citation style.

License

MIT. Copyright (c) 2026 Jayaram Nambiar.

Available Tools

7 tools
embed_zotero_word_fieldsEmbed Zotero citation fields in a Word documentA

Replace citation markers with Word fields the Zotero plugin can refresh.

Markers: {{zotero:ITEMKEY}}, {{zotero:KEY1+KEY2}}, {{zotero:ITEMKEY|locator=12|label=page|prefix=see|suffix=.}}, and {{zotero:bibliography}}. Open the result in Word and choose Zotero, Refresh.

ParametersJSON Schema
NameRequiredDescriptionDefault
styleNoCSL style short name or style URL. Default vancouver.vancouver
localeNoCitation locale, such as en-US.en-US
docx_pathYesAbsolute path of a .docx file containing {{zotero:ITEMKEY}} markers.
output_pathNoOptional .docx path to write. Empty writes a sibling named <name>.zotero.docx.
insert_bibliographyNoAppend a Zotero bibliography field when the document has no {{zotero:bibliography}} marker.

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
style_idNo
output_pathNo
citation_countNo
bibliography_insertedNo

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false and openWorldHint=true, so the agent knows this mutates state and interacts with an external environment. The description adds valuable context beyond that: the exact marker syntax that will be replaced and the requirement to open the result in Word and refresh. It does not explicitly state whether the original docx is modified, but the schema's output_path describes a sibling output file.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action and follows with necessary marker examples. Every sentence earns its place: the marker list is essential for correct invocation, and the final refresh instruction is a required post-step. No filler is present.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a full output schema, 100% parameter description coverage, and annotations covering mutation and open-world behavior, the description is complete enough to invoke the tool correctly. It supplies the marker syntax and the Word refresh procedure, which are the key tool-specific details an agent needs. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the parameter semantics baseline is 3 even without description-level parameter detail. The description adds marker syntax relevant to the docx_path input, but it does not explain style, locale, output_path, or insert_bibliography beyond what the schema already documents.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: replacing citation markers with Word fields the Zotero plugin can refresh. It names the marker syntax and the post-processing step, making its role clearly distinct from sibling tools like search_zotero or list_zotero_items. An agent can identify the tool without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by explaining the marker format and telling the user to refresh in Word afterward. However, it does not explicitly say when to use this tool versus alternatives or when not to use it. The intended context is inferable but not spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_zotero_itemGet one Zotero itemB
Read-only

Fetch one reference, including its abstract and a Vancouver bibliography line.

ParametersJSON Schema
NameRequiredDescriptionDefault
item_keyYes8-character Zotero item key from a search or list result.

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemNo
sourceNo
statusYes
messageYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=true, so the read-only safety profile is covered. The description adds that the response includes the abstract and a formatted bibliography line, which is a bit of extra context, but says nothing about failure behavior for a missing key or library scoping.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no waste; the verb, cardinality, and payoff of the call all arrive immediately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return value shape need not be explained, and annotations cover the safety profile; the one required parameter is documented. What is missing is usage routing and error/not-found behavior, though the core call is understandable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the single item_key parameter is fully documented in the schema as an 8-character Zotero key. The description adds no parameter-level meaning beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (fetch) and resource (one reference) with useful scope detail — it delivers the abstract and a Vancouver bibliography line, which separates it from the list/search siblings. It does not name a sibling explicitly, but 'one ... reference' makes the single-item retrieval semantics clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no when-to-use guidance, no prerequisites, and no alternatives. It never says to call this after search_zotero/list_zotero_items to resolve an item key, nor when a list or search tool would be preferable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_zotero_collectionsList Zotero collectionsA
Read-only

List collections in the user's library, following Zotero's 100-item pages.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
sourceNo
statusYes
messageYes
collectionsNo
total_resultsNo

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds genuine behavioral context beyond that by disclosing that results are returned in Zotero's 100-item pages, which tells the agent to expect paginated output.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with no filler that front-loads the operation and resource before adding the pagination note. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described, and there are no parameters to document. Purpose plus the pagination behavior is sufficient for an agent to call this correctly, though a note on how to traverse subsequent pages would fully close the loop.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, which is the baseline-4 case under the rubric. The description correctly implies a no-argument, library-wide enumeration with no filtering to configure.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('List') and resource ('collections') scoped to the user's library, so the agent can distinguish it from list_zotero_items or search_zotero. It does not explicitly name a sibling or contrast itself, but the resource is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied by the purpose: an agent infers this is the enumeration call for collections, but there is no explicit when-to-use statement, no prerequisites, and no mention of search_zotero as an alternative for filtered lookup.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_zotero_itemsList Zotero library itemsB
Read-only

Page through bibliographic items in the library or in one collection.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoPage size.
startNoZero-based offset. Use next_start from the previous page.
collection_keyNoOptional 8-character collection key. Empty lists the whole library.

Output Schema

ParametersJSON Schema
NameRequiredDescription
limitNo
startNo
sourceNo
statusYes
matchesNo
messageYes
next_startNo
total_resultsNo

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety and openness profile is covered. The description adds the paging trait ('Page through'), which is useful context, but says nothing about ordering, rate limits, or what paging cursor to use (that lives in the schema).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with zero filler; the scope constraint (library vs. collection) is stated immediately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and annotations covering safety, the description only needs to convey purpose and scope, which it does. It is adequate, though a brief note on ordering or how it relates to search_zotero would make it fully self-sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so limit, start, and collection_key are fully documented in the schema, including the next_start paging hint. The description's 'library or one collection' only loosely echoes collection_key, adding no syntax or format detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb ('Page through') and resource ('bibliographic items') plus scope ('in the library or in one collection'), which is clearer than the bare title. It doesn't explicitly contrast itself with search_zotero, so the sibling distinction is only implied by 'Page through' vs. search semantics.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no statement of when to choose this over search_zotero or get_zotero_item, nor any exclusions or prerequisites. The enumeration/paging use case is only implied by the words 'Page through'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_zoteroSearch the Zotero libraryA
Read-only

Search the user's Zotero library by title, creator, or year.

Attachments, notes, and annotations are omitted. Results are one page; follow next_start until it is null.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoPage size.
queryYesTitle, creator, or year. Zotero quick search treats this as one phrase.
startNoZero-based offset. Use next_start from the previous page.

Output Schema

ParametersJSON Schema
NameRequiredDescription
limitNo
startNo
sourceNo
statusYes
matchesNo
messageYes
next_startNo
total_resultsNo

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds genuine behavioral context beyond that: attachments, notes, and annotations are omitted from results, and results are paginated via next_start until null. It doesn't mention rate limits or auth, but the added scoping and pagination details are substantive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler; the search scope is front-loaded and the exclusions plus pagination contract follow immediately. Every clause carries information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be described, and the description covers result filtering and pagination adequately. The only gap is routing guidance relative to the sibling list/search tools, which keeps it from a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so limit, query, and start are fully documented in the schema, including the phrase-matching caveat for query and the next_start pattern for start. The description adds no parameter detail beyond restating the searchable fields, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Search the user's Zotero library") plus the searchable fields (title, creator, year), so the agent knows exactly what this returns. It does not name or contrast with the sibling list_zotero_items, which is the closest alternative, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage via "Search ... by title, creator, or year," but gives no explicit when-to-use or when-not-to-use guidance against siblings such as list_zotero_items or get_zotero_item. An agent must infer that this is the query-driven counterpart to the listing tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

upload_zotero_fileUpload a file to a Zotero attachmentA

Store a local file on an attachment item through the Web API upload flow.

Create the attachment first with zotero_api. A new child attachment uses itemType attachment, linkMode imported_file, parentItem, and contentType. Files already stored with the same MD5 are left unchanged. The upload limit here is 100 MB.

ParametersJSON Schema
NameRequiredDescriptionDefault
item_keyYes8-character key of an existing imported_file or imported_url attachment.
file_pathYesAbsolute path of the file on this computer.

Output Schema

ParametersJSON Schema
NameRequiredDescription
bodyNo
statusYes
messageYes
http_statusNo
last_modified_versionNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=false and openWorldHint=true. The description adds genuinely useful behavior: idempotency via MD5 dedup ('Files already stored with the same MD5 are left unchanged') and a hard 100 MB upload limit. It does not describe auth requirements or what happens on partial/failed uploads, so it falls short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then prerequisites and limits in short chunks. The enumeration of creation fields ('itemType attachment, linkMode imported_file, parentItem, and contentType') is a slight tangent belonging to the sibling tool, but overall it is tight and well ordered.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation. For a two-parameter upload tool the description covers the workflow prerequisite, the size ceiling, and the dedup rule, which is everything an agent needs to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already documented in the schema, making 3 the baseline. The description's mention of itemType/linkMode/parentItem/contentType pertains to the prerequisite zotero_api call rather than to this tool's own arguments, so it adds little parameter-level meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence gives a specific verb (store/upload), resource (a local file), and target (an attachment item via the Web API upload flow). It is clearly distinguishable from sibling zotero_api, which is identified as the tool that creates the attachment instead of uploading the bytes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly names the prerequisite ('Create the attachment first with zotero_api'), which routes the agent correctly between the two tools. It lacks an explicit when-not-to-use condition (e.g. what to do for non-imported_file link modes), but the context provided is clear and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

zotero_apiCall the Zotero Web APIA

Send one Zotero Web API v3 request to the configured user library.

Reads may still use the local app through the bibliography tools. This tool always uses api.zotero.org, including GET, so the response matches the account the API key can change. Create items with POST items and a JSON array. Put collection keys inside each item's collections array. Update one item with PATCH items/ITEMKEY or PUT of the full item data, and send its current version. Delete with DELETE and confirm_delete true.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyNoJSON object or array. Item creates are an array of item data. Include version when updating one object.
pathYesRelative Web API path. Examples: items, items/ITEMKEY, collections, collections/KEY/items, searches, tags, fulltext, deleted, groups/GROUPID/items.
queryNoQuery parameters. Values must be strings. Use itemKey for a multi-item delete.
methodYesGET, POST, PUT, PATCH, or DELETE.
write_tokenNoOptional 32-character token. Repeating it prevents a successful create from running twice.
confirm_deleteNoMust be true for DELETE. A delete without it is refused.
if_unmodified_since_versionNoLibrary version precondition for updates and deletes.

Output Schema

ParametersJSON Schema
NameRequiredDescription
bodyNo
statusYes
messageYes
http_statusNo
last_modified_versionNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=false and openWorldHint=true; the description goes further by disclosing that DELETE is refused without confirm_delete=true, that updates must carry the current version, that write_token guards against duplicate creates, and that responses reflect the API-key account rather than the local app. It does not mention rate limits or permission scopes, but it adds substantial behavior beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then a compact block of method-specific instructions. The sentences are terse but a few are telegraphic ('Create items with POST items and a JSON array'), trading a little polish for density.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a generic API passthrough with an output schema present, the description covers the essentials an agent needs: auth-account binding, method/path conventions, body shape, delete confirmation, and version preconditions. Return values are covered by the output schema, so nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3, but the description adds real meaning the schema lacks: body should be an array for item creates, collection keys belong in each item's collections array, and the version must be sent when updating. That is genuine parameter guidance rather than a restatement of the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

'Send one Zotero Web API v3 request to the configured user library' names a specific verb, resource, and target, and explicitly positions it against the bibliography tools that read the local app. An agent can distinguish it from search_zotero/list_zotero_items without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states the key routing rule (local-app bibliography tools for reads vs. this tool which always hits api.zotero.org) and spells out concrete usage patterns for POST items, PATCH items/ITEMKEY, PUT, and DELETE. It stops short of naming individual sibling tools or giving explicit exclusions, so it is clear context rather than full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 7 tool updatesv1.0.2
    • First observedembed_zotero_word_fields
    • First observedget_zotero_item
    • First observedlist_zotero_collections
    • First observedlist_zotero_items
    • First observedsearch_zotero
    • First observedupload_zotero_file
    • First observedzotero_api

TDQS

A3.9/5.0

Scored across 7 tools

Disambiguation4/5

The read tools are clearly separated by action: search_zotero (query), list_zotero_items (paginate), list_zotero_collections (collections), and get_zotero_item (single fetch). The only fuzzy boundary is zotero_api, which is a raw catch-all that can technically do everything the other tools do, but its description frames it explicitly as the Web API escape hatch, so confusion is limited.

Naming Consistency4/5

All names use snake_case with a verb-led pattern (search_, list_, get_, upload_, embed_) plus a domain noun. The placement of 'zotero' varies (search_zotero vs list_zotero_items vs zotero_api), which is a minor cosmetic inconsistency but nothing confusing.

Tool Count5/5

Seven tools is well-scoped for a Zotero library server, with dedicated read tools plus file upload, word-field embedding, and a raw API fallback. Each tool earns its place without redundancy.

Completeness4/5

Reads (search, list items, list collections, get item), file upload, and word-field embedding are covered, and zotero_api provides the create/update/delete path so there are no hard dead ends. However, first-class create/update/delete and collection management are only reachable via the raw API, leaving minor ergonomic gaps.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers