Skip to main content
Glama
jmlon

pydantic-zotero-mcp

by jmlon

pydantic-zotero-mcp

Un servidor MCP que da a los agentes de IA acceso de lectura a una biblioteca de Zotero: búsqueda, metadatos de elementos, colecciones, etiquetas, las notas propias de la persona investigadora y el texto completo indexado de los PDF adjuntos.

Consulta PRD.md para los requisitos.

Estado: M1 (núcleo de lectura) + M2 (texto completo) implementados. El formato de citas y la exportación (M3), los prompts (M4) y las herramientas de escritura (M5) aún no están construidos; consulta No implementado todavía.

Instalación

Como herramienta (pipx)

Instala el comando zotero-mcp en su propio entorno aislado:

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

En el entorno de otro proyecto

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

Para desarrollo en este servidor

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

Configuración

Obtén una clave de API de solo lectura y tu ID de usuario numérico en https://www.zotero.org/settings/keys. El ID de biblioteca es el número, no tu nombre de usuario.

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

Variable

Default

Propósito

ZOTERO_API_KEY

Clave de la API web (obligatoria salvo que ZOTERO_LOCAL=true)

ZOTERO_LIBRARY_ID

ID numérico de usuario o grupo

ZOTERO_LIBRARY_TYPE

user

user o group

ZOTERO_LOCAL

false

Lee en su lugar la API de escritorio de Zotero 7: sin clave, sin límite de peticiones, solo lectura

ZOTERO_ALLOW_WRITES

false

Reservado para M5; aún no existen herramientas de escritura

ZOTERO_FULLTEXT_MAX_CHARS

100000

Límite predeterminado de texto completo; max_chars por llamada lo anula

ZOTERO_DEFAULT_STYLE

chicago-note-bibliography

Reservado para M3

ZOTERO_MAX_CONCURRENCY

4

Límite de peticiones ascendentes (Zotero pide ≤ 4)

ZOTERO_MCP_TRANSPORT

stdio

stdio o http

ZOTERO_MCP_HOST

127.0.0.1

Dirección de enlace HTTP

ZOTERO_MCP_PORT

8000

Puerto HTTP

ZOTERO_MCP_PATH

/mcp

Ruta de montaje HTTP

ZOTERO_MCP_AUTH_TOKEN

Token Bearer; obligatorio para HTTP

Las opciones de la CLI anulan las variables de entorno.

Ejecución

Una vez instalado, zotero-mcp es el punto de entrada: sin ruta de intérprete, sin python -m, sin necesidad de acertar con el directorio de trabajo, que es lo que espera el command: de un cliente MCP:

# 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

Desde un checkout, sin instalar, python -m zotero_mcp también funciona:

uv run python -m zotero_mcp

Arrancar con --transport http y sin token termina con código 2 en lugar de servir sin autenticación: es un canal de lectura hacia una biblioteca personal.

En memoria (integrado en un proceso de agente)

Sin subprocesos, sin socket. La configuración se inyecta, por lo que el host nunca necesita variables de entorno:

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

Importar zotero_mcp no tiene efectos secundarios: no lee configuración, no crea ningún cliente, no usa red; eso es lo que hace posible la integración. Hay una prueba que lo garantiza.

Descubrimiento mediante punto de entrada

Para aplicaciones host que descubren servidores MCP incluidos a través de puntos de entrada de Python, este paquete declara uno en el grupo deep_research.mcp_servers:

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

build_server() no acepta argumentos y obtiene la configuración del entorno: instala este paquete en el entorno del host y el host podrá resolver y ejecutar el servidor en proceso con el nombre zotero, sin importar nada por ruta desde un archivo de configuración.

Una nota de ajuste para hosts automatizados: el límite predeterminado de texto completo de este servidor es de 100.000 caracteres (~25–30k tokens para una única llamada a get_item_fulltext), lo cual es generoso para uso interactivo y demasiado grande para un agente que hace muchas llamadas con un presupuesto de tokens: pasa un max_chars más pequeño por llamada, o baja ZOTERO_FULLTEXT_MAX_CHARS.

Herramientas

Tool

Propósito

get_library_info

Tamaño, modo, permisos. Llamada de orientación barata: úsala primero

search_items

Punto de entrada principal. mode="metadata" o "fulltext" (busca en el texto de los PDF)

list_recent_items

Elementos añadidos recientemente, los más nuevos primero

find_item_by_identifier

«¿Ya tengo esto?» por DOI, ISBN, ID de arXiv o clave

get_item

Metadatos completos; include_children=True también lista adjuntos y notas

get_item_children

Adjuntos y notas, con may_have_fulltext por adjunto

get_item_notes

Las notas propias de la persona investigadora, sin HTML

get_item_fulltext

Texto indexado del adjunto; resuelve de elemento principal → adjunto

list_collections

Árbol de colecciones anidadas

list_collection_items

Elementos de una colección

list_tags

Vocabulario de etiquetas, opcionalmente filtrado por prefijo

Recursos: 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.

Notas de diseño

