calibre-mcp
Enables conversational management of a Calibre ebook library via MCP, including search, metadata editing, adding, converting, deduplicating, removing, and emailing books with human-in-the-loop safety.
README
calibre-mcp
A local MCP server (stdio) that lets an LLM host — Claude Desktop, Claude Code, or any MCP-compatible client — manage a Calibre ebook library conversationally: search, edit metadata, add, convert, deduplicate, remove, and email books, all with human-in-the-loop safety.
I built this to stop clicking around the Calibre GUI and manage my library from a chat instead. It's a personal project, and also a deliberate showcase of how I build backend/tooling systems: hybrid I/O design, an explicit failure taxonomy, human-approval gates on every destructive action, and a test suite that never touches real user data. See ARCHITECTURE.md for the full design writeup.
Why the hybrid design
- Reads (
search,list,view, duplicate-finding) querymetadata.dbdirectly, read-only — fast, and structurally incapable of corrupting the library (the SQLite connection is openedmode=ro). - Writes (
edit,add,remove,convert,email) go through Calibre's own CLI tools (calibredb,ebook-convert,calibre-smtp) — never raw SQL — so Calibre stays authoritative over its own database. - Every write is preceded by an automatic
metadata.dbbackup (rolling, keeps the last 20). - Removal is recoverable: files are copied to a managed trash folder and the book is sent to Calibre's recycle bin — never a permanent delete.
- Every mutating or outward-facing tool is two-step (plan → confirm): the first call returns a
human-readable review plus a
confirmation_token; nothing changes — and nothing is sent — until you re-call with that exact token.
Full rationale, module boundaries, and the decision log behind these choices live in ARCHITECTURE.md.
Requirements
- Calibre installed, with
calibredbandebook-converton yourPATH(calibredb --version).calibre-smtpis also required if you wantemail_book. - Python ≥ 3.12 and
uv.
Install
git clone <this-repo> calibre-mcp
cd calibre-mcp
uv sync
Configure
The server manages one library, set via environment variable:
| Variable | Required | Default | Purpose |
|---|---|---|---|
CALIBRE_LIBRARY_PATH |
yes | — | Path to your Calibre library directory (the folder containing metadata.db). |
CALIBRE_MCP_BACKUP_DIR |
no | <library>/.calibre-mcp-backups/ |
Where pre-write backups and trashed files are stored. |
The server fails fast at startup with a clear error if CALIBRE_LIBRARY_PATH is unset or the
directory has no metadata.db.
email_book additionally needs SMTP relay credentials (loaded lazily — the server boots fine
without them, and only email_book fails if they're missing):
| Variable | Required | Default | Purpose |
|---|---|---|---|
CALIBRE_MCP_SMTP_RELAY |
for email | — | SMTP relay host. |
CALIBRE_MCP_SMTP_USERNAME |
for email | — | SMTP username. |
CALIBRE_MCP_SMTP_PASSWORD |
for email | — | SMTP password. Never logged, never returned in any tool output. |
CALIBRE_MCP_SMTP_FROM |
for email | — | Sender address. |
CALIBRE_MCP_SMTP_PORT |
no | 465 (SSL) / 25 (TLS/none) |
SMTP port. |
CALIBRE_MCP_SMTP_ENCRYPTION |
no | TLS |
One of SSL, TLS, NONE. |
Claude Desktop / Claude Code
Add to your MCP config (e.g. claude_desktop_config.json):
{
"mcpServers": {
"calibre": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/calibre-mcp", "run", "calibre-mcp"],
"env": {
"CALIBRE_LIBRARY_PATH": "/absolute/path/to/your/Calibre Library"
}
}
}
}
Run manually
CALIBRE_LIBRARY_PATH="/path/to/Calibre Library" uv run calibre-mcp
# or equivalently:
CALIBRE_LIBRARY_PATH="/path/to/Calibre Library" uv run python -m calibre_mcp
The server communicates over stdio (JSON-RPC); it prints nothing to stdout except MCP framing — all logs go to stderr, on purpose (see ARCHITECTURE.md).
Tools
| Tool | What it does | Gate |
|---|---|---|
search_books |
Resolve a Calibre search query (author:asimov, tag:scifi, …) to full book metadata. |
read-only |
list_books |
Paginated, sortable listing — works even when the Calibre GUI holds a write lock. | read-only |
get_book |
Full metadata for one book id. | read-only |
find_duplicates |
Advisory report of likely-duplicate books by normalized (title, author). Never merges. | read-only |
update_metadata |
Edit a whitelisted field set (title, authors, tags, series, rating, comments, …). | plan → confirm |
add_book |
Add a book from a local file path; surfaces duplicates honestly. | single-step (backed up) |
convert_book |
Convert to a new format (epub, azw3, mobi, pdf) — additive, keeps the original(s). |
single-step (backed up) |
remove_book |
Recoverable removal: trash copy + Calibre recycle bin, never a hard delete. | plan → confirm |
email_book |
Email a book's file via calibre-smtp, picking the best format automatically. |
plan → confirm |
Every tool's full contract (edge cases, error conditions, exact field whitelist) is documented in
its docstring in server.py — those docstrings are what the LLM host
sees, so they double as the API reference.
Development
uv run ruff check src tests # lint
uv run pytest # full suite (unit + integration + e2e)
uv run pytest -m unit # fast unit tests only
137 tests across three tiers (unit, integration, e2e); write tests never touch a real
library — see ARCHITECTURE.md.
Project layout
src/calibre_mcp/
├── server.py # FastMCP tool surface — the only stdio/MCP-aware module
├── library.py # CalibreLibrary facade — orchestrates every tool's business logic
├── sqlite_reader.py # Read-only metadata.db access (the only sqlite3 call site)
├── calibredb_runner.py # calibredb subprocess wrapper (search/edit/add/remove/add_format)
├── ebook_convert_runner.py # ebook-convert subprocess wrapper
├── calibre_smtp_runner.py # calibre-smtp subprocess wrapper
├── backup.py # metadata.db snapshots + recoverable trash
├── confirmation.py # plan→confirm token derivation/verification
├── config.py # env-driven startup config, fail-fast validation
└── errors.py # the failure taxonomy every layer maps to
Roadmap
Shipped: full read/curate/distribute loop (search, list, view, edit, add, remove, convert,
dedupe, email). What's next — library self-knowledge, bulk operations, cover/metadata enrichment,
device sync — is tracked in .specs/ROADMAP.md, including the reasoning for
sequencing and what's explicitly out of scope.
Contributing
See CONTRIBUTING.md for the dev workflow, the invariants a PR must preserve, and how the spec-driven process behind this repo works.
License
MIT © Gustavo F Sousa.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.