SyncShelf
Feeds reading/listening history from Audiobookshelf into Hardcover via a scheduled one-way sync, contributing to the unified reading log maintained in Hardcover.
Feeds reading history from Goodreads into Hardcover via a scheduled one-way sync, making Hardcover the single reading log. Provides data from Goodreads as input to the sync process.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@SyncShelfwhat did I finish reading last month?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
SyncShelf
SyncShelf is a self-hosted Python service for a two-person household. It is:
a remote MCP server that Claude connects to over OAuth, with tools that answer reading-history questions, edit the reading log, run and inspect the syncs, and request books from Chaptarr;
a set of scheduled one-way syncs that keep Hardcover as the single reading log, fed by Goodreads and Audiobookshelf;
a Chaptarr client that adds and searches one book in one format on request.
The build spec is docs/SPEC.md.
Status
Phase 1 (skeleton), released as v0.1.0. The package, CI and test harness exist.
uv run python -m syncshelf starts the service on 0.0.0.0:8000 (set by server.listen),
with an MCP endpoint that has no tools yet and a /healthz liveness check. Its data lives in
/data, or the existing directory named by SYNCSHELF_DATA_DIR. Phases are listed in SPEC §3.
Related MCP server: remote-mcp-oauth-github
Development
You need uv. It installs Python 3.14 for you.
uv sync # create .venv with the locked dependencies
uv run pre-commit install # gitleaks and the private denylist on every commitWhat | Command |
Lint and format |
|
Types |
|
Tests (offline, as CI runs them) |
|
Live tests (opt-in, never in CI) |
|
All pre-commit hooks |
|
Tests block outbound network access. Live tests read credentials from the git-ignored
repo-root .env; see .env.example.
To stop real values (your domain, emails, LAN hostnames) ever being committed, list them one per
line in the git-ignored local/denylist.txt. The pre-commit hook then refuses any commit that
contains one.
Contributing rules, for people and agents alike, are in AGENTS.md and SPEC §2.10.
Configuration and deployment
Configuration goes in profiles.yaml (git-ignored), modelled on
profiles.example.yaml. SyncShelf reads it from the path in
SYNCSHELF_CONFIG, default /config/profiles.yaml. Secrets never go in the file: each is a
${VAR} reference to the environment (see .env.example) or a *_file path. Startup stops on
bad config with a message naming the key. The full deployment guide is docs/runbook.md, which
arrives in phase 7. Until then, this section carries the deployment notes.
Each release tag publishes the image ghcr.io/<owner>/syncshelf:<version> (and :latest)
for amd64 and arm64, built from the Dockerfile. To run it:
/dataholds the database, itspre-migration-NNNN.dbsnapshots (taken before each upgrade, none on a fresh install) andgoodreads/.SYNCSHELF_DATA_DIRnames a different directory, which is useful outside a container. The container runs as10001:10001, so a bind-mounted host directory must exist and be owned by that user (chown 10001:10001 <dir>), or startup stops naming the unwritable path. A named volume gets the right owner from the image. Startup also stops if the database is newer than the image (an older release started on it)./config/profiles.yamlis the config. Mount it read-only (:ro); SyncShelf never writes it. Pass the secrets it references as environment variables or*_filepaths.Listening. The service listens on
server.listen, default0.0.0.0:8000, so Traefik or a published port (-p 8000:8000) reaches it. Keep port 8000 in the container: the image's health check probes127.0.0.1:8000. Phase 1 has no auth, so publish the port on loopback only (-p 127.0.0.1:8000:8000), as below.
docker run -d --name syncshelf \
-p 127.0.0.1:8000:8000 \
-v <data-dir>:/data \
-v <config-dir>/profiles.yaml:/config/profiles.yaml:ro \
ghcr.io/<owner>/syncshelf:<version>Licence
This server cannot be deployed
Maintenance
Related MCP Connectors
- platform7nOAuthtech.p7n
Connect Claude to your Platform7n workspaces — chat, links, and tasks. One-click OAuth.
Lets Claude, ChatGPT, and Muse read and update your beckett tasks, notes, calendar, and lists.
WHOOP recovery, strain, sleep and workouts in Claude via official WHOOP OAuth. Free, open source.
OAuth 2.1 short-link tools for AI agents with scoped tokens, approvals, audit logs, and revocation.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceConnects Claude to Microsoft Outlook through the Microsoft Graph API, enabling email management (list, search, read, send) and calendar operations (list, create, accept, decline, delete events) via OAuth 2.0 authentication.1MIT
- AlicenseNot gradedqualityDmaintenanceEnables Claude to authenticate with GitHub OAuth and access tools for user information, calculations, and GitHub repositories.5MIT
- AlicenseNot gradedqualityDmaintenanceEnables Claude to interact with Basecamp API for project and to-do management via OAuth authentication.55 npmMIT
- FlicenseAqualityCmaintenanceEnables Claude Code to manage Strety todos and people via read/write tools with OAuth token auto-refresh.81-