n8n Workflow Builder MCP Server
by makafeli
Verified
- src
- zotero_mcp
import os
from typing import Any
from dotenv import load_dotenv
from pydantic import BaseModel
from pyzotero import zotero
# Load environment variables
load_dotenv()
# Initialize Zotero client
def get_zotero_client() -> zotero.Zotero:
"""Get authenticated Zotero client using environment variables"""
library_id = os.getenv("ZOTERO_LIBRARY_ID")
library_type = os.getenv("ZOTERO_LIBRARY_TYPE", "user")
api_key = os.getenv("ZOTERO_API_KEY")
local = os.getenv("ZOTERO_LOCAL", "").lower() in ["true", "yes", "1"]
if local and not library_id:
# Indicates "current user" for the local API
library_id = "0"
if not local or all([library_id, api_key]):
raise ValueError(
"Missing required environment variables. Please set ZOTERO_LIBRARY_ID and ZOTERO_API_KEY"
)
return zotero.Zotero(
library_id=library_id,
library_type=library_type,
api_key=api_key,
local=local,
)
class AttachmentDetails(BaseModel):
key: str
content_type: str
def get_attachment_details(
zot: zotero.Zotero,
item: dict[str, Any],
) -> AttachmentDetails | None:
"""Get attachment ID and content type for a Zotero item"""
data = item.get("data", {})
item_type = data.get("itemType")
# Direct attachment - check if it's a PDF or other supported type
if item_type == "attachment":
content_type = data.get("contentType")
return AttachmentDetails(
key=data.get("key"),
content_type=content_type,
)
# For regular items, look for child attachments
try:
children: Any = zot.children(data.get("key", ""))
# Group attachments by content type and size
pdfs = []
htmls = []
others = []
for child in children:
child_data = child.get("data", {})
if child_data.get("itemType") == "attachment":
content_type = child_data.get("contentType")
file_size = child_data.get("md5", "") # Use md5 as proxy for size
if content_type == "application/pdf":
pdfs.append((child_data.get("key"), content_type, file_size))
elif content_type == "text/html":
htmls.append((child_data.get("key"), content_type, file_size))
else:
others.append((child_data.get("key"), content_type, file_size))
# Return first match in priority order
if pdfs:
pdfs.sort(key=lambda x: x[2], reverse=True)
return AttachmentDetails(
key=pdfs[0][0],
content_type=pdfs[0][1],
)
if htmls:
htmls.sort(key=lambda x: x[2], reverse=True)
return AttachmentDetails(
key=htmls[0][0],
content_type=htmls[0][1],
)
if others:
others.sort(key=lambda x: x[2], reverse=True)
return AttachmentDetails(
key=others[0][0],
content_type=others[0][1],
)
except Exception:
pass
return None