ZoteusBLOCK
Zotero MCP server: search, citations, add by DOI, safe writes, semantic search and PDF page images for Claude, ChatGPT and any MCP client. TypeScript, local-first.
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
A Zotero MCP server. Your whole library, inside Claude and ChatGPT.
Zoteus gives Claude Desktop, claude.ai, ChatGPT, Claude Code, Cursor and any other MCP client access to a Zotero library: search by keyword or by meaning, passages from your PDFs with page numbers, citations in any CSL style, adding items, and safe writes.
[](https://www.npmjs.com/package/@oscardvs/zoteus) [](https://www.npmjs.com/package/@oscardvs/zoteus) [](https://github.com/oscardvs/zoteus/actions/workflows/ci.yml) [](https://www.npmjs.com/package/@oscardvs/zoteus) [](./LICENSE)
A real session, 6 September 2026, against the maintainer's own library. Tool calls are shown as a time-lapse. The full recording is on zoteus.com.
Install
For most clients there is nothing to download: the client fetches Zoteus with npx the first time it runs. New to MCP servers? Start with docs/getting-started.md.
962f672db80cOBSERVED · 2026-10-11Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add zoteus --env ZOTERO_API_KEY=${ZOTERO_API_KEY} -- npx -y @oscardvs/[email protected]Exposed tools (34)
21 read · 8 write · 5 destructive. Blast radius: 5 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
Lab | read | Reading group |
ping | read | |
probe | read | probe |
search_tools | read | Discover the available Zotero tools by keyword — useful for progressive disclosure when you do not want to load every tool definition up front (the code-execution-with-MCP pattern). Pass an optional |
zotero_annotate | destructive | Add or delete Zotero PDF annotations (highlights, underlines, notes), the same objects you create in the Zotero PDF reader. |
zotero_attach_file | write | Add a stored file attachment (e.g. a PDF full text) under an existing item. Give |
zotero_attachment | write | Upload, download, or inspect attachment files. |
zotero_bibliography | read | Produce a formatted bibliography for items already in a Zotero library, rendered server-side by Zotero in a CSL style (by the desktop app for a library it serves, so no cloud key is needed there; otherwise by the Web API). Provide |
zotero_create_items | write | Create new items or update existing ones in a single batch (the server auto-chunks into groups of 50). |
zotero_delete_items | destructive | PERMANENTLY and IRREVERSIBLY delete items by key (this purges them — it is NOT the trash). Prefer zotero_trash_items, which is reversible. This tool is disabled unless the server is started with ZOTEUS_ALLOW_DELETE=true, and additionally requires |
zotero_evidence_table | read | Render rows of retrieved evidence as a Markdown or CSV table, deterministically, from passages you already retrieved with zotero_get_fulltext and zotero_semantic_search. This tool does NOT search and does NOT read the library: it formats what you pass it and echoes each row\ |
zotero_export | read | Export items in a bibliographic format and return the raw text. Choose |
zotero_format_bibliography | read | Render a formatted bibliography in any CSL style using citeproc-js — no Zotero library write required. Provide either |
zotero_fulltext | read | Not a search — to find which items contain a term, use |
zotero_get_fulltext | read | Retrieve an item |
zotero_get_item | read | Fetch one item by its key, returning the full item record (itemType, all bibliographic fields, creators, tags, collections, relations, version). Optionally set |
zotero_groups | read | List the group libraries this server can reach, with each group\ |
zotero_import | write | Resolve bibliographic metadata to Zotero item-data and optionally save it to your library. |
zotero_index | read | Manage the local hybrid-search index used by zotero_semantic_search. Every job runs in the background on the server, so this tool returns immediately and never blocks on large libraries. THREE write actions, and picking the right one matters: \ |
zotero_list_collections | read | List collections in a Zotero library (key, name, parent collection key, item count), sorted by name. Read-only: available even in read-only mode (unlike zotero_manage_collections, which also writes). Every collection in the library is read, then |
zotero_list_tags | read | List tags in a Zotero library with their usage count and whether each was auto-applied by Zotero. Optional |
zotero_manage_collections | destructive | List, create, rename, reparent, or delete collections, and move items into or out of a collection. Set |
zotero_manage_tags | destructive | List tags, or add/remove tags on items. Set |
zotero_pdf_images | read | See a PDF the way a reader does. Text extraction (zotero_get_fulltext) loses figures, turns tables into run-together numbers, drops most equations, and returns nothing for a scanned page with no text layer; this tool returns pictures instead. Pass a parent |
zotero_saved_searches | destructive | List, create, or delete saved-search DEFINITIONS. NOTE: the Zotero cloud Web API stores saved searches but does NOT execute them — to get the items a saved search matches, run an equivalent zotero_search_items query (or use the desktop local API when available). Set |
zotero_schema | read | Return the Zotero data model so you never hardcode item shapes. With no arguments, returns the schema version and the list of all item type names. With |
zotero_search_items | read | Search or list items in a Zotero library or collection. Quick search via |
zotero_styles | read | Resolve a human citation-style name to a valid CSL style id and confirm it is available, or list common style aliases. |
zotero_sync | write | Return what changed in a library since a given version, for efficient incremental sync. Provide |
zotero_tag_audit | read | Audit a library against a controlled tag vocabulary with priority tiers. Provide the vocabulary inline as |
zotero_trash_items | write | Move items to the trash (the safe, REVERSIBLE default) or restore them. This sets the |
zotero_update_item | write | Partially update one item (HTTP PATCH — only the fields you supply change; omitted fields are preserved). Provide |
zotero_whoami | read | Resolve the current Zotero identity (userID, username, display name) and per-library access scopes from the configured API key, report the running Zoteus |
zotero_word_document | write | Write a .docx whose citations are LIVE Zotero fields, not plain text: Zotero\ |
Trust audit
BLOCKgrade D · trust 69/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | FAIL |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (6 observation(s))
- Network
- declared (8 observation(s))
- Shell
- none-observed
- Dependencies
- not all pinned
- Secrets in source
- none-found
Findings (25)
item-payload.ts
if (a === 169 && b === 254) return true; // link-local + cloud IMDS (169.254.169.254)
ZOTEUS_TRANSLATION_SERVER_URL=http://127.0.0.1:1969
# ZOTEUS_OLLAMA_URL=http://127.0.0.1:11434
'μ': 'μ', // U+00B5 MICRO SIGN: unicode61 unifies it with Greek mu, so μm answers to μm.
zotero_annotate, zotero_delete_items, zotero_manage_collections, zotero_manage_tags, zotero_saved_searches
item-payload.test.ts
const md5 = createHash('md5').update(bytes).digest('hex');const md5 = createHash('md5').update(file.bytes).digest('hex');return createHash('sha1')import type { ToolContext } from '../../registry/registry.js';import { ensureLocalApi, isPersonalLibrary } from '../../registry/registry.js';import type { LibraryRef } from '../../api/web-client.js';import type { ToolContext } from '../../registry/registry.js';import type { LibraryRef } from '../../api/web-client.js';on the body. A tenant could previously point `url` at `http://169.254.169.254/...` or
`url: "http://169.254.169.254/..."` or `http://127.0.0.1:<port>/...` from a tenant of a hosted
for (const url of ['https://169.254.169.254/latest/meta-data/', 'https://127.0.0.1:8080/x.pdf', 'https://[::1]/x.pdf']) {const err = await failure(downloadAttachment(ctx, 'http://169.254.169.254/latest/meta-data/'));
on the body. A tenant could previously point `url` at `http://169.254.169.254/...` or
`http://127.0.0.1:<port>/...` and have the bytes stored in their library. A local, stdio
at http://127.0.0.1:1969" and suggested installing Docker: a missing identifier and a
@modelcontextprotocol/sdk, citeproc, cors, express, express-rate-limit, zod, @types/cors, @types/express
> **Semantic search setup.** The first `zotero_semantic_search` builds the library index in the background. On very large libraries you can also run `zotero_index` (action:"build") yourself, then poll
The default installation does not send usage analytics to the project. Optional operator-controlled usage logging is described below. The connector processes data on the machine or server where it run
Gates applied: no_behavioural_pass.
962f672db80cfull audit observations/trust-audit/mcp-server/oscardvs__zoteus.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-11 | 962f672db80c | BLOCK | D | 69 | first audit |
Questions
What is the @oscardvs/zoteus MCP server?
Zotero MCP server: search, citations, add by DOI, safe writes, semantic search and PDF page images for Claude, ChatGPT and any MCP client. TypeScript, local-first.
What tools does @oscardvs/zoteus expose?
34 in total: 21 read-only, 8 that write, and 5 that can delete or overwrite (zotero_annotate, zotero_delete_items, zotero_manage_collections, zotero_manage_tags, zotero_saved_searches). Every one is listed on this page with its risk.
Is @oscardvs/zoteus safe to connect to an agent?
No — not without reading the findings first. The audit graded it D (69/100) and found 2 critical or high issues in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 5 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does @oscardvs/zoteus need?
It reads GEMINI_API_KEY, OPENAI_API_KEY, ZOTERO_API_KEY and ZOTEUS_METRICS_TOKEN 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 @oscardvs/zoteus run?
It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on npm as @oscardvs/zoteus at 1.22.4.
How current is this page?
The grade is for one exact copy of the source (962f672db80c), read on 2026-10-11. The repository is watched and re-audited when it changes.