Feature request: programmatic sync trigger via local HTTP API #5909

15 views
Skip to first unread message

Bob Pasker

unread,
May 11, 2026, 11:41:38 PM (2 days ago) May 11
to zotero-dev
## Summary

It would help third-party integrations to have a way to programmatically trigger Zotero's sync from outside the desktop UI. Today there is no public endpoint or scripting hook for this; the only options are clicking *Sync Now*, waiting for the auto-sync interval, or simulating the keyboard shortcut via OS-level keystroke injection (e.g. `osascript` on macOS) — all of which are obviously fragile.

## Use case

I'm contributing to [zotero-mcp](https://github.com/54yyyu/zotero-mcp) ([draft PR #279](https://github.com/54yyyu/zotero-mcp/pull/279)), an MCP server that exposes Zotero to LLM agents. A common flow is:

1. The MCP client calls `zotero_add_from_file` (writes via the Zotero web API + WebDAV PUT for WebDAV-storage users).
2. The client immediately wants to read the file back — e.g. for fulltext extraction.
3. **Problem**: the running Zotero desktop's local DB doesn't know about the item yet, because it hasn't done its periodic sync. So the local API returns 404 even though the web API and WebDAV both have the data.
4. The user has to click *Sync Now* in the desktop UI for the local view to catch up.

The same pattern hits any external tool that wants to write through the web API and then immediately read back through the local API — automation pipelines, browser extensions other than the official Connector, reference-management bots, etc.

## What I'm asking for

Something narrow — a single endpoint, no fancy semantics:

```
POST http://localhost:23119/api/sync
```

Behaviour: trigger the same `Zotero.Sync.Runner.sync()` that the *Sync Now* menu item runs. Optionally return a JSON body indicating the sync started / was already in progress.

A short-poll companion would be enough to make this race-free for callers:

```
GET http://localhost:23119/api/sync/status
→ {"running": true|false, "last_sync": "<ISO 8601>"}
```

But even just the trigger alone is a big improvement over what's available today.

## Workarounds I've considered

- **osascript keystroke** — relies on Zotero having focus or grabbing it, fires the platform-bound shortcut, macOS-only.
- **Wait for auto-sync** — works, but couples client latency to the user's sync-interval preference and surfaces a confusing 404 in the meantime.
- **Bootstrap plugin** that exposes its own HTTP endpoint and calls `Zotero.Sync.Runner.sync()` internally — works, but pushing every third-party tool to ship its own sync-trigger plugin isn't a great experience.
- **Fall back to the web API on local 404** — does work for metadata, but file bytes for WebDAV-storage users still aren't reachable via the web API, so it doesn't close the loop.

## Caveats / questions for maintainers

- I appreciate sync has user-visible side effects (notifications, conflict prompts), so this endpoint probably should be gated the same way the Connector endpoints are (only listening on localhost; possibly an opt-in preference).
- Whether the endpoint should run a full sync vs. a quick "pull from server only" pass is open to discussion. For my use case a full sync is fine.
- Happy to attempt a PR if there's interest and a maintainer can confirm this is something Zotero would accept. I've intentionally filed this as a discussion-style issue rather than dropping code unsolicited.

Marked as a draft / discussion issue — feel free to convert, close, or redirect to the forum if that's the preferred venue for design discussion.

Dan Stillman

unread,
May 11, 2026, 11:57:23 PM (2 days ago) May 11
to zoter...@googlegroups.com
On 5/11/26 12:08 PM, Bob Pasker wrote:
> couples client latency to the user's sync-interval preference and
> surfaces a confusing 404 in the meantime

There's no "sync-interval preference". You either have auto-sync on or
you don't. If you do, the client should receive a WebSocket notification
and sync within a few seconds.

While we'll probably be extending the local API to make it possible [for
agents] to trigger programmatic actions, a sync is an asynchronous
operation, and could result in a conflict or error, etc., so the best
you would receive would be an indication that a sync had started, and
you'd have to poll anyway. So assuming auto-sync and functional
WebSocket messages, there's not much improvement to be had here over
just polling for the item until it 200s.

- Dan

Dan Stillman

unread,
May 12, 2026, 1:09:02 AM (yesterday) May 12
to zoter...@googlegroups.com
Also note that local writes to the local API are planned. It seems like
that would be the real solution here, rather than some convoluted
process where you’re writing to the online library and waiting for an
asynchronous, potentially UI-dependent sync operation to start and finish.

Bob Pasker

unread,
May 12, 2026, 10:00:06 AM (yesterday) May 12
to zotero-dev
local writes is the better solution. is this somethign we might see soonish?
Reply all
Reply to author
Forward
0 new messages