MCP server · Audited from source

Zotero MCP server

by 54yyyu/zotero-mcpMIT licenceAudited 21 Sep 2026 · source 2cfee124554b

PyPI zotero-mcp-server 0.9.1ssestdiostreamable-http★ 5,098
!CAUTIONGrade C · 76/100 · 21 Sep 2026 · 2cfee12
5,098GitHub stars

Is it safe? With care — CAUTION, grade C (76/100). It exposes 3 tools: 1 read, 1 write and 1 destructive. The audit recorded 22 findings (0 critical, 0 high, 6 medium, 16 low). Maintainer's description: Zotero MCP: Connects your Zotero research library with Claude and other AI assistants via the Model Context Protocol to discuss papers, get summaries, analyze citations, and more.

Ask an AI about this pageGChatGPTCClaudePPerplexityGeGeminiXGrok
More
Cite

Cite this page

ModelsAtlas. “Zotero MCP server (54yyyu/zotero-mcp)”. Retrieved 21 Sep 2026. https://modelsatlas.com/mcp/54yyyu/zotero-1

4 MCP servers are called Zotero. You are viewing 54yyyu/zotero-mcp. Compare all 4 →

Trust audit

Audit 0.4.1 · full source read 21 Sep 2026

Trust score76/100!CAUTION C
0 critical0 high6 medium16 low0 info

22 findings, listed below with the file and line each was found on. Grade A needs a sandboxed behavioural run too; this audit read the source only.

What the source does

  • FilesystemDeclared7 observations
  • NetworkDeclared10 observations
  • ShellNone observedNothing seen in the source
  • DependenciesPinnedNothing floats
  • SecretsNone foundNo keys in source

“Declared” means the server says it does this and the source agrees. Browser, file and shell access are expected of some kinds of server.

Five audit layers

LayerWhat we checkResult
L0 ProvenanceRepo owner, licence, archive status, activityPASS 1 finding
L1 Static sourceSecrets, path traversal, supply chainWARN 17 findings
L2 InstructionsPrompt injection and authority framing in docs and tool descriptionsPASS 3 findings
L3 InventoryDeclared tools match the sourceWARN 1 finding
L4 SandboxRun in isolation and watch behaviourSKIPPED

Provenance & runtime

Who published it, and what the audit could and could not run

Provenance

  • Repository owner 54yyyuUser accountAccount type recorded when we read the repository.
  • PackagePublished on PyPIzotero-mcp-server at version 0.9.1
  • LicenceMITFrom the repository, as read at the audited commit.
  • Last push5 days agoActivity of the repository when we read it.
  • Source commit read2cfee124554bThe audit covers exactly this commit, read on 21 Sep 2026.

Runtime

  • Sandbox runNot run yetThis audit read the source only; it did not execute the server.
  • Tool inventory3 declaredRead from the source and classed read, write or destructive.

Every value here is read from the record's own repository and audit.Suggest a correction

Findings (22)

Sorted by severity

