Skip to main content
Glama
jmlon

pydantic-zotero-mcp

by jmlon

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 check

Related 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

변수

기본값

설명

ZOTERO_API_KEY

웹 API 키 (ZOTERO_LOCAL=true가 아닐 때 필수)

ZOTERO_LIBRARY_ID

숫자 사용자 또는 그룹 ID

ZOTERO_LIBRARY_TYPE

user

user 또는 group

ZOTERO_LOCAL

false

대신 Zotero 7 데스크톱 API를 읽음: 키 불필요, 속도 제한 없음, 읽기 전용

ZOTERO_ALLOW_WRITES

false

M5용으로 예약됨; 현재 쓰기 도구는 없음

ZOTERO_FULLTEXT_MAX_CHARS

100000

기본 전체 텍스트 상한; 호출별 max_chars가 이를 재정의

ZOTERO_DEFAULT_STYLE

chicago-note-bibliography

M3용으로 예약됨

ZOTERO_MAX_CONCURRENCY

4

업스트림 요청 상한 (Zotero 공식 권장 ≤ 4)

ZOTERO_MCP_TRANSPORT

stdio

stdio 또는 http

ZOTERO_MCP_HOST

127.0.0.1

HTTP 바인딩 주소

ZOTERO_MCP_PORT

8000

HTTP 포트

ZOTERO_MCP_PATH

/mcp

HTTP 마운트 경로

ZOTERO_MCP_AUTH_TOKEN

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 model

zotero_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를 낮추세요.

도구

도구

용도

get_library_info

크기·모드·권한. 가벼운 방향 확인용 호출 — 우선 사용하세요

search_items

기본 진입점. mode="metadata" 또는 "fullfulltext" (PDF 텍스트 검색)

list_recent_items

최근 추가된 항목을 최신순으로

find_item_by_identifier

"이미 있는가?" — DOI, ISBN, arXiv ID 또는 key로 확인

get_item

전체 메타데이터; include_children=True는 첨부와 노트도 조회

get_item_children

첨부와 노트를, 각 attach별 may_have_fulltext와 함께 반환

get_item_notes

연구자 자신의 노트, HTML 제거 후 반환

get_item_fulltext

인덱싱된 첨부 텍스트; 상위 항목에서 첨부 항목을 찾아 반환

list_collections

중첩 컬렉션 트리

list_collection_items

한 컬렉션의 항목들

list_tags

태그 어휘, 선택적으로 접두어 필터 적용

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.requestZotero.links를 매 호출에서 덮어쓰며, Total-Results는 호출 이후 인스턴스에서 다시 읽어옵니다. 그래서 하나의 공유 클라이언트를 동시에 쓰면 다른 호출의 합계를 보고하게 됩니다. gateway.pyZOTERO_MAX_CONCURRENCY 만큼의 클라이언트 풀을 유지하고, 작업당 하나를 빌린 뒤 그 워커 스레드 안에서 응답 메타데이터를 읽습니다. 모든 호출은 anyio.to_thread.run_sync를 거치므로 이벤트 루프가 블로킹되지 않습니다.

백오프는 pyzotero의 몫입니다. pyzotero ≥ 1.13에서는 Backoff / Retry-After를 이미 존중하고 내부적으로 429 재시도를 하므로, 게이트웨이가 이를 다시 구현하지 않습니다. 게이트웨이는 일시적인 전송 오류와 5xx 오류에 대해서만 제한된 3회 재시도를 추가합니다.

조용한 잘림은 없습니다. 모든 검색에서 total_matched, truncated, next_start를 보고하며 전체 텍스트는 total_charstruncated를 보고합니다.

결과는 판정이 아닌 후보입니다 (PRD D3). find_item_by_identifiermatched_on (key / doi / title / identifier / none)과 함께 신뢰도와 모든 유사 후보를 반환합니다 — 사전출판본(프리프린트)과 출판본이 함께 살아남습니다. 필터링은 호출자가 합니다.

PRD와의 차이

구현 과정에서 내린 판단들이므로 알아둘 만합니다:

  1. 모듈 레벨 mcp 객체가 없습니다. PRD 7.2는 모듈 레벨 mcp = create_server() 와, 임포트 시 부작용 없음, 둘을 요구했습니다. 충돌합니다: 서버를 만든다는 것은 설정을 검증하기 때문에, 모듈 레벨 인스턴스는 Zotero 환경 변수가 없는 기계에서 ImportError를 발생게 하며, 인메모리 경로를 부수기도 합니다. create_server() / build_default_server()만 존재합니다.

  2. 쓰기 도구는 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 누락을 함께 검증합니다.

  3. has_fulltext는 셋 중 하나(three-valued)입니다. PRD 6은 bool로 타입을 정했지만, 부모 항목에 대해 이 값을 판단하려면 항목별로 별도 children 요청을 해야 해서 25개 항목 검색이 26개 요청이 되어 버립니다. 항목에 자식이 전혀 없다면 False, 첨부 항목에 대해서는 get_item(include_children=True) 이후에 True/False, 결정되지 않았으면 null(생격)입니다. ItemSummary.num_children가 이를 저렴하게 알려줍니다.

  4. find_item_by_identifierCitationMatch를 반환하며, ItemSummary | None 가 아닙니다. D3의 결과입니다. 이전 서명은 정확히 그 식별자 일치를 판정글은 결정을 클라이언트로 옮긴 그 호출을 하고 있었기에 좋 .

  5. matched_onkeyidentifier를 추가로 받습니다. PRD의 네 값에 더해, 정확한 key 일치와 약한 검색 일치를 구분하게 됩니다.

  6. list_recent_items(since_days=...)는 로컬에서 필터링합니다. Zotero에는 서버 측 날짜 필터가 없으므로 좁은 기간은 limit보다 적은 수를 돌려줄 수 있으며, 응답의 hint가 그때를 알려줍니다.

테스트

uv run pytest      # 80 passed

이 스위트는 FakeZotero를 대상으로 FastMCP의 인메모리 전송을 사용합니다. FakeZotero가 pyzotero의 인스턴스로부터 메타데이터를 읽는 비슷한 동작을 재현합니다. 네트워크 없음, 서브프로세스 없음, 실제 인증 정보 없음. 포함 범위: 스키마 서피스, projection과 토큰 예산, 페이지네이션 및 잘림 보고, 전체 텍스트 상한과 상위 항목 해석, 매칭 재현율(프리프린트/출판 쌍이 모두 반환됨), 오류 메시지 품질, 리소스 템플릿 검증(순회 시도 포함), 설정 검증, CLI 우선순위, 게이트웨이 재시도/캐싱, 그리고 패키지를 임포트했을 때 네트워크에 닿으면 실패하는 임포트 순수성 검사까지 포함합니다.

아직 구현되지 않은 것

  • M3format_citation, format_bibliography, export_items

  • M4 — 네 가지 프롬프트(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 체크된 의미 체계. 삭제는 영구적으로 범위 밖입니다.

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