zotero-mcp-code について
Python のコード実行を通じて Zotero ライブラリを検索するスキルです。セマンティック検索、キーワード検索、タグ検索を組み合わせ、コード内で重複排除・順位付け・絞り込みを行い、選んだ項目だけを LLM のコンテキストに渡します。
主な機能
- 01セマンティック・キーワード・タグ検索の併用
- 02結果の重複排除と順位付け
- 03種類・日付・タグによる絞り込み
- 04著者と最近の項目の検索
- 05抄録付き検索結果の整形
活用シーン
- 01異なる綴りで文献を検索
- 02著者の最近の論文を検索
- 03日付や項目の種類で結果を絞り込む
- 04コンテキストを抑えて大規模ライブラリを検索
MCP 対応
このスキルは Zotero の検索に MCP の直接呼び出しではなく、コード実行を使います。大量の検索結果をコード内で処理し、選んだ結果だけをコンテキストに渡す方法を説明しています。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ kerim/ zotero-code-execution --skill zotero-mcp-codeインストール後、Claude Code で/zotero-mcp-codeを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
QUICK_START.mdHONEST_STATUS.mdDEPLOYMENT_SUMMARY.mdLICENSEIMPLEMENTATION_SUMMARY.mdREADME.md.gitignoreREADME_LIBRARY.mdCLAUDE_INSTRUCTIONS.mdCLAUDE.mdsetup.pysetup_paths.pyexamples.pyzotero_lib.pytest_basic.pytest_real_performance.pyrequirements.txtskill/README.md詳細
Zotero MCP コード実行スキル
コード実行を使って、Zotero ライブラリを安全かつ効率的に、漏れなく検索します。
🎯 基本概念
MCP ツールを直接呼び出すと(すべての結果がコンテキストに読み込まれ、クラッシュする危険があるため)、Python コードを記述して次の処理を行います。
- 大規模なデータセットを取得します(各検索方式で50~100件以上)
- コード実行環境でフィルタリングとランキングを行います
- 上位 N 件の結果のみをコンテキストに返します
利点:
- ✅ クラッシュのリスクがありません(大量のデータはコード内に保持されます)
- ✅ 複数の検索方式を自動で実行します
- ✅ 重複を自動で除外します
- ✅ 自動でランキングします
- ✅ 5~10回ではなく、1回の関数呼び出しで済みます
⚠️ 重要な注意事項
複数語での検索
Zotero では、複数語のクエリは AND 条件として扱われます!
❌ 誤り: comprehensive_search("Atyal Atayal 泰雅族") → すべての語が必要なため、結果は0件です
✅ 正しい方法: 各語を個別に検索して結果を統合します(下記のパターン6を参照)
複数語の OR 検索を使うケース:
- 複数の綴り(Atayal、Atyal)
- 複数の言語(Atayal、泰雅族)
- 同義語(skill transfer、transfer of learning)
セマンティック検索の状況
セマンティック検索は現在、正しく動作しています(2025-01-08に修正)。ただし、セマンティック検索エンジン自体の出力に404エラーメッセージが表示されることがあります。これらは無視してかまいません。ラッパーが正しく処理します。
🚀 基本的な使い方
**Zotero の検索の90%**では、次のシンプルなパターンを使います。
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import SearchOrchestrator, format_results
# Single comprehensive search
orchestrator = SearchOrchestrator()
results = orchestrator.comprehensive_search(
"user's query here",
max_results=20, # Return top 20 most relevant
use_semantic=True # Semantic search now works correctly
)
# Format and display
print(format_results(results, include_abstracts=True))
次の処理が自動で行われます:
- セマンティック検索(ベクトル類似度)を実行します
- キーワード検索(qmode="everything" と "titleCreatorYear")を実行します
- タグベースの検索を実行します
- 合計100件以上のアイテムを取得します
- 結果の重複を除外します
- 関連度順にランキングします
- 上位20件のみをコンテキストに返します
📋 よくあるパターン
パターン1:シンプルな検索(最も一般的)
ユーザーの依頼:「身体化された認知に関する論文を探してください」
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import SearchOrchestrator, format_results
orchestrator = SearchOrchestrator()
results = orchestrator.comprehensive_search("embodied cognition", max_results=20)
print(format_results(results))
パターン2:絞り込み検索
ユーザーの依頼:「機械学習に関する最近の学術誌論文を探してください」
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import ZoteroLibrary, SearchOrchestrator, format_results
library = ZoteroLibrary()
orchestrator = SearchOrchestrator(library)
# Fetch broadly (safe - filtering happens in code)
items = library.search_items("machine learning", limit=100)
# Filter in code
filtered = orchestrator.filter_by_criteria(
items,
item_types=["journalArticle"],
date_range=(2020, 2025)
)
print(format_results(filtered[:15]))
パターン3:著者の検索
ユーザーの依頼:「Kahneman の論文を持っていますか?」
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import ZoteroLibrary, format_results
library = ZoteroLibrary()
results = library.search_items(
"Kahneman",
qmode="titleCreatorYear",
limit=50
)
# Sort by date
sorted_results = sorted(results, key=lambda x: x.date, reverse=True)
print(format_results(sorted_results))
パターン4:タグベースの検索
ユーザーの依頼:「「learning」と「cognition」のタグが付いた論文を表示してください」
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import ZoteroLibrary, format_results
library = ZoteroLibrary()
results = library.search_by_tag(["learning", "cognition"], limit=50)
print(format_results(results[:20]))
パターン5:最近の論文
ユーザーの依頼:「最近追加したものは何ですか?」
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import ZoteroLibrary, format_results
library = ZoteroLibrary()
results = library.get_recent(limit=20)
print(format_results(results))
パターン6:複数語の OR 検索(複数の綴り・言語)
ユーザーの依頼:「Atyal または泰雅族に関する論文を探してください」(別の綴り・言語)
重要: Zotero では、複数語のクエリは AND 条件として扱われます。OR 検索をするには、各語を個別に検索して結果を統合します。
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import SearchOrchestrator, format_results
orchestrator = SearchOrchestrator()
# Search each term separately
all_results = {}
for term in ['Atayal', '泰雅族']:
results = orchestrator.comprehensive_search(term, max_results=50, use_semantic=True)
for item in results:
all_results[item.key] = item # Deduplicate by key
# Re-rank combined results
ranked = orchestrator._rank_items(list(all_results.values()), 'Atayal 泰雅族')
# Optional: Filter for specific content
filtered = [item for item in ranked
if any(term in (item.title + item.abstract).lower()
for term in ['atyal', 'atayal', '泰雅'])]
print(format_results(filtered[:25], include_abstracts=True))
パターン7:複数トピックの AND 検索
ユーザーの依頼:「認知と学習の両方に関する論文を探してください」
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import SearchOrchestrator, format_results
orchestrator = SearchOrchestrator()
# Search both topics
results1 = orchestrator.comprehensive_search("cognition", max_results=30)
results2 = orchestrator.comprehensive_search("learning", max_results=30)
# Find intersection
keys1 = {item.key for item in results1}
keys2 = {item.key for item in results2}
common_keys = keys1 & keys2
if common_keys:
common_items = [item for item in results1 if item.key in common_keys]
print("Papers about both topics:")
print(format_results(common_items))
else:
print("No papers found on both topics.")
print("\nCognition results:")
print(format_results(results1[:10]))
print("\nLearning results:")
print(format_results(results2[:10]))
🔧 応用的な使い方
カスタムのフィルタリングロジック
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import ZoteroLibrary, SearchOrchestrator, format_results
library = ZoteroLibrary()
orchestrator = SearchOrchestrator(library)
# Fetch large dataset
items = library.search_items("neural networks", limit=100)
# Custom filtering
recent_with_doi = [
item for item in items
if item.doi and item.date and int(item.date[:4]) >= 2020
]
print(format_results(recent_with_doi[:15]))
複数の観点からのカスタム検索
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import ZoteroLibrary, SearchOrchestrator, format_results
library = ZoteroLibrary()
orchestrator = SearchOrchestrator(library)
all_results = set()
# Multiple search angles
queries = [
"skill transfer",
"transfer of learning",
"generalization of skills"
]
for query in queries:
results = library.search_items(query, limit=30)
all_results.update(results)
# Rank combined results
ranked = orchestrator._rank_items(list(all_results), "skill transfer")
print(format_results(ranked[:20]))
反復的な絞り込み
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import ZoteroLibrary, SearchOrchestrator, format_results
library = ZoteroLibrary()
orchestrator = SearchOrchestrator(library)
# Initial search
initial = library.search_items("memory", limit=50)
# Analyze tags
tag_freq = {}
for item in initial:
for tag in item.tags:
tag_freq[tag] = tag_freq.get(tag, 0) + 1
# Find most common tag
if tag_freq:
most_common_tag = max(tag_freq, key=tag_freq.get)
# Refine search
refined = orchestrator.filter_by_criteria(
initial,
required_tags=[most_common_tag]
)
print(f"Papers with most common tag '{most_common_tag}':")
print(format_results(refined))
📚 API リファレンス
SearchOrchestrator
検索を自動化するためのメインクラスです。
comprehensive_search(query, max_results=20, use_semantic=True, use_keyword=True, use_tags=True, search_limit_per_strategy=50)
複数の検索方式で検索し、重複の除外とランキングを自動で行います。
パラメーター:
query(str):検索クエリmax_results(int):返す結果の最大数(デフォルト:20)use_semantic(bool):セマンティック検索を使います(デフォルト:True)use_keyword(bool):キーワード検索を使います(デフォルト:True)use_tags(bool):タグ検索を使います(デフォルト:True)search_limit_per_strategy(int):検索方式ごとに取得するアイテム数(デフォルト:50)
戻り値: ZoteroItem オブジェクトのリスト
filter_by_criteria(items, item_types=None, date_range=None, required_tags=None, excluded_tags=None)
さまざまな条件でアイテムをフィルタリングします。
パラメーター:
items(list):フィルタリングするアイテムitem_types(list):許可するアイテムタイプ(例:["journalArticle"])date_range(tuple):(最小年、最大年)required_tags(list):含まれている必要があるタグexcluded_tags(list):含まれていてはならないタグ
戻り値: フィルタリング済みの ZoteroItem オブジェクトのリスト
ZoteroLibrary
Zotero への低レベルインターフェースです。
search_items(query, qmode="titleCreatorYear", item_type="-attachment", limit=100, tag=None)
基本的なキーワード検索です。
semantic_search(query, limit=100, search_type="hybrid")
セマンティック検索/ベクトル検索です。
search_by_tag(tags, item_type="-attachment", limit=100)
タグで検索します。
get_recent(limit=50)
最近追加されたアイテムを取得します。
get_tags()
ライブラリ内のすべてのタグを取得します。
format_results(items, include_abstracts=True, max_abstract_length=300)
アイテムを Markdown 形式に整形します。
⚙️ 設定
デフォルトパラメーター
ほとんどの検索に適したデフォルト値です。
orchestrator.comprehensive_search(
query,
max_results=20, # Top 20 results
search_limit_per_strategy=50 # Fetch 50 per strategy
)
検索の深さを調整する
簡易検索(結果が少なく、処理が速い)の場合:
results = orchestrator.comprehensive_search(
query,
max_results=10,
search_limit_per_strategy=20
)
詳細検索(より包括的)の場合:
results = orchestrator.comprehensive_search(
query,
max_results=30,
search_limit_per_strategy=100
)
🔍 仕組み
内部処理
comprehensive_search("embodied cognition", max_results=20) を呼び出すと:
-
セマンティック検索(有効な場合):
- 「embodied cognition」を検索(ハイブリッドモード)→ 50 件のアイテム
- 「embodied cognition」を検索(ベクトルモード)→ 50 件のアイテム
-
キーワード検索(有効な場合):
- qmode="everything" で検索 → 50 件のアイテム
- qmode="titleCreatorYear" で検索 → 50 件のアイテム
-
タグ検索(有効な場合):
- クエリから単語を抽出
- ライブラリ内で一致するタグを検索
- 一致するタグで検索 → 50 件のアイテム
-
処理:
- すべての結果を統合(約 250 件)
- アイテムキーを使って重複を除去(約 120 件の一意なアイテム)
- 関連度スコアで順位付け
- 上位 20 件を返す
-
コンテキスト:
- 最終的な 20 件のアイテムのみが LLM のコンテキストに渡されます
- すべての処理はコード実行環境で行われます
これが優れている理由
以前の方法(MCP を直接呼び出す場合):
# 5+ function calls, all results to context
results1 = zotero_semantic_search("query", limit=10) # Crash risk if > 15
results2 = zotero_search_items("query", limit=10)
# ... manual deduplication, no ranking
# All items (50+) load into context
新しい方法(コード実行を使用する場合):
# 1 function call, only top results to context
results = orchestrator.comprehensive_search("query", max_results=20)
# Fetches 250+ items, processes in code, returns top 20
🛠️ エラー処理
発生する可能性のあるエラーは、必ず処理してください。
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import SearchOrchestrator, format_results
orchestrator = SearchOrchestrator()
try:
results = orchestrator.comprehensive_search("query", max_results=20)
if results:
print(format_results(results))
else:
print("No results found. Try a broader search term.")
except Exception as e:
print(f"Search failed: {e}")
print("Please check your Zotero MCP configuration.")
📖 例
8 つの完全な動作例については、/Users/niyaro/Documents/Code/zotero-code-execution/examples.py を参照してください。
🎓 クイックリファレンス
| タスク | コード |
|---|---|
| 基本検索 | orchestrator.comprehensive_search(query, max_results=20) |
| 種類で絞り込む | orchestrator.filter_by_criteria(items, item_types=["journalArticle"]) |
| 日付で絞り込む | orchestrator.filter_by_criteria(items, date_range=(2020, 2025)) |
| 著者を検索 | library.search_items(author, qmode="titleCreatorYear", limit=50) |
| タグで検索 | library.search_by_tag([tags], limit=50) |
| 最近のアイテム | library.get_recent(limit=20) |
| 出力を整形 | format_results(items, include_abstracts=True) |
💡 ヒント
- シンプルに始める:ほとんどのクエリでは
comprehensive_search()を使用します - 深さを調整する:
search_limit_per_strategyを使って検索の詳細度を調整します - 検索後に絞り込む:広く取得してから、コード内で絞り込みます
- 独自のロジック:複雑な絞り込みには Python を使用します
- エラーを確認する:必ず try/except で囲みます
📁 ドキュメント
- クイックスタート:
/Users/niyaro/Documents/Code/zotero-code-execution/QUICK_START.md - 完全なドキュメント:
/Users/niyaro/Documents/Code/zotero-code-execution/README.md - 例:
/Users/niyaro/Documents/Code/zotero-code-execution/examples.py - ステータス:
/Users/niyaro/Documents/Code/zotero-code-execution/HONEST_STATUS.md
⚠️ 重要な注意事項
- これはコード実行を使用し、MCP を直接呼び出すものではありません
- 大規模なデータセットはコード内で処理されるため、コンテキストを小さく保てます
- セマンティック検索を利用できない場合があります(その場合はキーワード検索に切り替わります)
- 結果は自動的に重複が除去され、順位付けされます
- 絞り込みはコード内で行われるため、大きな上限値(100 以上)を安全に使用できます
🔄 zotero-mcp からの移行
以前のパターン:
# Multiple manual MCP calls
results1 = zotero_semantic_search("query", limit=10)
results2 = zotero_search_items("query", limit=10)
# Manual deduplication...
新しいパターン:
# One function call with code execution
import sys
sys.path.append('/Users/niyaro/Documents/Code/zotero-code-execution')
import setup_paths
from zotero_lib import SearchOrchestrator, format_results
orchestrator = SearchOrchestrator()
results = orchestrator.comprehensive_search("query", max_results=20)
print(format_results(results))
重要: このスキルは、大規模な検索を安全に処理するためにコード実行を使用します。実装は /Users/niyaro/Documents/Code/zotero-code-execution/ にあります。