Skip to main content

Headless Zotero-compatible runtime with CLI, HTTP API, MCP, local desktop interoperability, web sync, qmd-backed semantic search, and support for your agent tool of choice

Project description

zotero-headless

zotero-headless logo

zotero-headless is an open-source headless Zotero-compatible runtime with:

  • a CLI
  • an HTTP API
  • an MCP server
  • a clean-room canonical store
  • Zotero web sync
  • local Zotero desktop interoperability
  • qmd-backed semantic search over exported library content
  • compatibility with the agent tool of your choice through API or MCP

All three main interfaces are first-class:

  • CLI
    • good for humans, scripts, and shell automation
  • HTTP API
    • good for apps, services, agents, and direct integrations
  • MCP
    • good for agent tools that already speak MCP

The project is built for two use cases:

  • desktop interoperability
    • work against an existing local Zotero profile
    • import, poll, and apply the currently supported subset of changes back to the local desktop database
  • headless/server runtime
    • run zotero-headless-daemon on a machine without the Zotero GUI
    • expose API and MCP for automation, retrieval, background sync jobs, and agent integrations

Status

This is still pre-release, but it is no longer just a sketch. The codebase already includes:

  • canonical SQLite store plus change log
  • zotero-headless CLI
  • zotero-headless-daemon runtime
  • zotero-headless-mcp stdio server
  • local HTTP API
  • Zotero web sync for user and group libraries
  • local Zotero desktop import, polling, and narrow apply/writeback support
  • remote attachment upload/download for the currently supported stored-file and snapshot-style paths
  • Better BibTeX-oriented citekey compatibility
  • qmd export and semantic search over Markdown derived from canonical state
  • MCP setup helpers for common agent tools
  • runtime observability endpoints and background sync status

What It Is For

Typical end-user use cases:

  • run a headless Zotero-compatible service on a server
  • query or mutate libraries through CLI, API, or MCP
  • sync against Zotero web libraries without requiring the Zotero GUI to be running
  • work against a local desktop Zotero profile when local interoperability is needed
  • export/query library content through qmd-backed semantic search flows

This repository also contains contribution and architecture material because the project is still evolving, but the repo is not meant only for contributors.

Why The Repo Includes Vendored Zotero Code

This repository intentionally includes a vendored Zotero source snapshot under vendor/.

That is here for contributor visibility and debugging, not because the whole project is just a Zotero wrapper. The current architecture is a clean-room headless runtime with adapters around Zotero desktop and Zotero web sync, but understanding the upstream desktop/runtime behavior still matters for:

  • local database interoperability
  • daemon/bootstrap experiments
  • sync semantics
  • attachment handling
  • reproducible debugging for contributors

For this project, keeping that context available is more useful than hiding it in a separate private mirror.

Repository Layout

  • src/zotero_headless/
    • main runtime, CLI, API, MCP, sync, and adapter code
  • tests/
    • regression coverage for the runtime, sync, adapter, and tooling surfaces
  • docs/
    • architecture notes and implementation planning
  • vendor/
    • vendored Zotero source snapshot used for reference and compatibility work

Local-only workspace material should go in ignored directories such as:

  • .codex/
  • .agents/
  • .notes/
  • .tmp/

Install

From source:

git clone https://github.com/<owner>/zotero-headless.git
cd zotero-headless
PYTHONPATH=src python3 -m zotero_headless capabilities

Main entrypoints:

zotero-headless
zotero-headless-daemon
zotero-headless-mcp

Short aliases:

zhl
zhl-daemon
zhl-mcp

Quick Start

Run the setup flow:

zhl setup start

setup start tries autodiscovery first and then falls back to prompts for anything still missing.

Autodiscovery looks for:

  • standard Zotero data directories such as ~/Zotero
  • common Zotero desktop binary locations
  • already-saved API credentials and remote-library selections

Then the wizard will:

  • ask for your local Zotero data directory
  • ask for your Zotero API key only when web sync is needed
  • discover your personal library and available group libraries
  • let you choose which remote libraries to configure
  • store a default remote library for later use

That means it also works for:

  • a Linux server where this is the only Zotero-related install
  • rerunning setup later to add or remove group libraries
  • switching to a different Zotero account in true headless mode
  • changing local Zotero paths without redoing the whole setup

You can inspect what autodiscovery sees without changing config:

zhl config autodiscover

You can also reconfigure specific parts later:

zhl setup account
zhl setup libraries
zhl setup local

For non-interactive automation, you can still initialize configuration directly:

