Skip to main content
Glama
jmlon

pydantic-zotero-mcp

by jmlon

pydantic-zotero-mcp

Ein MCP-Server, der KI-Agenten Lesezugriff auf eine Zotero-Bibliothek gewährt – Suche, Metadaten von Einträgen, Sammlungen, Tags, die eigenen Notizen des Forschers und den indizierten Volltext angehängter PDFs.

Siehe PRD.md für die Anforderungen.

Status: M1 (Lesen Kern) + M2 (Volltext) implementiert. Zitierformatierung und -export (M3), Prompts (M4) und Schreibwerkzeuge (M5) sind noch nicht gebaut – siehe Noch nicht implementiert.

Installation

Als Werkzeug (pipx)

Installiert den Befehl zotero-mcp in eine eigene isolierte Umgebung:

pipx install pydantic-zotero-mcp        # or: pipx install /path/to/checkout
zotero-mcp --help

In der Umgebung eines anderen Projekts

uv add pydantic-zotero-mcp              # or: uv pip install pydantic-zotero-mcp

Für die Entwicklung an diesem Server

git clone https://github.com/jmlon/pydantic-zotero-mcp
cd pydantic-zotero-mcp
uv sync           # creates ./.venv from this project's own lock file
uv run pytest
uv run ruff check

Related MCP server: zotero-cli-cc

Konfiguration

Holen Sie sich einen schreibgeschützten API-Schlüssel und Ihre numerische Benutzer-ID von https://www.zotero.org/settings/keys. Die Bibliotheks-ID ist die Nummer, nicht Ihr Benutzername.

export ZOTERO_API_KEY=...
export ZOTERO_LIBRARY_ID=123456      # numeric
export ZOTERO_LIBRARY_TYPE=user      # or group

Variable

Standard

Zweck

ZOTERO_API_KEY

Web-API-Schlüssel (erforderlich, außer ZOTERO_LOCAL=true)

ZOTERO_LIBRARY_ID

Numerische Benutzer- oder Gruppen-ID

ZOTERO_LIBRARY_TYPE

user

user oder group

ZOTERO_LOCAL

false

Stattdessen die Zotero-7-Desktop-API lesen: kein Schlüssel, kein Rate Limit, schreibgeschützt

ZOTERO_ALLOW_WRITES

false

Für M5 reserviert; es gibt noch keine Schreibwerkzeuge

ZOTERO_FULLTEXT_MAX_CHARS

100000

Standard-Obergrenze für Volltext; max_chars pro Aufruf überschreibt sie

ZOTERO_DEFAULT_STYLE

chicago-note-bibliography

Für M3 reserviert

ZOTERO_MAX_CONCURRENCY

4

Obergrenze für Upstream-Anfragen (Zotero bittet um ≤ 4)

ZOTERO_MCP_TRANSPORT

stdio

stdio oder http

ZOTERO_MCP_HOST

127.0.0.1

HTTP-Bindeadresse

ZOTERO_MCP_PORT

8000

HTTP-Port

ZOTERO_MCP_PATH

/mcp

HTTP-Mount-Pfad

ZOTERO_MCP_AUTH_TOKEN

Bearer-Token; für HTTP erforderlich

CLI-Flags überschreiben Umgebungsvariablen.

Ausführen

Nach der Installation ist zotero-mcp der Einstiegspunkt – kein Interpreterpfad, kein python -m, kein Arbeitsverzeichnis, das stimmen muss, was ein MCP-Client mit command: erwartet:

# stdio (default) — an agent launches this as a subprocess
zotero-mcp

# streamable HTTP — requires ZOTERO_MCP_AUTH_TOKEN
ZOTERO_MCP_AUTH_TOKEN=secret zotero-mcp --transport http --port 8000

# read the Zotero desktop app instead of the web API
zotero-mcp --local

Aus einem Checkout heraus funktioniert ohne Installation weiterhin python -m zotero_mcp:

uv run python -m zotero_mcp

Der Start mit --transport http und ohne Token beendet sich mit Exit-Code 2, anstatt unauthentifiziert zu dienen: Dies ist ein Lesekanal in eine persönliche Bibliothek.

Im Speicher (eingebettet in einen Agentenprozess)

Kein Subprozess, kein Socket. Die Einstellungen werden injiziert, sodass der Host nie Umgebungsvariablen benötigt:

from fastmcp import Client
from zotero_mcp import ZoteroSettings, create_server

server = create_server(
    ZoteroSettings(
        api_key=key,
        library_id="123456",
        library_type="user",
    )
)

async with Client(server) as client:  # lifespan opens here
    result = await client.call_tool("search_items", {"query": "attention"})
    print(result.structured_content["items"])  # dict; result.data is a model

