https://github.com/u9401066/zotero-keeper
AI-powered research toolkit integrating PubMed search, Zotero management, and VS Code extension with OpenURL institutional access
https://github.com/u9401066/zotero-keeper
ai-research literature-search mcp pubmed reference-manager vscode-extension zotero
Last synced: 6 days ago
JSON representation
AI-powered research toolkit integrating PubMed search, Zotero management, and VS Code extension with OpenURL institutional access
- Host: GitHub
- URL: https://github.com/u9401066/zotero-keeper
- Owner: u9401066
- License: apache-2.0
- Created: 2025-12-12T03:14:02.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-03-04T07:00:53.000Z (about 2 months ago)
- Last Synced: 2026-03-04T13:08:06.929Z (about 2 months ago)
- Topics: ai-research, literature-search, mcp, pubmed, reference-manager, vscode-extension, zotero
- Language: Python
- Size: 1.02 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Codeowners: .github/CODEOWNERS
- Security: SECURITY.md
- Roadmap: ROADMAP.md
Awesome Lists containing this project
README
# Zotero Keeper ๐
Let AI manage your references! A MCP Server connecting VS Code Copilot / Claude Desktop to your local Zotero library.
[](https://www.python.org/downloads/)
[](https://github.com/modelcontextprotocol/python-sdk)
[](LICENSE)
[](https://www.zotero.org/)
[](https://github.com/u9401066/zotero-keeper/actions/workflows/ci.yml)
[](CONTRIBUTING.md)
> ๐ **English** | **[็น้ซไธญๆ](README.zh-TW.md)**
---
## ๐ One-Click Install (VS Code)
> **Prerequisites**: [Zotero 7 or 8](https://www.zotero.org/download/) must be running
> ๐ก **Requires [uv](https://docs.astral.sh/uv/getting-started/installation/)** - Click installs automatically via `uvx zotero-keeper`
---
## โจ What is this?
**Zotero Keeper** is a [MCP Server](https://modelcontextprotocol.io/) that lets your AI assistant:
- ๐ **Search references**: "Find papers about CRISPR from 2024"
- ๐ **View details**: "What's the abstract of this article?"
- โ **Add references**: "Add this DOI to my Zotero" (with auto-fetch metadata!)
- ๐ **PubMed integration**: "Search PubMed, skip what I already have"
- ๐ **Interactive save**: Shows collection options for you to choose!
No more manually searching, copying, pasting. Just tell your AI in natural language!
---
## โจ Features
- **๐ MCP Native**: Built with FastMCP SDK for seamless AI integration
- **๐ MCP Resources**: Browse Zotero data via URIs (`zotero://collections`, etc.)
- **๐ฌ MCP Elicitation**: Interactive collection selection with numbered options
- **๐ Auto-fetch Metadata**: DOI/PMID โ complete abstract + all fields automatically!
- **๐ Citation Metrics**: RCR and NIH Percentile stored in Zotero extra fields
- **๐ก๏ธ Collection Validation**: Use `collection_name` for safer auto-validation
- **๐ Read Operations**: Search, list, and retrieve items from local Zotero
- **โ๏ธ Write Operations**: Add references via Connector API
- **๐ง Smart Features**: Duplicate detection, validation, intelligent import
- **๐ Collection Support**: Nested collections (folders) with hierarchy
- **๐๏ธ Clean Architecture**: DDD with onion architecture
- **๐ No Cloud Required**: All operations are local
---
## ๐ Quick Start
### Prerequisites
- โ
[Python 3.12+](https://www.python.org/downloads/)
- โ
[Zotero 7 or 8](https://www.zotero.org/download/) (must be running)
- โ
[VS Code](https://code.visualstudio.com/) + GitHub Copilot, or [Claude Desktop](https://claude.ai/)
- โ
[uv](https://docs.astral.sh/uv/getting-started/installation/) (recommended)
### Installation
```bash
# 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
```
### Configure VS Code Copilot
Create `.vscode/mcp.json` in your workspace:
```json
{
"servers": {
"zotero-keeper": {
"type": "stdio",
"command": "uv",
"args": [
"run",
"--directory",
"/path/to/zotero-keeper/mcp-server",
"python", "-m", "zotero_mcp"
]
}
}
}
```
### Configure Claude Desktop
Add to `claude_desktop_config.json`:
```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](https://docs.astral.sh/uv/) is installed.
### Common Environment Variables
If you run the server directly, these are the main settings you may want to provide via `.env` or your MCP launcher configuration:
```bash
ZOTERO_HOST=localhost
ZOTERO_PORT=23119
ZOTERO_TIMEOUT=30
NCBI_EMAIL=your.email@example.com
# NCBI_API_KEY=your_api_key_here
# ZOTERO_KEEPER_ENABLE_LEGACY_PUBMED_TOOLS=1
# PUBMED_SEARCH_PATH=/path/to/pubmed-search-mcp
```
- Use `NCBI_EMAIL` and optional `NCBI_API_KEY` for higher NCBI/PubMed rate limits.
- Use `ZOTERO_KEEPER_ENABLE_LEGACY_PUBMED_TOOLS=1` only if you intentionally want keeper's older PubMed bridge/import tools.
- Use `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.
---
## ๐ Documentation Map
- [README.zh-TW.md](README.zh-TW.md) โ Traditional Chinese overview
- [mcp-server/README.md](mcp-server/README.md) โ focused server usage and tool reference
- [vscode-extension/README.md](vscode-extension/README.md) โ VS Code extension setup and UX
- [docs/COLLABORATION_WORKFLOW.md](docs/COLLABORATION_WORKFLOW.md) โ collaboration-safe flow between pubmed-search-mcp and keeper
- [docs/tools-reference.md](docs/tools-reference.md) โ parameter reference and examples for public tools
- [docs/faq.md](docs/faq.md) โ installation, troubleshooting, and workflow FAQ
- [docs/ZOTERO_LOCAL_API.md](docs/ZOTERO_LOCAL_API.md) โ Zotero API capability notes and limitations
- [ARCHITECTURE.md](ARCHITECTURE.md) โ component and layering overview
- [CONTRIBUTING.md](CONTRIBUTING.md) โ development workflow and contribution guide
---
## ๐ง Available Tools (23 default public + 5 legacy opt-in)
> ๐ก **Tip**: Most read operations can also be done via [MCP Resources](#-mcp-resources-browsable-data) without calling tools.
### ๐ Core Tools (server.py - 6 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?" |
### ๐ Collection Tools (server.py - 5 tools)
> โ ๏ธ 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) |
### โ๏ธ Save Tools (interactive_tools.py - 2 tools)
> ๐ **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" |
### ๐ Saved Search Tools (saved_search_tools.py - 3 tools)
| 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?" |
### ๐ Advanced Search & Ownership Check (search_tools.py - 2 public tools)
| 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?" |
### ๐ฅ Import Tools (single public handoff)
> ๐ค **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" |
#### Legacy PubMed bridge tools
`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.
### ๐ Analytics Tools (analytics_tools.py - 2 tools)
| 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?" |
### ๐ Attachment & Fulltext Tools (attachment_tools.py - 2 tools)
> ๐๏ธ **PDF Access**: List attached PDFs and read Zotero-indexed fulltext. Requires `ZOTERO_DATA_DIR` for file paths.
| 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" |
#### Recommended PubMed โ Zotero workflow
```python
# 1. Search with pubmed-search-mcp
results = unified_search("anesthesia AI", output_format="json")
# 2. Optional: filter against local Zotero
owned = check_articles_owned([article["pmid"] for article in results["articles"] if article.get("pmid")])
# 3. Import selected records into Zotero
import_articles(
articles=results["articles"],
collection_name="AI Research"
)
```
### ๐ค Collaboration-Safe Setup (Summary)
- pubmed-search-mcp runs search/discovery/export; zotero-keeper handles duplicate checks and the single `import_articles` handoff.
- Ensure pubmed-search-mcp is installed or the submodule is present; set `PUBMED_SEARCH_PATH` if you rely on a local checkout.
- Keep legacy PubMed bridge tools disabled unless you set `ZOTERO_KEEPER_ENABLE_LEGACY_PUBMED_TOOLS=1` intentionally.
- Full checklist: see `docs/COLLABORATION_WORKFLOW.md`.
#### advanced_search Examples
```python
# ๐ ไพๆ็ป้กๅๆๅฐ
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"
)
```
---
## ๐ MCP Resources (Browsable Data)
No tool calls needed! AI can directly browse Zotero data:
| Resource URI | Description |
|--------------|-------------|
| `zotero://collections` | All collections |
| `zotero://collections/tree` | Collection hierarchy |
| `zotero://collections/{key}` | Specific collection |
| `zotero://collections/{key}/items` | Items in collection |
| `zotero://items` | Recent items |
| `zotero://items/{key}` | Item details |
| `zotero://tags` | All tags |
| `zotero://searches` | Saved searches |
| `zotero://searches/{key}` | Search details |
| `zotero://schema/item-types` | Available item types |
---
## ๐ฏ Interactive Save (Recommended!)
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:
1. AI Research (match: 90%) - Title matches
2. Medical Imaging (match: 75%) - Keyword matches
๐ All Collections:
3. Biology (12 items)
4. Chemistry (8 items)
5. To Read (23 items)
0. Save to My Library (no collection)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Enter the number of your choice: [User enters: 1]
AI: โ
Saved to 'AI Research' collection!
```
### ๐ Data Integrity: Auto-fetch Metadata
When you provide a **DOI** or **PMID**, the tool automatically fetches complete metadata:
- **DOI** โ CrossRef API โ Full abstract, authors, journal, date
- **PMID** โ PubMed API โ Full abstract, MeSH terms, affiliations
No more missing abstracts! Just provide the identifier.
---
## ๐ Collection Organization
Zotero supports **nested collections**. Recommended strategies:
### By Topic (Recommended)
```
๐ 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").
---
## ๐ฌ PubMed Integration
Works seamlessly with [pubmed-search-mcp](https://github.com/u9401066/pubmed-search-mcp):
```
You: "Find new anesthesia AI papers from 2024 that I don't have"
AI executes:
1. pubmed-search-mcp: unified_search("anesthesia AI", min_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
```
### Install PubMed Integration
```bash
cd mcp-server
uv sync --extra pubmed
```
---
## ๐ Remote Zotero Setup
If Zotero runs on another computer:
### 1. On Zotero Machine (Windows)
```powershell
# Enable Local API (in Zotero โ Tools โ Developer โ Run JavaScript)
Zotero.Prefs.set("httpServer.localAPI.enabled", true)
# Open firewall
netsh advfirewall firewall add rule name="Zotero" dir=in action=allow protocol=TCP localport=23119
# Setup port proxy (Zotero only listens on 127.0.0.1)
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=23119 connectaddress=127.0.0.1 connectport=23119
```
### 2. Configure MCP Server
```json
{
"env": {
"ZOTERO_HOST": "192.168.1.100",
"ZOTERO_PORT": "23119"
}
}
```
---
## ๐๏ธ Architecture
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ AI Agent (VS Code / Claude) โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ MCP Protocol
โ โโโ Tools (22)
โ โโโ Resources (10 URIs)
โ โโโ Elicitation (interactive input)
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Zotero Keeper MCP Server โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ MCP Layer โ โ
โ โ โโโ server.py (11 tools: 6 core + 5 collection) โ
โ โ โโโ resources.py (10 URIs, incl. collections) โ
โ โโโ interactive_tools.py (2 save tools) โ โ
โ โ โโโ saved_search_tools.py (3 tools) โ โ
โ โ โโโ search_tools.py (3 tools) โ โ
โ โ โโโ pubmed_tools.py (2 tools) โ โ
โ โ โโโ batch_tools.py (1 tool) โ โ
โ โ โโโ smart_tools.py (helpers only) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ HTTP (port 23119)
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Zotero Desktop Client โ
โ โโโ Local API (/api/...) โ Read โ
โ โโโ Connector API (/connector/...) โ Write โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
---
## โ ๏ธ Zotero API Limitations (Important!)
### API Capability Matrix
Zotero provides **two local APIs**, but neither supports full CRUD:
| API | Endpoint | Read | Create | Update | Delete |
|-----|----------|:----:|:------:|:------:|:------:|
| **Local API** | `/api/...` | โ
| โ | โ | โ |
| **Connector API** | `/connector/...` | โ | โ
| โ | โ |
### ๐ Technical Details
**Local API** (port 23119):
- Designed for reading Zotero data (items, collections, tags)
- Per [official source code](https://github.com/zotero/zotero/blob/main/chrome/content/zotcom/server/server_localAPI.js#L28-L43): **"Write access is not yet supported."**
- DELETE/PATCH/PUT methods return `501 Not Implemented`
**Connector API** (port 23119):
- Designed for browser extensions to **save new items**
- `saveItems` endpoint: **Always creates NEW items, never updates**
- Even if you import the same PMID twice โ creates duplicate items
- No `updateItem` or `deleteItem` endpoints exist
### ๐ด Operations NOT Supported
| Operation | API Support | Technical Reason |
|-----------|-------------|------------------|
| โ **Delete items** | 501 Not Implemented | Local API is read-only |
| โ **Update items** | 501 Not Implemented | Local API is read-only |
| โ **Move items to collection** | Cannot modify | Connector API only creates, never updates |
| โ **Add tags to existing items** | Cannot modify | No update endpoint available |
| โ **Create collections** | 400 Bad Request | Connector API doesn't support it |
| โ **Delete collections** | 501 Not Implemented | Local API is read-only |
| โ **Merge duplicates** | No API | Must use Zotero GUI |
### ๐ก What This Means
**"Smart Management" Limitations:**
```
โ Cannot do:
- "Move these 10 papers to another collection"
- "Delete all duplicate references"
- "Help me organize my collections"
- "Archive old papers"
โ
Can do:
- "Add to specific collection when importing" (at creation time)
- "Search for matching references" (then handle manually)
- "List potential duplicates" (but manual deletion needed)
```
### ๐ ๏ธ Workarounds
| Need | Alternative |
|------|-------------|
| Organize collections | Drag & drop in Zotero GUI |
| Delete duplicates | Zotero โ Tools โ "Merge duplicates" |
| Batch operations | Use [Zotero Actions & Tags](https://github.com/windingwind/zotero-actions-tags) plugin |
| Auto-categorize | Use [Zutilo](https://github.com/wshanks/Zutilo) plugin |
### ๐ฎ Future Possibilities
Zotero team is working on **Local API write support**:
- [GitHub Issue #1320](https://github.com/zotero/zotero/issues/1320) - Request for write support
- Expected in future Zotero releases (8.x+)
**We'll update zotero-keeper as soon as Zotero supports it!**
---
### ๐ Local API Exclusive: Execute Saved Searches
| 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?" |
---
## ๐ฆ Installation & Distribution Paths
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` | โ
Available now | Existing MCP-capable clients |
| 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](CONTRIBUTING.md).
---
## ๐ค Troubleshooting
### Can't connect to Zotero?
1. Make sure Zotero is running
2. Test: `curl http://127.0.0.1:23119/connector/ping`
3. Should return: `Zotero is running`
### MCP Server not found?
1. Use absolute paths
2. Check Python environment
3. Restart VS Code / Claude Desktop
### PubMed features missing?
```bash
cd mcp-server
uv sync --extra pubmed
```
---
## ๐ Resources
- [CHANGELOG](CHANGELOG.md) - Release notes
- [ARCHITECTURE](ARCHITECTURE.md) - Technical architecture
- [CONTRIBUTING](CONTRIBUTING.md) - How to contribute
- [ROADMAP](ROADMAP.md) - Development roadmap
- [docs/tools-reference.md](docs/tools-reference.md) - Full MCP tools parameter reference
- [docs/faq.md](docs/faq.md) - Frequently asked questions
- [pubmed-search-mcp](https://github.com/u9401066/pubmed-search-mcp) - PubMed search (Apache 2.0)
---
## ๐ค Contributing
Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md).
- ๐ [Report Bugs](https://github.com/u9401066/zotero-keeper/issues)
- ๐ก [Request Features](https://github.com/u9401066/zotero-keeper/issues)
- ๐ง [Submit PRs](https://github.com/u9401066/zotero-keeper/pulls)
---
## ๐ License
Apache 2.0 - See [LICENSE](LICENSE)
---
Made with โค๏ธ for researchers
Let AI manage your references, focus on your research!