La proyección es la clave. El JSON crudo de Zotero es de ~1 KB por elemento entre links, library, meta y campos de tipo vacíos. zotero_mcp/projection.py reduce una página de 25 elementos de ~6.100 a ~2.400 tokens estimados (39 % del crudo), por debajo del presupuesto de 4.000 del PRD. Los campos nulos se eliminan en la serialización mediante CompactModel.

pyzotero es síncrono y con estado. Zotero.request y Zotero.links se sobrescriben en cada llamada, y Total-Results se lee de la instancia después; así que un cliente compartido usado de forma concurrente informaría de los totales de otra llamada. gateway.py mantiene un pool de hasta ZOTERO_MAX_CONCURRENCY clientes, retira uno por operación y lee los metadatos de la respuesta dentro del mismo hilo de trabajo que lo tiene. Cada llamada pasa por anyio.to_thread.run_sync para que el bucle de eventos nunca se bloquee.

El backoff es trabajo de pyzotero. pyzotero ≥ 1.13 ya respeta Backoff / Retry-After y reintenta el 429 internamente, así que la puerta de enlace no lo reimplementa. Solo añade un reintento acotado de 3 intentos para fallos transitorios de transporte y errores 5xx.

Nada se trunca en silencio. Las búsquedas informan de total_matched, truncated y next_start; el texto completo informa de total_chars y truncated.

Los resultados son candidatos, no veredictos (PRD D3). find_item_by_identifier devuelve matched_on (key / doi / title / identifier / none) además de una confianza y todos los candidatos plausibles: un preprint y su versión publicada sobreviven ambos. El llamante filtra.

Desviaciones del PRD

Vale la pena conocerlas, ya que cada una fue una decisión de criterio tomada durante la implementación:

  1. No hay objeto mcp a nivel de módulo. El PRD 7.2 pedía a la vez un mcp = create_server() a nivel de módulo y ausencia de efectos secundarios en la importación. Eso entra en conflicto: construir el servidor valida la configuración, así que una instancia a nivel de módulo lanza ImportError en cualquier máquina sin las variables de entorno de Zotero y rompe la vía en memoria que se suponía que debía soportar. Solo existen create_server() / build_default_server().

  2. Las herramientas de escritura se registrarán condicionalmente, no con enabled=False. El PRD 5.5 especificaba @mcp.tool(enabled=False), pero FastMCP 3.x no tiene el kwarg enabled, y una herramienta deshabilitada pero listada sigue costando contexto. Cuando llegue M5, las herramientas de escritura simplemente no se registrarán salvo que ZOTERO_ALLOW_WRITES=true.

    Este servidor está dirigido a FastMCP 3.x. Dos particularidades de 3.x dan forma al código: enabled ya no está en los decoradores, y result.data es un modelo pydantic generado mientras que result.structured_content es el dict simple; las pruebas se basan en esto último, que además verifica la omisión de nulos en el cable.

  3. has_fulltext tiene tres valores. El PRD 6 lo tipaba como bool, pero determinarlo para un elemento principal requiere una petición de hijos separada por elemento, lo que convertiría una búsqueda de 25 elementos en 26 peticiones. Es False cuando un elemento no tiene ningún hijo, True/False para adjuntos y después de get_item(include_children=True), y null (omitido) cuando no se puede determinar. ItemSummary.num_children da la señal barata.

  4. find_item_by_identifier devuelve CitationMatch, no ItemSummary | None. Se deriva de D3: la firma anterior hacía exactamente la llamada de identidad que esa decisión trasladó al cliente.

  5. matched_on ganó key e identifier además de los cuatro valores del PRD, para distinguir una coincidencia exacta de clave de una coincidencia débil de búsqueda.

  6. list_recent_items(since_days=...) filtra localmente. Zotero no tiene filtro de fecha en el servidor, así que una ventana estrecha puede devolver menos elementos que limit; el hint de la respuesta indica cuándo ha ocurrido.

Pruebas

uv run pytest      # 80 passed

La suite usa el transporte en memoria de FastMCP contra un FakeZotero que reproduce el comportamiento de pyzotero de leer los metadatos de la instancia. Sin red, sin subprocesos, sin credenciales reales. Cobertura: superficie del esquema, proyección y presupuesto de tokens, paginación e informe de truncamiento, límite de texto completo y resolución del elemento principal, recuperación de coincidencias (los pares preprint/publicado se devuelven ambos), calidad de los mensajes de error, validación de plantillas de recursos incluidos intentos de traversal, validación de configuración, precedencia de la CLI, reintentos/caché de la puerta de enlace, y una comprobación de pureza de importación que falla si importar el paquete toca la red.

No implementado todavía

  • M3format_citation, format_bibliography, export_items

  • M4 — los cuatro prompts (literature_review, find_related_work, check_citations, summarize_reading), instrumentación con Logfire

  • M5 — herramientas de escritura (create_item, update_item_fields, add_item_tags, add_items_to_collection, create_note) con semántica PATCH con verificación de versión. La eliminación queda fuera de alcance permanentemente.

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