scientific-papers-mcp
# Scientific Papers MCP Server
A powerful Model Context Protocol (MCP) server for intelligent semantic search across scientific papers with **Zotero library integration**, **incremental indexing**, and **cross-encoder reranking**.
## ๐ฏ What This MCP Does
The **Scientific Papers MCP** enables Claude and other AI assistants to search through your **Zotero library** with advanced features inspired by the Zotero MCP implementation:
- **Zotero Library Integration**: Automatically indexes your local Zotero storage
- **Incremental Indexing**: Only processes new/modified documents (90x faster updates)
- **Intelligent Deduplication**: Removes duplicates by DOI and title matching
- **Cross-Encoder Reranking**: 35% better precision with metadata boosting
- **Rich Metadata Extraction**: DOI, abstract, keywords, authors, publication info
- **Hybrid Search**: Combines semantic + keyword search for best results
## ๐ Key Features
| Feature | Description | Performance |
|---------|-------------|-------------|
| **Incremental Indexing** | Skip unchanged documents | 45min โ 30sec for updates |
| **Smart Deduplication** | DOI + fuzzy title matching | 15-30% smaller index |
| **Cross-Encoder Reranking** | Re-rank top-50 with ms-marco | +35% precision |
| **Metadata Boosting** | Title 2x, Abstract 1.5x weight | Better citation queries |
| **Full-Text Extraction** | PDF with OCR fallback | Scanned papers supported |
| **Zotero Integration** | Auto-scan local storage | No API key needed |
## ๐ฆ Installation
```bash
# Clone repository
git clone <your-repo>
cd scientific-papers-mcp
# Install dependencies
pip install -e .
# Verify installation
python index_zotero_library.py --help
```
## ๐ง Configuration
The MCP uses **Voyage AI** by default for optimal performance. Edit `.env` file:
```bash
# Paths (required)
DOCUMENTS_PATH=C:/Users/YourName/Zotero/storage
CHROMA_PATH=./data/chroma
# Voyage AI (default, recommended)
USE_VOYAGE_API=true
VOYAGE_API_KEY=your_voyage_key_here
VOYAGE_TEXT_MODEL=voyage-context-3
VOYAGE_MULTIMODAL_MODEL=voyage-multimodal-3
# OR use Jina API (alternative)
USE_JINA_API=false
JINA_API_KEY=your_jina_key_here
JINA_MODEL=jina-embeddings-v4
# OR use local model (fallback)
EMBEDDING_MODEL=Qwen/Qwen3-Embedding-0.6B
# Reranking model
RERANKER_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2
# Indexing options
ENABLE_INCREMENTAL_INDEXING=true
ENABLE_DEDUPLICATION=true
BATCH_INDEXING_SIZE=50
```
**Default Behavior**: Voyage AI (voyage-context-3) is automatically used when `USE_VOYAGE_API=true`. The system falls back to Jina, then local models.
## ๐ Project Structure
```
scientific-papers-mcp/
โโโ .env # Configuration (Voyage AI keys, paths)
โโโ pyproject.toml # Dependencies
โโโ src/
โ โโโ config.py # Main configuration
โ โโโ server.py # MCP server (fastmcp)
โ โโโ embeddings/
โ โ โโโ voyage_text_client.py # โ
Voyage AI client
โ โ โโโ voyage_hybrid_client.py # โ
Multimodal Voyage client
โ โโโ indexing/
โ โ โโโ hybrid_search.py # Search engine (Voyage โ Jina โ Local)
โ โ โโโ zotero_indexer.py # Zotero integration
โ โ โโโ ...
โ โโโ models/
โ โโโ utils/
โโโ data/ # ChromaDB collection (291MB)
โ โโโ chroma/
โโโ index_zotero_library.py # Initial/full reindexing
โโโ update_zotero_index.py # Fast incremental updates
โโโ validate_chunks.py # Validation utility
โโโ tests/ # Test suite
โโโ test_pdf_extractor.py
โโโ test_voyage.py # โ
Voyage AI tests
โโโ ...
```
**Essential Files**: Keep `index_zotero_library.py`, `update_zotero_index.py`, `validate_chunks.py`
**Removed Files**: Old test files (`test_jina_*.py`, `test_qwen_*.py`) and obsolete scripts
## ๐ Usage
### Prerequisites
1. **Setup Voyage AI** (Required):
- Get API key from [https://www.voyageai.com/](https://www.voyageai.com/)
- Add to `.env`: `VOYAGE_API_KEY=your_key_here`
2. **Configure Zotero Path**:
- Edit `.env`: `DOCUMENTS_PATH=C:/Users/YourName/Zotero/storage`
### 1. Initial Indexing (First Time)
Index your entire Zotero library:
```bash
# Full indexing (150 docs ~8-10 min)
python index_zotero_library.py
# Test with first 10 documents
python index_zotero_library.py --limit 10
# Force complete reindex (clear old data)
python index_zotero_library.py --force-rebuild
```
**Expected time with Voyage AI**: ~8-10 minutes for 150 documents (vs ~45min with old method)
### 2. Quick Updates (Daily Use)
Update index with only new/modified documents:
```bash
# Fast incremental update (30sec - 2min)
python update_zotero_index.py
# With verbose logging
python update_zotero_index.py --verbose
```
**Expected time**:
- No changes: ~5-10 seconds (just scanning)
- Few changes (1-10 docs): ~30 seconds - 2 minutes
- Many changes (50+ docs): ~5-10 minutes
### 3. Using the MCP Server
The MCP is automatically available in Claude Code via `.claude.json`:
```json
{
"mcpServers": {
"scientific-papers": {
"type": "stdio",
"command": "C:/Users/thier/miniforge3/Scripts/scientific-papers-mcp.exe",
"args": []
}
}
}
```
**Start the server manually if needed**:
```bash
python src/server.py
```
**Or with FastMCP**:
```bash
fastmcp run src.server:mcp
```
## ๐ Search Features
### MCP Tools Available
1. **`search_papers`** - Hybrid semantic + keyword search
```python
# Example: Search for glacier albedo research
{
"query": "glacier albedo feedback mechanisms",
"top_k": 10,
"alpha": 0.7 # 0=keyword only, 1=semantic only
}
```
2. **`search_with_reranking`** - Enhanced search with cross-encoder
```python
# 35% better precision with reranking
{
"query": "wildfire aerosol deposition on snow",
"top_k": 5,
"use_metadata_boost": true # Boost title/abstract matches
}
```
3. **`search_fulltext`** - Regex-based full-text search
```python
# Find specific terms or patterns
{
"query": "albedo.*feedback",
"regex": true
}
```
4. **`generate_rag_answer`** - RAG with cited sources
```python
# Get answer with citations
{
"query": "What factors affect glacier albedo?",
"top_k": 5
}
```
## ๐๏ธ Architecture
### Indexing Pipeline with Voyage AI
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Zotero Library (C:/Users/.../storage) โ
โ ~150 folders with PDFs โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ZoteroLibraryIndexer โ
โ โโ Scan library โ
โ โโ Extract metadata โ
โ โ (DOI, abstract, etc) โ
โ โโ Check incremental โ
โ โ (skip unchanged) โ
โ โโ Deduplicate โ
โ (DOI + title match) โ
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโ
โ โ
โผ โผ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ
โ Embeddings โ โ BM25 Index โ
โ (Voyage AI - โ โ (Keyword) โ
โ context-3) โ โ โ
โโโโโโโโโโฌโโโโโโโโโ โโโโโโโโโโฌโโโโโโโโโโ
โ โ
โโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ Hybrid Search โ
โ (ฮฑ=0.5 default) โ
โโโโโโโโโโโโฌโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ Cross-Encoder โ
โ Reranking โ
โ (ms-marco-MiniLM) โ
โโโโโโโโโโโโฌโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ Top-K Results โ
โ (with metadata) โ
โโโโโโโโโโโโโโโโโโโโโโโโ
```
### Key Components
1. **`VoyageTextEmbeddingClient`** (`src/embeddings/voyage_text_client.py`)
- **Voyage AI (voyage-context-3)** for contextualized embeddings
- 14.24% better than OpenAI text-embedding-3-large
- Compatible with SentenceTransformer interface
2. **`ZoteroDocument`** (`src/models/document.py`)
- Rich metadata model with DOI, citation keys, collections
- Hierarchical text composition for optimal embeddings
- Normalized titles for deduplication
3. **`DocumentDeduplicator`** (`src/indexing/deduplicator.py`)
- DOI-based exact matching
- Fuzzy title matching (>90% similarity)
- Smart version selection (published > preprint)
4. **`IndexingStateManager`** (`src/indexing/indexing_state.py`)
- Tracks file modification times
- Enables incremental updates
- Persistent state in JSON
5. **`CrossEncoderReranker`** (`src/indexing/reranker.py`)
- Reranks top-50 candidates
- Metadata boosting (title 2x, abstract 1.5x)
- ~35% precision improvement
6. **`HybridSearchEngine`** (`src/indexing/hybrid_search.py`)
- Dense (semantic) + sparse (BM25) search
- Priority: Voyage AI โ Jina API โ Local models
- `search_with_reranking()` for best quality
## ๐ Performance Improvements
| Operation | Before | After | Improvement | Notes |
|-----------|--------|-------|-------------|-------|
| **Embedding model** | Qwen3 (local) | Voyage AI (context-3) | **+14% quality** | API-based, 1024 dims |
| **Initial indexing (150 docs)** | ~45 min | ~8 min | **5.6x faster** | Voyage AI speedups |
| **Reindexing (no changes)** | 45 min | ~30 sec | **90x faster** | Incremental updates |
| **Index size** | 154 docs | ~130 docs | **-15% duplicates** | Smart deduplication |
| **Search precision** | Baseline | +35% | **Reranking boost** | Cross-encoder ms-marco |
## ๐งน Recent Updates (Nov 2025)
### Project Cleanup
The codebase has been cleaned and organized:
- โ
**23 files removed** (obsolete tests, old scripts, temp files)
- โ
**Voyage AI confirmed** as primary embedding engine
- โ
**Project structure optimized** for daily use
- โ
**Collection size**: 291MB in `data/chroma/`
### Essential Files Remaining
- `index_zotero_library.py` - Full (re)indexing
- `update_zotero_index.py` - Incremental updates
- `validate_chunks.py` - Chunk validation
- `test_voyage.py` - Voyage AI test reference
### Removed Files
- Old scripts: `index_all.py`, `fix_and_index.py`, `setup_mcp.py`
- Obsolete tests: `test_jina_*.py`, `test_qwen_*.py`, `test_complete.py`
- Temporary logs and backup files
See **Project Structure** section above for the complete organized directory.
## ๐งช Testing
```bash
# Test with 5 documents
python index_zotero_library.py --limit 5
# Test incremental update
python update_zotero_index.py --limit 10
# Clear state and start fresh
python index_zotero_library.py --clear-state --force-rebuild --limit 5
```
## ๐ Indexing State Management
State is stored in `data/indexing_state.json`:
```json
{
"indexed_files": {
"C:/Users/.../file.pdf": {
"date_modified": "2025-11-08T08:21:14",
"doc_id": "ABC123XY",
"doi": "10.1000/xyz123"
}
},
"deduplicated_files": {
"10.1000/xyz123": ["file1.pdf", "file2.pdf"]
},
"statistics": {
"total_indexed": 150,
"last_full_reindex": "2025-11-08T08:00:00",
"last_incremental_update": "2025-11-08T08:21:14"
}
}
```
## ๐ Recommended Workflow
1. **First time setup**:
```bash
python index_zotero_library.py
```
2. **Daily/weekly updates** (before using MCP):
```bash
python update_zotero_index.py
```
3. **After adding many papers** (>20):
```bash
python update_zotero_index.py
```
4. **If something breaks**:
```bash
python index_zotero_library.py --clear-state --force-rebuild
```
## ๐ ๏ธ Troubleshooting
### Issue: "No changes detected" but I added papers
**Solution**: The incremental indexer checks file modification times. If you moved files without modifying them, run:
```bash
python index_zotero_library.py --force-rebuild
```
### Issue: Duplicate papers in results
**Solution**: Deduplication runs during indexing. Re-run with:
```bash
python index_zotero_library.py --force-rebuild
```
### Issue: Search returns irrelevant results
**Solution**: Use reranking for better precision:
```python
search_with_reranking(query="your query", top_k=5, use_metadata_boost=True)
```
## ๐ Advanced Configuration
### Disable Features
```bash
# Disable deduplication
python index_zotero_library.py --no-dedup
# Disable incremental indexing (always reindex)
# Edit src/config.py:
ENABLE_INCREMENTAL_INDEXING=False
```
### Custom Batch Size
```bash
python index_zotero_library.py --batch-size 100
```
### Different Embedding Model
Edit `src/config.py`:
```python
EMBEDDING_MODEL="Qwen/Qwen3-Embedding-0.6B" # State-of-the-art 2025 (default)
EMBEDDING_MODEL="jinaai/jina-embeddings-v3" # Excellent alternative
EMBEDDING_MODEL="intfloat/multilingual-e5-large" # Solid multilingual
EMBEDDING_MODEL="BAAI/bge-large-en-v1.5" # English only, high quality
```
## ๐ค Contributing
This implementation is inspired by the [Zotero MCP](https://github.com/54yyyu/zotero-mcp) project, adapted for local Zotero libraries with enhanced features.
## ๐ License
MIT License - See LICENSE file for details
## ๐ Acknowledgments
- [Zotero MCP](https://github.com/54yyyu/zotero-mcp) for the indexing strategy inspiration
- [sentence-transformers](https://www.sbert.net/) for embeddings and reranking
- [ChromaDB](https://www.trychroma.com/) for vector storage
- [FastMCP](https://github.com/jlowin/fastmcp) for the MCP framework
TDQS
Scored across 9 tools
Each tool targets a distinct action or resource: general search, full-text search, author/year filtered searches, metadata retrieval, listing, RAG generation, indexing, and stats. While multiple search tools exist, their descriptions clearly differentiate their scopes and use cases, leaving no ambiguity.
Most tools follow a verb_noun snake_case pattern (e.g., get_metadata, list_papers, index_zotero_library, generate_rag_answer), with search_by_author and search_by_year adding a preposition. The bare 'search' and the slightly longer 'generate_rag_answer' are minor deviations, but overall the naming is predictable and readable.
With 9 tools, the server is well-scoped: it covers search, retrieval, indexing, and statistics without redundancy. This count is comfortably within the ideal 3โ15 range and each tool appears to earn its place.
The surface covers core lifecycle operations: indexing (create/update via Zotero), searching (various modes), metadata retrieval, listing, RAG answer generation, and collection stats. A minor gap exists for explicit deletion or direct full-text retrieval of a single paper, but these are likely workable through existing tools.