Das Importieren von zotero_mcp hat keine Seiteneffekte – keine Konfiguration wird gelesen, kein Client erstellt, kein Netzwerk – genau das macht das Einbetten möglich. Es gibt einen Test, der das durchsetzt.

Erkennung über Einstiegspunkt

Für Hostanwendungen, die gebündelte MCP-Server über Python-Einstiegspunkte erkennen, deklariert dieses Paket einen in der Gruppe deep_research.mcp_servers:

[project.entry-points."deep_research.mcp_servers"]
zotero = "zotero_mcp:build_server"

build_server() akzeptiert keine Argumente und leitet die Einstellungen aus der Umgebung ab – installieren Sie dieses Paket in der Umgebung des Hosts, und der Host kann den Server unter dem Namen zotero im Prozess auflösen und ausführen, ohne etwas per Pfad aus einer Konfigurationsdatei zu importieren.

Ein Hinweis zur Abstimmung für automatisierte Hosts: Die Standard-Obergrenze für Volltext dieses Servers beträgt 100.000 Zeichen (~25.000–30.000 Token für einen einzelnen get_item_fulltext-Aufruf), was für die interaktive Nutzung großzügig ist und viel zu groß für einen Agenten, der viele Aufrufe innerhalb eines Token-Budgets tätigt – übergeben Sie pro Aufruf ein kleineres max_chars oder senken Sie ZOTERO_FULLTEXT_MAX_CHARS.

Werkzeuge

Werkzeug

Zweck

get_library_info

Größe, Modus, Berechtigungen. Günstiger Orientierungsaufruf – zuerst nutzen

search_items

Primärer Einstiegspunkt. mode="metadata" oder "fulltext" (durchsucht PDF-Text)

list_recent_items

Kürzlich hinzugefügte Einträge, neueste zuerst

find_item_by_identifier

„Habe ich das schon?" per DOI, ISBN, arXiv-ID oder Schlüssel

get_item

Vollständige Metadaten; include_children=True listet auch Anhänge und Notizen auf

get_item_children

Anhänge und Notizen, mit may_have_fulltext pro Anhang

get_item_notes

Die eigenen Notizen des Forschers, HTML entfernt

get_item_fulltext

Indizierter Anhangstext; löst Eltern → Anhang auf

list_collections

Verschachtelter Sammlungsbaum

list_collection_items

Einträge in einer Sammlung

list_tags

Tag-Vokabular, optional präfixgefiltert

Ressourcen: zotero://library/info, zotero://collections, zotero://items/{key}, zotero://items/{key}/fulltext, zotero://collections/{key}/items, zotero://schema/item-types, zotero://schema/item-types/{type}/fields.

Designhinweise

Projektion ist der Punkt. Rohes Zotero-JSON ist ~1 KB pro Eintrag an links, library, meta und leeren Typfeldern. zotero_mcp/projection.py reduziert eine Seite mit 25 Einträgen von ~6.100 auf ~2.400 geschätzte Token (39 % des Rohwerts), unter dem PRD-Budget von 4.000. Null-Felder werden bei der Serialisierung von CompactModel entfernt.

pyzotero ist synchron und zustandsbehaftet. Zotero.request und Zotero.links werden bei jedem Aufruf überschrieben, und Total-Results wird danach von der Instanz gelesen – ein gemeinsam genutzter Client würde also die Summen eines anderen Aufrufs melden. gateway.py hält einen Pool von bis zu ZOTERO_MAX_CONCURRENCY Clients, leiht sich pro Vorgang einen aus und liest die Antwortmetadaten im selben Worker-Thread, der den Client hält. Jeder Aufruf läuft über anyio.to_thread.run_sync, sodass die Ereignisschleife nie blockiert wird.

Backoff ist pyzoteros Aufgabe. pyzotero ≥ 1.13 beachtet bereits Backoff / Retry-After und wiederholt 429 intern, daher implementiert das Gateway es nicht neu. Es fügt nur einen begrenzten 3-Versuche-Wiederholungsversuch für vorübergehende Transport- und 5xx-Fehler hinzu.

Nichts wird stillschweigend abgeschnitten. Suchen melden total_matched, truncated und next_start; Volltext meldet total_chars und truncated.

Ergebnisse sind Kandidaten, keine Urteile (PRD D3). find_item_by_identifier gibt matched_on (key / doi / title / identifier / none) sowie ein Konfidenzniveau und alle plausiblen Kandidaten zurück – ein Preprint und seine veröffentlichte Version überleben beide. Der Aufrufer filtert.

Abweichungen vom PRD

