搜尋、閱讀、整理與安全寫入 Zotero;支援 Zotero 7–9 Connector 與 Zotero 10+ Local API。
Translation pending
Developer toolsPython · TypeScriptGitHub @u9401066OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Zotero 10+ Local API and PubMed MCP research workspace: Keeper 2.1, PubMed Search 0.6.1, and a one-click VS Code extension.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Let AI manage your references! A MCP Server connecting VS Code Copilot / Claude Desktop to your local Zotero library.
Zotero Keeper feature site ·
VS Code Marketplace
Prerequisites: Zotero 7, 8, 9, or 10+ must be running. Zotero 10+ is required for authorized Local API writes.
📦 Install Zotero + PubMed MCP from the VS Code MarketplaceRead the full README ↗Let AI manage your references! A MCP Server connecting VS Code Copilot / Claude Desktop to your local Zotero library.
🌐 English | 繁體中文
Prerequisites: Zotero 7, 8, 9, or 10+ must be running. Zotero 10+ is required for authorized Local API writes.
📦 Install Zotero + PubMed MCP from the VS Code Marketplace
The v0.10.0 VSIX is the recommended distribution. It creates an isolated environment and installs Zotero Keeper 2.4.0 plus the pinned PubMed Search MCP 0.7.7 release snapshot. The uvx/PyPI path remains available for direct-server installs; verify the published version before assuming it matches this source release.
⚠️ MCP SDK 2.0 is not compatible with 1.x. After upgrading the extension, run Zotero MCP: Reinstall Python Environment if VS Code still has an older managed environment.
Zotero Keeper is a MCP Server that lets your AI assistant:
No more manually searching, copying, pasting. Just tell your AI in natural language!
MCPServer API (not the incompatible 1.x FastMCP surface)zotero://collections, etc.)ROOT always requires a second confirmationcollection_name for safer auto-validation# Clone the repository
git clone https://github.com/u9401066/zotero-keeper.git
cd zotero-keeper/mcp-server
# Install with uv (required)
uv sync --extra all
# Test (make sure Zotero is running)
uv run python -m zotero_mcp
Create .vscode/mcp.json in your workspace:
{
"servers": {
"zotero-keeper": {
"type": "stdio",
"command": "uv",
"args": [
"run",
"--directory",
"/path/to/zotero-keeper/mcp-server",
"python", "-m", "zotero_mcp"
]
}
}
}
Add to claude_desktop_config.json:
{
"mcpServers": {
"zotero-keeper": {
"command": "uv",
"args": ["run", "python", "-m", "zotero_mcp"],
"cwd": "/path/to/zotero-keeper/mcp-server"
}
}
}
💡 Use absolute paths and ensure uv is installed.
If you run the server directly, these are the main settings you may want to provide via .env or your MCP launcher configuration:
ZOTERO_HOST=localhost
ZOTERO_PORT=23119
ZOTERO_TIMEOUT=30
[email protected]
# NCBI_API_KEY=your_api_key_here
# ZOTERO_KEEPER_ENABLE_LEGACY_PUBMED_TOOLS=1
# PUBMED_SEARCH_PATH=/path/to/pubmed-search-mcp
NCBI_EMAIL and optional NCBI_API_KEY for higher NCBI/PubMed rate limits.ZOTERO_KEEPER_ENABLE_LEGACY_PUBMED_TOOLS=1 only if you intentionally want keeper's older PubMed bridge/import tools.PUBMED_SEARCH_PATH only during local development when you want keeper to import a checked-out pubmed-search-mcp tree instead of the installed package.Keeper 2.4 adds two read-only citation tools: export_items (BibTeX, BibLaTeX,
RIS, CSL JSON, … through Zotero's own translators) and get_bibliography
(CSL-rendered bibliography / in-text citation HTML for any installed style).
Keeper 2.3 added seven tools: get_item_schema, get_item_annotations,
update_item_tags, update_item_creators, update_note, set_item_trashed, and
batch_update_item_fields. Saved searches preserve attachment/note/annotation
results and support nested groups and paging. See the 50-tool audit
for exact coverage and deliberate omissions (including group writes and annotation editing).
VSIX 0.9.1 stopped automatic harness overwrites; 0.10.0 keeps that behavior. Installation is opt-in, records
SHA-256 ownership, backs up managed upgrades, prevents downgrades and preserves
custom files/whole skills. Updates use atomic replacements and rollback on
failure; interrupted updates stop for recovery review. Upgrade and recovery guide.
Keeper 2.3.1 streams ownership scans with database/version checks, rejects
incomplete results, and reports unavailable statistics as unknown rather than zero.
PubMed 0.7.7 (same 41-tool interface as 0.7.3) uses validate_pico_plan for agent-provided PICO fields and
read_session(request={"action":"pmids"}) for cached session reuse.
💡 Tip: Most read operations can also be done via MCP Resources without calling tools.
| Tool | Description | Example |
|---|---|---|
check_connection | Test Zotero connectivity | "Is Zotero running?" |
search_items | Search references | "Find papers about CRISPR" |
get_item | Get item details | "Show abstract for key:ABC123" |
list_items | List recent items | "Show papers in collection X" |
list_tags | List all tags | "What tags have I used?" |
get_item_types | Available item types | "What types can I add?" |
⚠️ These can also be accessed via
zotero://collections/...Resources
| Tool | Description | Equivalent Resource |
|---|---|---|
list_collections | List all folders | zotero://collections |
get_collection | Get collection details | zotero://collections/{key} |
get_collection_items | Items in a collection | zotero://collections/{key}/items |
get_collection_tree | Hierarchical tree view | zotero://collections/tree |
find_collection | Find by name | — (Tool only) |
These tools use Zotero's official Local API v3 write support. Before preview,
obtain a response-bound server_id from a Local API read or
authorize_local_writes, and include it as expected_server_id. The key stays
inside the Keeper process; all writes are restricted to loopback and bound to
the reviewed Zotero Server-ID.
| Tool | Description | Safety boundary |
|---|---|---|
authorize_local_writes | Ask Zotero to authorize Keeper; use require_remembered=true before file upload | Never returns or logs the key |
create_collection | Create a top-level or nested collection | Exact parent key + explicit confirmation |
update_collection | Rename or move one exact collection | Current object version + exact parent validation |
delete_collection | Delete one exact collection | Destructive confirmation + current object version |
add_items_to_collection | Add up to 50 existing items without removing other memberships | Validates every key before one versioned batch write |
remove_items_from_collection | Remove up to 50 memberships without deleting the items | Preserves every other collection membership |
update_item_fields | Update approved scalar metadata fields | Requires the current local object version |
update_item_tags | Add/remove exact item tags, retaining unrelated tags | Exact object version + approved identity |
update_item_creators | Replace an ordered creator list | Runtime creator-role validation + object version |
update_note | Replace an exact note's HTML | Retains its parent; empty HTML explicitly clears |
set_item_trashed | Move to Trash or restore | Recoverable alternative to permanent deletion |
batch_update_item_fields | Update scalar metadata on up to 50 items | All versions preflighted; inspect per-item results |
delete_item | Delete one exact item, note, or attachment | Destructive confirmation + current object version |
create_note | Add a child note to an existing item | Validates the parent + explicit confirmation |
create_saved_search | Create a Zotero saved search | Structured conditions + explicit confirmation |
These operations are unavailable on Zotero 7–9, which retain the existing Connector import path. Destructive operations are exposed only as exact, versioned task tools; Keeper still does not expose an unrestricted raw API, arbitrary PATCH, or arbitrary DELETE escape hatch.
For each mutation, put expected_server_id (and the response-bound item object
version or full-text library cursor, when applicable) into the confirm=false
proposal before asking for approval. If later authorization reports a different
identity, discard that proposal, reread, preview again, and obtain new approval;
never add identity only after preview. Confirmed execution repeats the unchanged
proposal. A 412 is never retried automatically.
| Tool | Description | Example |
|---|---|---|
export_items | Export ≤50 exact item keys as BibTeX/BibLaTeX/RIS/CSL JSON/CSV/MODS/… via Zotero translators | "Export these 12 papers as BibTeX" |
get_bibliography | CSL-rendered bibliography and/or in-text citations for ≤50 exact keys (apa, vancouver, …) | "Give me the APA reference list for this collection" |
📊 Auto RCR: When PMID is provided, automatically fetches Relative Citation Ratio from iCite and stores in Zotero's extra field
| Tool | Description | Example |
|---|---|---|
interactive_save ⭐ | Interactive save + auto RCR | "Save this paper to Zotero" |
quick_save | Quick save + auto RCR | "Quick save to AI Research" |
All save paths fail closed when no destination is confirmed. interactive_save asks for an exact collection key (or the explicit sentinel ROOT); choosing ROOT triggers a second confirmation. skip_collection_prompt=True aborts instead of silently saving to the library root. quick_save, import_articles, and import_pdf reject a missing collection unless the user has explicitly confirmed root storage and the caller passes allow_library_root=true.
| Tool | Description | Example |
|---|---|---|
list_saved_searches | List all saved searches | "What saved searches exist?" |
run_saved_search | Execute a saved search | "Which papers have no PDF?" |
get_saved_search_details | Get search conditions | "What's in 'Missing PDF' search?" |
| Tool | Description | Example |
|---|---|---|
advanced_search ⭐ | Multi-condition search (itemType, tag, qmode) | "Find all journal articles tagged with AI" |
check_articles_owned | Check if PMIDs exist in Zotero | "Do I have these PMIDs?" |
🤝 Collaboration-safe default: PubMed search/discovery/export lives in pubmed-search-mcp. Zotero Keeper exposes one public import handoff:
import_articles.
| Tool | Description | Example |
|---|---|---|
import_articles ⭐ | Single public import entry for JSON articles or RIS text | "Import these PubMed results to AI Research" |
import_pdf 📎 | Import a local PDF through Zotero Connector endpoints, with metadata or Zotero recognition | "Import this PDF and attach it to its paper" |
search_pubmed_exclude_owned, quick_import_pmids, import_ris_to_zotero, import_from_pmids, and batch_import_from_pubmed are now hidden by default to avoid duplicating pubmed-search-mcp.
If you intentionally want the old standalone keeper behavior, set ZOTERO_KEEPER_ENABLE_LEGACY_PUBMED_TOOLS=1 before starting the server.
| Tool | Description | Example |
|---|---|---|
get_library_stats | Library statistics (year/author/journal) | "Show my library statistics" |
find_orphan_items | Find unorganized items | "Which papers need organizing?" |
🗂️ PDF Access: Zotero 10+ resolves attachment paths through the official Local API.
ZOTERO_DATA_DIRremains an optional fallback for older Zotero versions or unavailable view URLs.
| Tool | Description | Example |
|---|---|---|
get_item_attachments | List PDFs/snapshots for an item | "What attachments does key:X42A7DEE have?" |
get_item_fulltext | Get Zotero-indexed fulltext content | "Read the full text of key:X42A7DEE" |
# 1. Search with pubmed-search-mcp
results = unified_search("anesthesia AI", output_format="json")
# 2. Optional: filter against local Zotero
pmids = [
article.get("identifiers", {}).get("pmid")
for article in results["articles"]
]
owned = check_articles_owned(pmids=[pmid for pmid in pmids if pmid])
# 3. Import selected records into Zotero
import_articles(
articles=results["articles"],
collection_name="AI Research"
)
import_articles handoff.PUBMED_SEARCH_PATH if you rely on a local checkout.ZOTERO_KEEPER_ENABLE_LEGACY_PUBMED_TOOLS=1 intentionally.docs/COLLABORATION_WORKFLOW.md.# 🔍 依文獻類型搜尋
advanced_search(item_type="journalArticle") # 只找期刊論文
advanced_search(item_type="book") # 只找書籍
advanced_search(item_type="-attachment") # 排除附件
# 🏷️ 依標籤搜尋
advanced_search(tag="AI") # 具有 AI 標籤的文獻
advanced_search(tags=["AI", "Review"]) # 同時具有兩個標籤 (AND)
advanced_search(tag="AI || ML") # 具有任一標籤 (OR)
# 📝 全文搜尋 (含 abstract)
advanced_search(q="XGBoost", qmode="everything") # 搜尋摘要內容
# 🌟 組合條件
advanced_search(
q="machine learning",
item_type="journalArticle",
tag="AI",
sort="dateAdded",
direction="desc"
)
The SDK v2 server advertises six concrete resources. Four additional parameterized URI templates resolve individual items, collections, collection contents, and saved searches.
| Resource URI | Description |
|---|---|
zotero://collections | All collections |
zotero://collections/tree | Collection hierarchy |
zotero://items | Recent items |
zotero://tags | All tags |
zotero://searches | Saved searches |
zotero://schema/item-types | Available item types |
| Resource template | Description |
|---|---|
zotero://collections/{key} | Specific collection |
zotero://collections/{key}/items | Items in collection |
zotero://items/{key} | Item details |
zotero://searches/{key} | Saved-search details |
The interactive_save tool uses MCP Elicitation to show collection options:
User: "Save this DOI:10.1234/example paper to Zotero"
[MCP Elicitation pops up]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📚 Saving: Deep Learning for Medical Imaging
⭐ Suggested:
AI Research — key `A1B2C3D4` (match: 90%)
Medical Imaging — key `M5N6P7Q8` (match: 75%)
📂 All Collections:
Biology — key `B1O2L3O4` (12 items)
Chemistry — key `C5H6E7M8` (8 items)
To Read — key `T1O2R3E4` (23 items)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Enter the exact collection key, or `ROOT`: [User enters: A1B2C3D4]
AI: ✅ Saved to 'AI Research' collection!
ROOT is not a default shortcut. Selecting it starts a second confirmation before a save can proceed; declining or skipping the prompt aborts the operation.
When you provide a DOI or PMID, the tool automatically fetches complete metadata:
No more missing abstracts! Just provide the identifier.
Zotero supports nested collections. Recommended strategies:
📁 My Library
├── 📁 Research Topics
│ ├── 📂 CRISPR Gene Editing
│ ├── 📂 Machine Learning in Medicine
│ └── 📂 Anesthesia Safety
├── 📁 Projects
│ ├── 📂 2024 Paper Draft
│ └── 📂 PhD Thesis
└── 📁 Reading List
├── 📂 To Read
└── 📂 Important
💡 Best Practice: Use collections for primary organization, tags for cross-cutting attributes (e.g., "to-read", "important", "review").
The v0.10.0 VSIX pins pubmed-search-mcp 0.7.7 at release commit 8247af2. Its MCP SDK v2 server exposes 41 tools across 16 categories (unchanged since 0.7.3). 0.7.4–0.7.7 add upstream rate-limit/cancellation hardening, one validated input contract for all tools with structured recoverable errors, and opt-in unified_search(fulltext="prefetch"). Earlier releases added fail-closed provider contracts, trials/native_semantic/systematic search modes, durable SearchRun status and replay through read_session, and richer Research Chronicle maps and Mermaid timelines. PubMed has a separate feature site.
You: "Find new anesthesia AI papers from 2024 that I don't have"
AI executes:
1. pubmed-search-mcp: unified_search("anesthesia AI", filters="year:2024-", output_format="json")
→ Found 30 candidate articles
2. zotero-keeper: check_articles_owned([...pmids...])
→ Detects which PMIDs already exist locally
3. zotero-keeper: import_articles(articles=selected_articles, collection_name="AI Research")
→ Imports the selected records into Zotero
You: Done! 25 new papers in Zotero
cd mcp-server
uv sync --extra pubmed
As of 2026-08-12, no Zotero-organization repository or Zotero documentation was found that publishes an official Zotero MCP server. 54yyyu/zotero-mcp is a capable community server listed in the MCP Registry, not an official Zotero server. An OpenAI-curated Zotero connector is likewise a separate connector product and should not be described as Zotero's official MCP server or assigned an invented tool schema.
The community server and Zotero Keeper both use the Python module/package name zotero_mcp. If you run both, install them in separate virtual environments and separate MCP processes; do not add the community package to the extension-managed environment. See the ecosystem comparison.
Zotero Local API reads and the Connector endpoints are local interfaces; Zotero 10+ Local API writes add runtime authorization, but the resulting key is unscoped. Port 23119 must therefore remain on loopback. Do not expose or forward it to a LAN or the Internet.
For remote libraries, use Zotero's authenticated HTTPS Web API, or place a purpose-built authenticated service in front of Zotero and apply TLS, authorization, and network access controls. Keep Zotero Keeper and Zotero Desktop on the same trusted host when using Local/Connector operations.
┌─────────────────────────────────────────────────┐
│ AI Agent (VS Code / Claude) │
└──────────────────────┬──────────────────────────┘
│ MCP Protocol
│ ├── Tools (50 default)
│ ├── Resources (6 + 4 URI templates)
│ └── Elicitation (interactive input)
▼
┌─────────────────────────────────────────────────┐
│ Zotero Keeper MCP Server │
│ ┌───────────────────────────────────────────┐ │
│ │ MCP Layer │ │
│ │ ├── server.py + basic reads (6 tools) │ │
│ │ ├── collection_tools.py (5 tools) │ │
│ │ ├── local_api_tools.py (17 guarded tools) │ │
│ │ ├── item_edit_tools.py (7 task tools) │ │
│ │ ├── resources.py (6 resources + 4 templates) │
│ │ ├── interactive_tools.py (2 save tools) │ │
│ │ ├── saved_search_tools.py (3 tools) │ │
│ │ ├── search_tools.py (2 default + 1 legacy) │ │
│ │ ├── unified_import_tools.py (2 tools) │ │
│ │ ├── analytics + attachment tools (4) │ │
│ │ ├── pubmed/batch legacy modules (4 tools) │ │
│ │ └── smart_tools.py (helpers only) │ │
│ └───────────────────────────────────────────┘ │
└──────────────────────┬──────────────────────────┘
│ HTTP (port 23119)
▼
┌─────────────────────────────────────────────────┐
│ Zotero Desktop Client │
│ ├── Local API (/api/...) → Read + authorized │
│ │ write (10+) │
│ └── Connector API (/connector/...) → Legacy │
│ create │
└─────────────────────────────────────────────────┘
Zotero 10+ changed the Local API substantially. The platform now supports authorized item, collection, and saved-search writes, tag deletion, full-text writes, and full file uploads. Keeper 2.4 exposes a deliberately constrained subset rather than handing an unscoped key and arbitrary API paths to an AI client.
| Interface | Scope | Authentication | Keeper 2.4 use |
|---|---|---|---|
Local API v3 /api/... | Same-machine library reads; Zotero 10+ writes | Reads are unauthenticated; writes require runtime user approval | Reads on Zotero 7–10+; guarded writes on 10+ |
Connector API /connector/... | Browser-connector save flows | Local interface | Backward-compatible create/import path, including Zotero 7–9 |
Web API v3 https://api.zotero.org | Remote and synchronized libraries | zotero.org key/OAuth | Recommended for remote access; not used by the local Keeper tools |
For Zotero 10+ writes, Keeper first obtains a response-bound
Zotero-Server-ID from discovery/read or runtime authorization. That identity
must already appear in the confirm=false proposal and every confirmed mutation
carries it as expected_server_id. update_item_fields additionally carries
the object version from the same exact-item response. Full-text replacement uses
the response-bound library cursor and bulk POST /api/users/0/fulltext with
If-Unmodified-Since-Version, not the attachment object version. If
authorization identifies another database, the read, preview, and approval must
all be repeated. A changed database or stale cursor returns 412 and is never
silently overwritten; missing identity/preconditions (428) and invalid
authorization (401) also fail closed.
Keeper 2.4 maps every My Library write family to explicit, task-oriented workflows while retaining safer cross-version Connector imports:
Arbitrary raw requests, unrestricted structural-array replacement, duplicate merging, annotation editing, batch object deletion, and group-library writes remain outside the public surface. See docs/ZOTERO_LOCAL_API.md for the complete platform matrix and Keeper's narrower safety contract.
| API | Execute Saved Search |
|---|---|
| Web API (api.zotero.org) | ❌ Can only read search metadata |
| Local API | ✅ Can execute and retrieve results! |
Recommended Saved Searches (create once, use forever):
| Name | Condition | AI Prompt |
|---|---|---|
| Missing PDF | Attachment File Type is not PDF | "Which papers have no PDF?" |
| Missing DOI | DOI is empty | "Which items lack DOI?" |
| Recent | Date Added in last 7 days | "What did I add this week?" |
| Unread | Tag is not "read" | "What haven't I read?" |
| Duplicates | Similar titles | "Potential duplicate items?" |
We support both developer-oriented and researcher-friendly entry points today, while keeping room for simpler packaging later.
| Path | Status | Best for |
|---|---|---|
| VS Code extension | ✅ Available now | Researchers who want guided setup inside VS Code |
Source checkout + uv sync | ✅ Available now | Contributors and local development |
Direct MCP registration via uvx zotero-keeper | ⚠️ Older PyPI line | Existing clients that intentionally accept the pre-2.0 package |
| Standalone executable | 🚧 Planned | Users who do not want to install Python/uv |
| Homebrew / Chocolatey | 🚧 Planned | OS-level package manager workflows |
💡 Want to help improve installation? See CONTRIBUTING.md.
curl http://127.0.0.1:23119/connector/pingZotero is runningcd mcp-server
uv sync --extra pubmed
Contributions welcome! See CONTRIBUTING.md.
Apache 2.0 - See LICENSE
update_saved_search | Rename or replace conditions on one saved search | Current object version + exact-key preflight |
delete_saved_search | Delete one exact saved search | Destructive confirmation + current object version |
delete_tags | Delete up to 50 exact tag names | Response-bound library cursor + one atomic request |
attach_file_to_item | Attach a local file to an existing item | Remembered authorization + validated loopback upload URL |
replace_attachment_file | Replace the bytes of an existing stored attachment | Remembered authorization + exact MD5/item-version preflight |
set_attachment_fulltext | Write indexed text for an attachment | Response-bound library cursor + Server-ID + explicit confirmation |
set_attachment_fulltexts | Write indexed text for up to 10 attachments | One response-bound library cursor + per-entry results |