Introduces a stdio MCP server that lets Claude sync books from a Calibre
library (including the one managed by Calibre-Web-Automated) to a BookFusion
account. Reuses the same HTTP API, request shape and digest algorithms as the
official BookFusion Calibre plugin so existing accounts and metadata stay in
sync.
- bookfusion_api: async httpx client mirroring /uploads/init, /uploads/finalize,
/uploads/{id}, /uploads?isbn=..., /limits with HTTP Basic auth.
- calibre_library: read-only reader for metadata.db plus the file/metadata
digest helpers from the upstream plugin.
- sync: high-level flow (lookup by id/ISBN/digest -> upload or update).
- server: 8 MCP tools (library_status, list_books, get_book,
get_bookfusion_limits, check_book_in_bookfusion, sync_book_to_bookfusion,
sync_books_to_bookfusion, sync_all_books).
- config: env-var based settings (BOOKFUSION_API_KEY, CALIBRE_LIBRARY_PATH...).
- 14 pytest tests covering API client, settings loader and library reader.
|
||
|---|---|---|
| src/bookfusion_mcp | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| pyproject.toml | ||
| README.md | ||
BookFusion MCP
An MCP server that lets Claude (or any other MCP client) sync books from a Calibre library — including the one managed by Calibre-Web-Automated — to your BookFusion account.
It reuses the exact same HTTP API that the official BookFusion Calibre plugin talks to, so anything you already have configured on the BookFusion side (account, quota, integrations, API key) just works.
What it does
The server reads metadata directly from the Calibre metadata.db SQLite
database and the on-disk book / cover files. It never writes to the database.
It exposes the following MCP tools:
| Tool | Purpose |
|---|---|
library_status |
Show the configured library path, book count and BookFusion endpoint. |
list_books |
Paginated list of local books, optionally filtered by title/author. |
get_book |
Full details for one book (formats, identifiers, digests). |
get_bookfusion_limits |
Fetch upload limits (max filesize, etc.). |
check_book_in_bookfusion |
Look up a local book on BookFusion (by id, ISBN or digest). |
sync_book_to_bookfusion |
Upload or update a single book. |
sync_books_to_bookfusion |
Same, in parallel for a list of book ids. |
sync_all_books |
Sync every book matching a list_books filter. |
Configuration
Copy .env.example to .env and fill it in:
cp .env.example .env
| Env var | Required | Default | Notes |
|---|---|---|---|
BOOKFUSION_API_KEY |
yes | — | Get it from BookFusion → Settings → Integrations → Calibre. |
CALIBRE_LIBRARY_PATH |
yes | — | Host path to the directory containing metadata.db. For Calibre-Web-Automated this is the host folder you mapped to /calibre-library. |
BOOKFUSION_API_BASE |
no | https://www.bookfusion.com/calibre-api/v1 |
Override only if you self-host or test against a staging instance. |
BOOKFUSION_UPLOAD_THREADS |
no | 2 |
Parallel uploads when running sync_books_to_bookfusion / sync_all_books. |
BOOKFUSION_TIMEOUT |
no | 120 |
Request timeout in seconds. |
Never commit your API key.
.envis already in.gitignore.
Install
The server requires Python 3.10+.
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
Run the test suite to make sure everything is wired up:
pytest -q
Running the server
bookfusion-mcp
This starts a stdio MCP server. Connect any MCP client to it.
Claude Desktop / Claude Code
Add the server to your client config (Claude Desktop's
claude_desktop_config.json or Claude Code's ~/.claude.json):
{
"mcpServers": {
"bookfusion": {
"command": "bookfusion-mcp",
"env": {
"BOOKFUSION_API_KEY": "your-bookfusion-api-key",
"CALIBRE_LIBRARY_PATH": "/path/to/your/calibre-library"
}
}
}
}
If you installed inside a virtualenv, point command at the venv's
bookfusion-mcp binary, e.g.
/home/you/FGU-bookfusion/.venv/bin/bookfusion-mcp.
Calibre-Web-Automated specifics
The server only needs read access to:
- the
metadata.dbfile produced by Calibre / CWA, and - the book / cover files inside the same library directory.
If you run CWA in Docker and want the MCP server on the same host, point
CALIBRE_LIBRARY_PATH at whatever you mounted into the container at
/calibre-library. Example:
docker run -d \
-v /opt/cwa/library:/calibre-library \
... \
crocodilestick/calibre-web-automated
→ on the host, set CALIBRE_LIBRARY_PATH=/opt/cwa/library.
How the sync works
For each book the server:
- Picks the first format the BookFusion plugin supports (EPUB, PDF, CBZ, CBR, CBT, MOBI).
- Computes the file digest the way the plugin does
(
sha256(filesize_bytes || 0x00 || file_contents)) and a metadata digest over the same fields the plugin hashes — so digests match what BookFusion already has. - Looks up the book on BookFusion using the most specific identifier
available, in this order: existing
bookfusionidentifier →isbn→ file digest. - If the upstream digest matches and
reupload=false, skips the book. - Otherwise either
PUT /uploads/{id}to update an existing book, or runs the three-stepinit → upload to presigned URL → finalizeflow for a new one.
Notes & limits
- Uploads are one-way (Calibre → BookFusion), exactly like the official plugin.
metadata.dbis opened read-only viafile:...?mode=roso Calibre / CWA can keep the file open at the same time.- The
bookshelvesfield is wired through the API but not yet populated from Calibre custom columns; PRs welcome.
License
GPL-3.0-or-later, matching the upstream BookFusion Calibre plugin.