Wissenswert, da jede eine Ermessensentscheidung während der Implementierung war:

  1. Kein mcp-Objekt auf Modulebene. PRD 7.2 forderte sowohl ein mcp = create_server() auf Modulebene als auch keine Seiteneffekte beim Import. Das widerspricht sich: Das Erstellen des Servers validiert die Konfiguration, daher würde eine Instanz auf Modulebene auf jedem Rechner ohne Zotero-Umgebungsvariablen einen ImportError auslösen und den In-Memory-Pfad brechen, den sie unterstützen sollte. Es existieren nur create_server() / build_default_server().

  2. Schreibwerkzeuge werden bedingt registriert, nicht mit enabled=False. PRD 5.5 spezifizierte @mcp.tool(enabled=False), aber FastMCP 3.x hat kein enabled-Kwarg, und ein deaktiviertes, aber aufgelistetes Werkzeug kostet trotzdem Kontext. Wenn M5 eintrifft, werden Schreibwerkzeuge einfach nicht registriert, sofern nicht ZOTERO_ALLOW_WRITES=true gesetzt ist.

    Dieser Server zielt auf FastMCP 3.x. Zwei 3.x-Besonderheiten prägen den Code hier: enabled ist aus den Dekorateuren entfernt, und result.data ist ein generiertes Pydantic-Modell, während result.structured_content das einfache Dict ist – die Tests prüfen auf Letzteres, was auch die Null-Auslassung auf der Leitung verifiziert.

  3. has_fulltext ist dreiwertig. PRD 6 typisierte es als bool, aber die Bestimmung für ein übergeordnetes Element erfordert eine separate Kinderanfrage pro Element, was eine Suche mit 25 Einträgen zu 26 Anfragen machen würde. Es ist False, wenn ein Element überhaupt keine Kinder hat, True/False für Anhänge und nach get_item(include_children=True) und null (weggelassen), wenn unbestimmt. ItemSummary.num_children liefert das günstige Signal.

  4. find_item_by_identifier gibt CitationMatch zurück, nicht ItemSummary | None. Folgt aus D3 – die alte Signatur traf genau den Identitätsaufruf, den diese Entscheidung auf den Client verlagert hat.

  5. matched_on erhielt key und identifier zusätzlich zu den vier PRD-Werten, um einen exakten Schlüsseltreffer von einem schwachen Suchergebnis zu unterscheiden.

  6. list_recent_items(since_days=...) filtert lokal. Zotero hat keinen serverseitigen Datumsfilter, daher kann ein enges Zeitfenster weniger Elemente als limit zurückgeben; der hint in der Antwort sagt, wann das passiert ist.

Tests

uv run pytest      # 80 passed

Die Suite verwendet den In-Memory-Transport von FastMCP gegen ein FakeZotero, das das Verhalten von pyzotero nachbildet, Metadaten von der Instanz zu lesen. Kein Netzwerk, kein Subprozess, keine echten Anmeldedaten. Abdeckung: Schemaoberfläche, Projektion und Token-Budget, Paginierung und Abschneideberichte, Volltext-Obergrenze und Elternauflösung, Trefferabruf (Preprint/veröffentlichte Paare werden beide zurückgegeben), Fehlermeldungsqualität, Ressourcenvorlagenvalidierung einschließlich Traversierungsversuchen, Konfigurationsvalidierung, CLI-Vorrang, Gateway-Wiederholung/-Zwischenspeicherung und ein Import-Reinheitscheck, der fehlschlägt, wenn das Importieren des Pakets das Netzwerk berührt.

Noch nicht implementiert

  • M3format_citation, format_bibliography, export_items

  • M4 – die vier Prompts (literature_review, find_related_work, check_citations, summarize_reading), Logfire-Instrumentierung

  • M5 – Schreibwerkzeuge (create_item, update_item_fields, add_item_tags, add_items_to_collection, create_note) mit versionsgeprüfter PATCH-Semantik. Das Löschen ist dauerhaft außerhalb des Rahmens.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    A lightweight MCP server that connects AI agents to a local Zotero library for paper management and metadata retrieval. It enables users to search titles and abstracts, browse collections, and automatically ingest papers via arXiv ID or DOI with PDF attachments.
    8
    15
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    MCP server that exposes 45 tools for Zotero reference management, enabling AI agents to read/write items, search, extract PDF text, and manage workspaces via the Zotero CLI.
    198
    AGPL 3.0

View all related MCP servers

Related MCP Connectors

  • Remote MCP server for full read/write access to a Zotero library

  • Agentic search over your Dewey document collections from any MCP-compatible client.

  • An MCP server that gives your AI access to the source code and docs of all public github repos

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jmlon/pydantic-zotero-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server