python -m zotero_headless config init \
  --data-dir "$HOME/Zotero" \
  --api-key "$ZOTERO_API_KEY" \
  --user-id 123456 \
  --remote-library-id user:123456 \
  --remote-library-id group:654321 \
  --default-library-id user:123456

Run the daemon runtime:

zhl-daemon serve --host 127.0.0.1 --port 8787 --sync-interval 300

Run the API directly without the daemon wrapper:

zhl api serve --host 127.0.0.1 --port 8787

Run the MCP server:

zhl-mcp

API exposure works in two modes:

  • zotero-headless api serve
    • standalone HTTP API process
  • zotero-headless-daemon serve
    • daemon runtime that hosts the same HTTP API plus runtime state and background sync

So no, the API is not only exposed on zotero-headless-daemon.

Inspect capabilities and daemon state:

zotero-headless capabilities
zotero-headless daemon status
zotero-headless doctor

Choosing An Interface

Use the CLI if you want:

  • terminal-first workflows
  • shell scripts
  • direct local administration

Use the HTTP API if you want:

  • app-to-app integration
  • service orchestration
  • direct agent integrations without MCP
  • long-running daemon deployments

Use MCP if you want:

  • native tool use inside MCP-capable agent clients
  • easy installation into Codex, Claude Code, Cursor, Gemini, Cline, Windsurf, and similar tools

Current Command Surface

Local desktop interoperability:

zotero-headless local libraries
zotero-headless local import
zotero-headless local poll
zotero-headless local plan-apply --library local:1
zotero-headless local apply --library local:1

Remote sync:

zotero-headless sync canonical-discover
zotero-headless sync canonical-pull --library user:123456
zotero-headless sync canonical-push --library user:123456
zotero-headless sync conflicts --library user:123456

qmd flows:

zotero-headless qmd export
zotero-headless qmd query "retrieval augmented generation"

MCP/client setup:

zotero-headless setup list
zotero-headless setup add codex --scope user
zotero-headless setup add claude-code --scope project
zotero-headless setup add claude-desktop --scope user
zotero-headless setup add cursor --scope project
zotero-headless setup add gemini --scope user
zotero-headless setup add cline --scope user
zotero-headless setup add antigravity --scope user
zotero-headless setup add windsurf --scope user

Agent skill helpers:

zotero-headless skill install codex
zotero-headless skill install claude-code
zotero-headless skill install gemini-cli
zotero-headless skill install cline
zotero-headless skill install antigravity
zotero-headless skill install openclaw
zotero-headless skill install opencode

What Is Implemented vs. What Is Still Narrow

Implemented:

  • canonical headless store and mutation log
  • runtime daemon, API, and MCP server
  • Zotero web sync for remote libraries
  • local desktop import and polling
  • narrow local writeback/apply support for the supported item, collection, note, annotation, and attachment paths
  • remote attachment handling for the currently supported stored-file and snapshot-style paths
  • Better BibTeX-oriented citekey handling

Still intentionally narrow:

  • some local desktop writeback edge cases
  • full Zotero file-sync parity across every attachment mode and conflict case
  • broader packaging/release polish

Documentation

References

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zotero_headless-0.1.0.tar.gz (92.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zotero_headless-0.1.0-py3-none-any.whl (79.6 kB view details)

Uploaded Python 3

File details

Details for the file zotero_headless-0.1.0.tar.gz.

File metadata

  • Download URL: zotero_headless-0.1.0.tar.gz
  • Upload date:
  • Size: 92.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for zotero_headless-0.1.0.tar.gz
Algorithm Hash digest
SHA256 29fb6eda5afe7379e88f30be29c1f9d1e61f80faa9cb62c082ef164f70daf5f1
MD5 61aadc9297f70887a36b7b04b71d95b4
BLAKE2b-256 23401586dff7ab4f37051320ea0e052c9eb85a508a604f46f81e356bb4007aef

See more details on using hashes here.

Provenance

The following attestation bundles were made for zotero_headless-0.1.0.tar.gz:

Publisher: publish.yml on robinradx/zotero-headless

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file zotero_headless-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for zotero_headless-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bdf17bff42193bc574b934eaf7a43f66a90d8d84ff311024d8a8e49049380cf1
MD5 7f8147301dce5c0e07ebda545796d7f6
BLAKE2b-256 7110c210f18f1c81ed1fef54d016d281c04459dc464465bac234cda9e7f9a03b

See more details on using hashes here.

Provenance

The following attestation bundles were made for zotero_headless-0.1.0-py3-none-any.whl:

Publisher: publish.yml on robinradx/zotero-headless

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page