pydantic-zotero-mcp
pydantic-zotero-mcp
AI 에이전트에 Zotero 라이브러리에 대한 읽기 접근 권한을 부여하는 MCP 서버입니다 — 검색, 항목 메타데이터, 컬렉션, 태그, 연구자 본인의 노트, 첨부된 PDF의 인덱싱된 전체 텍스트(full text)를 포함합니다.
요구 사항은 PRD.md를 참조하세요.
상태: M1(읽기 코어) + M2(전체 텍스트) 구현됨. 인용 서식 지정 및 내보내기(M3), 프롬프트(M4), 쓰기 도구(M5)는 아직 구현되지 않았습니다 — 아직 구현되지 않은 것을 참조하세요.
설치
도구로 설치 (pipx)
zotero-mcp 명령을 자체 격리 환경에 설치합니다:
pipx install pydantic-zotero-mcp # or: pipx install /path/to/checkout
zotero-mcp --help다른 프로젝트의 환경에 설치
uv add pydantic-zotero-mcp # or: uv pip install pydantic-zotero-mcp이 서버 개발용
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 checkRelated MCP server: zotero-cli-cc
설정
읽기 전용 API 키와 숫자 사용자 ID를 https://www.zotero.org/settings/keys에서 받으세요. 라이브러리 ID는 사용자 이름이 아니라 숫자입니다.
export ZOTERO_API_KEY=...
export ZOTERO_LIBRARY_ID=123456 # numeric
export ZOTERO_LIBRARY_TYPE=user # or group변수 | 기본값 | 설명 |
| — | 웹 API 키 ( |
| — | 숫자 사용자 또는 그룹 ID |
|
|
|
|
| 대신 Zotero 7 데스크톱 API를 읽음: 키 불필요, 속도 제한 없음, 읽기 전용 |
|
| M5용으로 예약됨; 현재 쓰기 도구는 없음 |
|
| 기본 전체 텍스트 상한; 호출별 |
|
| M3용으로 예약됨 |
|
| 업스트림 요청 상한 (Zotero 공식 권장 ≤ 4) |
|
|
|
|
| HTTP 바인딩 주소 |
|
| HTTP 포트 |
|
| HTTP 마운트 경로 |
| — | Bearer 토큰; HTTP에서 필수 |
CLI 플래그가 환경 변수를 재정의합니다.
실행
설치 후에는 zotero-mcp가 진입점입니다. 인터프리터 경로를 지정하거나 python -m을 붙이거나
작업 디렉터리를 맞출 필요가 없습니다. 이것이 MCP 클라이언트의 command:가 기대하는 방식입니다:
# 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체크아웃에서 설치하지 않고도 python -m zotero_mcp가 여전히 동작합니다:
uv run python -m zotero_mcp--transport http로 토큰 없이 시작하면 인증되지 않은 요청을 처리하는 대신 exit code 2로
종료합니다: 개인 라이브러리로 연결되는 읽기 전용 채널이기 때문입니다.
인메모리 (에이전트 프로세스에 임베드)
서브프로세스도, 소켓도 없습니다. 설정이 주입되므로 호스트가 환경 변수를 신경 쓸 필요가 없습니다:
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 modelzotero_mcp를 임포트해도 부작용이 없습니다 — 설정을 읽거나, 클라이언트를 만들거나,
네트워크에 접속하지 않습니다. 그래서 임베딩이 가능한 것입니다. 이를 강제하는 테스트가 있습니다.
엔트리 포인트를 통한 검색
번들된 MCP 서버를 Python 엔트리 포인트로 발견하는 호스트 애플리케이션을 위해, 이 패키지는
deep_research.mcp_servers 그룹에 하나를 선언합니다:
[project.entry-points."deep_research.mcp_servers"]
zotero = "zotero_mcp:build_server"build_server()는 인자를 받지 않고 환경에서 설정을 읽습니다. 이 패키지를 호스트의 환경에
설치하면, 호스트는 설정 파일에서 경로로 뭔가를 임포트하지 않고도 zotero라는 이름으로
인프로세스(in-process) 서버를 해석하고 실행할 수 있습니다.
자동화된 호스트를 위한 튜닝 참고 사항: 이 서버의 기본 전체 텍스트 상한은 100,000자
(단일 get_item_fulltext 호출 기준 약 25,000~30,000토큰)로, 대화형에는 넉넉한 값이지만
토큰 예산 하에서 여러 번 호출하는 에이전트에게는 너무 큽니다 — 호출 때 더 작은 max_chars를
전달하거나 ZOTERO_FULLTEXT_MAX_CHARS를 낮추세요.
도구
도구 | 용도 |
| 크기·모드·권한. 가벼운 방향 확인용 호출 — 우선 사용하세요 |
| 기본 진입점. |
| 최근 추가된 항목을 최신순으로 |
| "이미 있는가?" — DOI, ISBN, arXiv ID 또는 key로 확인 |
| 전체 메타데이터; |
| 첨부와 노트를, 각 attach별 |
| 연구자 자신의 노트, HTML 제거 후 반환 |
| 인덱싱된 첨부 텍스트; 상위 항목에서 첨부 항목을 찾아 반환 |
| 중첩 컬렉션 트리 |
| 한 컬렉션의 항목들 |
| 태그 어휘, 선택적으로 접두어 필터 적용 |
Resources: 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.
설계 노트
핵심은 투영(Projection)입니다. 원시 Zotero JSON은 항목당 links, library, meta,
빈 타입 필드 등을 포함해 약 1KB입니다. zotero_mcp/projection.py는 25개 항목 페이지를
추정 토큰 수 기준 약 6,100개에서 약 2,400개(원본의 39%)로 줄여 PRD의 4,000 예산 안에
들게 합니다. CompactModel이 직렬화 시 null 필드를 누락시킵니다.
pyzotero는 동기적이고 상태를 가집니다. Zotero.request와 Zotero.links를 매 호출에서
덮어쓰며, Total-Results는 호출 이후 인스턴스에서 다시 읽어옵니다. 그래서 하나의 공유 클라이언트를
동시에 쓰면 다른 호출의 합계를 보고하게 됩니다. gateway.py는 ZOTERO_MAX_CONCURRENCY 만큼의
클라이언트 풀을 유지하고, 작업당 하나를 빌린 뒤 그 워커 스레드 안에서 응답 메타데이터를 읽습니다.
모든 호출은 anyio.to_thread.run_sync를 거치므로 이벤트 루프가 블로킹되지 않습니다.
백오프는 pyzotero의 몫입니다. pyzotero ≥ 1.13에서는 Backoff / Retry-After를 이미
존중하고 내부적으로 429 재시도를 하므로, 게이트웨이가 이를 다시 구현하지 않습니다. 게이트웨이는
일시적인 전송 오류와 5xx 오류에 대해서만 제한된 3회 재시도를 추가합니다.
조용한 잘림은 없습니다. 모든 검색에서 total_matched, truncated, next_start를 보고하며
전체 텍스트는 total_chars와 truncated를 보고합니다.
결과는 판정이 아닌 후보입니다 (PRD D3). find_item_by_identifier는
matched_on (key / doi / title / identifier / none)과 함께 신뢰도와
모든 유사 후보를 반환합니다 — 사전출판본(프리프린트)과 출판본이 함께 살아남습니다.
필터링은 호출자가 합니다.
PRD와의 차이
구현 과정에서 내린 판단들이므로 알아둘 만합니다:
모듈 레벨
mcp객체가 없습니다. PRD 7.2는 모듈 레벨mcp = create_server()와, 임포트 시 부작용 없음, 둘을 요구했습니다. 충돌합니다: 서버를 만든다는 것은 설정을 검증하기 때문에, 모듈 레벨 인스턴스는 Zotero 환경 변수가 없는 기계에서ImportError를 발생게 하며, 인메모리 경로를 부수기도 합니다.create_server()/build_default_server()만 존재합니다.쓰기 도구는
enabled=False가 아니라 조건부로 등록됩니다. PRD 5.5에서@mcp.tool(enabled=False)를 명시했으나 FastMCP 3.x에는enabled인자가 없고, 비활성이지만 목록에 남은 도구도 여전히 컨텍스트 비용을 차지합니다. M5가 들어오면,ZOTERO_ALLOW_WRITES=true가 아니고는 쓰기 도구가 아예 등록되지 않습니다.이 서버는 FastMCP 3.x를 대상으로 합니다. 코드에 영향을 준 3가지 —
enabled가 데코레이터에서 사라졌고,result.data는 생성된 pydantic 모델이고result.structured_content는 평범한 dict입니다. 테스트는 후자(협 placed content)를 단언하며, 이는 네트워크에서 null 누락을 함께 검증합니다.has_fulltext는 셋 중 하나(three-valued)입니다. PRD 6은bool로 타입을 정했지만, 부모 항목에 대해 이 값을 판단하려면 항목별로 별도 children 요청을 해야 해서 25개 항목 검색이 26개 요청이 되어 버립니다. 항목에 자식이 전혀 없다면False, 첨부 항목에 대해서는get_item(include_children=True)이후에True/False, 결정되지 않았으면null(생격)입니다.ItemSummary.num_children가 이를 저렴하게 알려줍니다.find_item_by_identifier는CitationMatch를 반환하며,ItemSummary | None가 아닙니다. D3의 결과입니다. 이전 서명은 정확히 그 식별자 일치를 판정글은 결정을 클라이언트로 옮긴 그 호출을 하고 있었기에 좋 .matched_on이key와identifier를 추가로 받습니다. PRD의 네 값에 더해, 정확한 key 일치와 약한 검색 일치를 구분하게 됩니다.list_recent_items(since_days=...)는 로컬에서 필터링합니다. Zotero에는 서버 측 날짜 필터가 없으므로 좁은 기간은limit보다 적은 수를 돌려줄 수 있으며, 응답의hint가 그때를 알려줍니다.
테스트
uv run pytest # 80 passed이 스위트는 FakeZotero를 대상으로 FastMCP의 인메모리 전송을 사용합니다. FakeZotero가 pyzotero의
인스턴스로부터 메타데이터를 읽는 비슷한 동작을 재현합니다. 네트워크 없음, 서브프로세스 없음,
실제 인증 정보 없음. 포함 범위: 스키마 서피스, projection과 토큰 예산, 페이지네이션 및 잘림 보고,
전체 텍스트 상한과 상위 항목 해석, 매칭 재현율(프리프린트/출판 쌍이 모두 반환됨), 오류 메시지 품질,
리소스 템플릿 검증(순회 시도 포함), 설정 검증, CLI 우선순위, 게이트웨이 재시도/캐싱, 그리고 패키지를
임포트했을 때 네트워크에 닿으면 실패하는 임포트 순수성 검사까지 포함합니다.
아직 구현되지 않은 것
M3 —
format_citation,format_bibliography,export_itemsM4 — 네 가지 프롬프트(
literature_review,find_related_work,check_citations,summarize_reading), Logfire 계측M5 — 쓰기 도구(
create_item,update_item_fields,add_item_tags,add_items_to_collection,create_note)와 버전이 확인된 PATCH 체크된 의미 체계. 삭제는 영구적으로 범위 밖입니다.
This server cannot be installed
Maintenance
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
- AlicenseAqualityCmaintenanceA 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.815MIT
- AlicenseNot gradedqualityAmaintenanceMCP 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.198AGPL 3.0
- AlicenseNot gradedqualityAmaintenanceMCP server that lets AI assistants search, create, organize, and cite from a Zotero library.3MIT
- AlicenseNot gradedqualityDmaintenanceMCP server that connects AI assistants to your Zotero library, enabling full-text PDF extraction and metadata search.MIT
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
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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