mcpField
Z
zotero-mcp-code

zotero-mcp-code

github.com/kerim生産性6284 回インストール40 週間前に更新
リポジトリ

zotero-mcp-code について

Python のコード実行を通じて Zotero ライブラリを検索するスキルです。セマンティック検索、キーワード検索、タグ検索を組み合わせ、コード内で重複排除・順位付け・絞り込みを行い、選んだ項目だけを LLM のコンテキストに渡します。

主な機能

  1. 01セマンティック・キーワード・タグ検索の併用
  2. 02結果の重複排除と順位付け
  3. 03種類・日付・タグによる絞り込み
  4. 04著者と最近の項目の検索
  5. 05抄録付き検索結果の整形

活用シーン

  1. 01異なる綴りで文献を検索
  2. 02著者の最近の論文を検索
  3. 03日付や項目の種類で結果を絞り込む
  4. 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.md
HONEST_STATUS.md
DEPLOYMENT_SUMMARY.md
LICENSE
IMPLEMENTATION_SUMMARY.md
README.md
.gitignore
README_LIBRARY.md
CLAUDE_INSTRUCTIONS.md
CLAUDE.md
setup.py
setup_paths.py
examples.py
zotero_lib.py
test_basic.py
test_real_performance.py
requirements.txt
skill/
README.md

詳細

Zotero MCP コード実行スキル

コード実行を使って、Zotero ライブラリを安全かつ効率的に、漏れなく検索します。

🎯 基本概念

MCP ツールを直接呼び出すと(すべての結果がコンテキストに読み込まれ、クラッシュする危険があるため)、Python コードを記述して次の処理を行います。

  1. 大規模なデータセットを取得します(各検索方式で50~100件以上)
  2. コード実行環境でフィルタリングとランキングを行います
  3. 上位 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) を呼び出すと:

  1. セマンティック検索(有効な場合):

    • 「embodied cognition」を検索(ハイブリッドモード)→ 50 件のアイテム
    • 「embodied cognition」を検索(ベクトルモード)→ 50 件のアイテム
  2. キーワード検索(有効な場合):

    • qmode="everything" で検索 → 50 件のアイテム
    • qmode="titleCreatorYear" で検索 → 50 件のアイテム
  3. タグ検索(有効な場合):

    • クエリから単語を抽出
    • ライブラリ内で一致するタグを検索
    • 一致するタグで検索 → 50 件のアイテム
  4. 処理:

    • すべての結果を統合(約 250 件)
    • アイテムキーを使って重複を除去(約 120 件の一意なアイテム)
    • 関連度スコアで順位付け
    • 上位 20 件を返す
  5. コンテキスト:

    • 最終的な 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)

💡 ヒント

  1. シンプルに始める:ほとんどのクエリでは comprehensive_search() を使用します
  2. 深さを調整する:search_limit_per_strategy を使って検索の詳細度を調整します
  3. 検索後に絞り込む:広く取得してから、コード内で絞り込みます
  4. 独自のロジック:複雑な絞り込みには Python を使用します
  5. エラーを確認する:必ず 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/ にあります。

コメント