MEDIUMInformation disclosuredisclose.log_secret · src/zotero_mcp/setup_helper.py:829
F-12 Information disclosureCWE-209 · CWE-532Layer L1
print(f"  API Key: {_obfuscate_sensitive(api_key)}")
Why
No further detail recorded for this rule.
Fix
—
MEDIUMFilesystem / pathfs.system_paths · Dockerfile:43
F-05 Filesystem / pathCWE-22 · CWE-59Layer L1
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
Why
No further detail recorded for this rule.
Fix
—
MEDIUMNetwork egressnet.raw_ip · src/zotero_mcp/better_bibtex_client.py:66
F-04 Network egressCWE-200 · CWE-319Layer L1
self.base_url = f"http://127.0.0.1:{self.port}/better-bibtex/json-rpc"
Why
No further detail recorded for this rule.
Fix
—
MEDIUMNetwork egressnet.raw_ip · src/zotero_mcp/better_bibtex_client.py:121
F-04 Network egressCWE-200 · CWE-319Layer L1
f"http://127.0.0.1:{self.port}/better-bibtex/cayw?probe=true",
Why
No further detail recorded for this rule.
Fix
—
MEDIUMNetwork egressnet.raw_ip · src/zotero_mcp/tools/annotations.py:175
F-04 Network egressCWE-200 · CWE-319Layer L1
f"http://127.0.0.1:{port}/connector/saveItems",
Why
No further detail recorded for this rule.
Fix
—
MEDIUMFilesystem / pathmcp.destructive_tools
F-05 Filesystem / pathCWE-22 · CWE-59Layer L3
zotero_remove_item_relation
Why
1 tool(s) can delete or overwrite
Fix
prefer a read-only mode or scoped tokens; the page states the blast radius
LOWInventory / provenanceinv.hidden_file · .pre-commit-config.yaml
F-13 Inventory / provenanceCWE-1104Layer L0
.pre-commit-config.yaml
Why
hidden member outside the usual dotfiles
Fix
review its purpose
LOWCode injectioncode.dynamic_import · tests/live/test_batch_live.py:112
F-02 Code injectionCWE-78 · CWE-94 · CWE-95Layer L1
module = __import__(f"zotero_mcp.{provider}_batch", fromlist=["_"])
Why
No further detail recorded for this rule.
Fix
—
LOWCode injectioncode.dynamic_import · tests/test_chroma_client_real.py:335
F-02 Code injectionCWE-78 · CWE-94 · CWE-95Layer L1
mod = importlib.import_module(path.stem)
Why
No further detail recorded for this rule.
Fix
—
LOWCode injectioncode.eval_exec · tests/test_description_tokens.py:108
F-02 Code injectionCWE-78 · CWE-94 · CWE-95Layer L1
desc_val = eval(desc_text, {"__builtins__": {}}, {})
Why
evaluates text as code
Fix
remove; use a parser or a dispatch table
LOWInsecure cryptocrypto.weak_hash · src/zotero_mcp/tools/_helpers.py:2114
F-09 Insecure cryptoCWE-327 · CWE-338Layer L1
digest = hashlib.md5()
Why
No further detail recorded for this rule.
Fix
—
LOWInsecure cryptocrypto.weak_hash · src/zotero_mcp/webdav.py:108
F-09 Insecure cryptoCWE-327 · CWE-338Layer L1
digest = hashlib.md5()  # noqa: S324 — Zotero's WebDAV protocol mandates md5
Why
No further detail recorded for this rule.
Fix
—
LOWInsecure cryptocrypto.weak_hash · tests/test_attach_file.py:551
F-09 Insecure cryptoCWE-327 · CWE-338Layer L1
"md5": hashlib.md5(content).hexdigest(),
Why
No further detail recorded for this rule.
Fix
—
LOWInsecure cryptocrypto.weak_hash · tests/test_attach_file.py:576
F-09 Insecure cryptoCWE-327 · CWE-338Layer L1
"md5": hashlib.md5(b"%PDF-1.4 other-bytes").hexdigest(),
Why
No further detail recorded for this rule.
Fix
—
LOWInsecure cryptocrypto.weak_hash · tests/test_attach_file.py:604
F-09 Insecure cryptoCWE-327 · CWE-338Layer L1
"md5": hashlib.md5(b"%PDF-1.4 old-bytes").hexdigest(),
Why
No further detail recorded for this rule.
Fix
—
LOWNetwork egressnet.metadata_ip · tests/test_pdf_cascade.py:293
F-04 Network egressCWE-200 · CWE-319Layer L1
zot, "ITEM1", "http://169.254.169.254/latest/meta-data/", "10.1/x", dummy_ctx)
Why
cloud metadata endpoint: the classic SSRF credential grab
Fix
—
LOWNetwork egressnet.raw_ip · tests/test_pdf_cascade.py:282
F-04 Network egressCWE-200 · CWE-319Layer L1
zot, "ITEM1", "http://127.0.0.1:23119/api/users/0", "10.1/x", dummy_ctx)
Why
No further detail recorded for this rule.
Fix
—
LOWNetwork egressnet.raw_ip · tests/test_pdf_cascade.py:293
F-04 Network egressCWE-200 · CWE-319Layer L1
zot, "ITEM1", "http://169.254.169.254/latest/meta-data/", "10.1/x", dummy_ctx)
Why
No further detail recorded for this rule.
Fix
—
LOWPrivilege escalation / persistencepriv.escalate · .github/workflows/release.yml:115
F-06 Privilege escalation / persistenceCWE-269 · CWE-250Layer L1
sudo mv mcp-publisher /usr/local/bin/
Why
asks for elevated privileges
Fix
—
LOWPrompt injectionprompt.credential_read · docs/configuration.md:7
F-01 Prompt injectionCWE-94 · CWE-1427Layer L2
- **Local read-only**: offline access to a running Zotero, no credentials at all (`ZOTERO_LOCAL=true`)
Why
asks the agent to read credentials
Fix
—
LOWPrompt injectionprompt.credential_read · docs/getting-started.md:233
F-01 Prompt injectionCWE-94 · CWE-1427Layer L2
Add `--scope project` after `add` to keep the server configuration in the current project. For hybrid or web API access, add the credentials described above to the `env` command. See [Autohand Code](h
Why
asks the agent to read credentials
Fix
—
LOWPrompt injectionprompt.transfer_instruction · CHANGELOG.md:370
F-01 Prompt injectionCWE-94 · CWE-1427Layer L2
- **`update-db --allow-mass-deletion`** — the deletion pass now refuses to remove 25+ documents amounting to 25%+ of the syncing library's indexed documents in one run, a fingerprint far more likely t
Why
an instruction to move sensitive data to an outside destination
Fix
remove; a skill never needs the user's secrets off the machine

Tools it exposes

3 declared in source · 1 destructive

1 read1 write1 destructive

1 tool can delete or overwrite. An agent that can be talked into calling a tool can be talked into calling this one, so give it a token scoped to what you need.

ToolRiskWhat it does
zotero_remove_item_relationdestructiveNo description in the source
zotero_add_item_relationwriteNo description in the source
zotero_get_item_relatedreadNo description in the source

Install

Package version 0.9.1 · audited commit 2cfee12

Read the findings first. The most severe is Information disclosure (medium) at src/zotero_mcp/setup_helper.py.

claude mcp add zotero-mcp-server --env ZOTERO_API_KEY=${ZOTERO_API_KEY} -- uvx zotero-mcp-server==0.9.1 serve

The command pins the package version recorded in the source (0.9.1); the audit covers commit 2cfee124554b. Transport: sse · stdio · streamable-http. Reads these environment variables: GEMINI_API_KEY, GITHUB_TOKEN, GOOGLE_API_KEY, OPENAI_API_KEY, ZOTERO_API_KEY, ZOTERO_TOKENS_PER_MINUTE. Give it the narrowest token it needs.

Audit history

  1. !CAUTION C 76 / 100

    Source changed, verdict held · 2cfee124554b

README badge

For maintainers · updates on every re-audit

ModelsAtlas: CAUTION CMODELSATLASCAUTION · C
[![ModelsAtlas: CAUTION C](https://modelsatlas.com/mcp/54yyyu/zotero-1/badge.svg)](https://modelsatlas.com/mcp/54yyyu/zotero-1/)

The badge always shows the latest audit; a maintainer cannot pin an old verdict.

Other ratings

Cited, never blended into our score

No third-party security ratings are recorded for this server yet. When they exist they appear here with their source and date, beside, not inside, our grade.

Questions about Zotero MCP server

What is the Zotero MCP server?
Zotero MCP: Connects your Zotero research library with Claude and other AI assistants via the Model Context Protocol to discuss papers, get summaries, analyze citations, and more.
What tools does Zotero expose?
3 in total: 1 read-only, 1 that write, and 1 that can delete or overwrite (zotero_remove_item_relation). Every one is listed on this page with its risk.
Is Zotero safe to connect to an agent?
With care. The audit graded it C (76/100) and found 22 things worth knowing before you trust this server, listed below with the exact line each was found on. Separately from the audit: 1 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does Zotero need?
It reads GEMINI_API_KEY, GITHUB_TOKEN, GOOGLE_API_KEY, OPENAI_API_KEY, ZOTERO_API_KEY and ZOTERO_TOKENS_PER_MINUTE from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does Zotero run?
It speaks sse, stdio and streamable-http, so it runs as a local process your client starts. It is published on PyPI as zotero-mcp-server.
How current is this page?
The grade is for one exact copy of the source (2cfee124554b), read on 2026-09-21. The repository is watched and re-audited when it changes.
Which Zotero MCP server is the right one?
kujenga/zotero-mcp. 4 servers share the name; see the side-by-side comparison.

Sources

  • 54yyyu/zotero-mcp on GitHub — the source we read, its licence, stars and activityObserved · 21 Sep 2026
  • ModelsAtlas trust audit — CAUTION verdict for commit 2cfee124554bObserved · 21 Sep 2026

Spotted something wrong? Report a correction · Methodology

Keep going in your AI

Opens with this page as the source. We add nothing else to the prompt.