Comprehensive reference for all MCP tools and endpoints
CalibreMCP uses FastMCP 2.13+ with portmanteau tools - consolidated tools that handle multiple related operations through an operation parameter. This reduces tool count while maintaining full functionality.
Portmanteau tool that consolidates all book querying operations: search, list, find, get books by various criteria.
IMPORTANT: Users may use different verbs (search, list, find, query, get) but they all map to the same operation.
ALL of these user requests should use operation="search":
- "search books by [author]" →
query_books(operation="search", author="...") - "list books by [author]" →
query_books(operation="search", author="...") - "find books by [author]" →
query_books(operation="search", author="...") - "query books by [author]" →
query_books(operation="search", author="...") - "get books by [author]" →
query_books(operation="search", author="...") - "show me books by [author]" →
query_books(operation="search", author="...")
Rule: If the user wants to access/retrieve/discover books with filters (author, tag, publisher, etc.), use operation="search" regardless of which verb they use.
async def query_books(
operation: str, # "search", "list", "by_author", "by_series"
# Search parameters (for operation="search")
author: Optional[str] = None,
authors: Optional[List[str]] = None,
exclude_authors: Optional[List[str]] = None,
text: Optional[str] = None,
query: Optional[str] = None, # Alias for text
tag: Optional[str] = None,
tags: Optional[List[str]] = None,
exclude_tags: Optional[List[str]] = None,
series: Optional[str] = None,
exclude_series: Optional[List[str]] = None,
publisher: Optional[str] = None,
publishers: Optional[List[str]] = None,
has_publisher: Optional[bool] = None,
rating: Optional[int] = None,
min_rating: Optional[int] = None,
max_rating: Optional[int] = None,
unrated: Optional[bool] = None,
pubdate_start: Optional[str] = None,
pubdate_end: Optional[str] = None,
added_after: Optional[str] = None,
added_before: Optional[str] = None,
min_size: Optional[int] = None,
max_size: Optional[int] = None,
formats: Optional[List[str]] = None,
comment: Optional[str] = None,
has_empty_comments: Optional[bool] = None,
format_table: bool = False,
limit: int = 50,
offset: int = 0,
# For operation="by_author"
author_id: Optional[int] = None,
# For operation="by_series"
series_id: Optional[int] = None,
# For operation="list"
sort: str = "title",
) -> Dict[str, Any]-
operation="search"⭐ PRIMARY OPERATION- Use for ALL user requests to access books with filters
- Works with ANY verb: "search", "list", "find", "query", "get", "show me"
- Supports comprehensive filtering (author, publisher, year, tags, rating, etc.)
- Example:
query_books(operation="search", author="Conan Doyle")
-
operation="list"- Only use when user explicitly wants ALL books without filters
- Simple pagination with minimal filtering
- Example:
query_books(operation="list", limit=20)
-
operation="by_author"- Get books by numeric author_id (requires
author_idparameter) - For author names, use
operation="search"withauthorparameter instead - Example:
query_books(operation="by_author", author_id=42)
- Get books by numeric author_id (requires
-
operation="by_series"- Get books in a series by numeric series_id (requires
series_idparameter) - For series names, use
operation="search"withseriesparameter instead - Example:
query_books(operation="by_series", series_id=15)
- Get books in a series by numeric series_id (requires
Author Filters:
author: Filter by author name (case-insensitive partial match)authors: Filter by multiple authors (OR logic)exclude_authors: Exclude books by these authors
Text & Tags:
text/query: Search in title, author, tags, series, commentstag: Filter by single tagtags: Filter by multiple tags (OR logic)exclude_tags: Exclude books with these tags
Series:
series: Filter by series nameexclude_series: Exclude books in these series
Rating:
rating: Exact rating (1-5)min_rating: Minimum rating (1-5)max_rating: Maximum rating (1-5)unrated: Filter for unrated books only
Publisher:
publisher: Filter by publisher namepublishers: Filter by multiple publishershas_publisher: Filter books with/without publisher
Date Filters:
pubdate_start: Publication date start (YYYY-MM-DD)pubdate_end: Publication date end (YYYY-MM-DD)added_after: Date added after (YYYY-MM-DD)added_before: Date added before (YYYY-MM-DD)
File Filters:
min_size: Minimum file size in bytesmax_size: Maximum file size in bytesformats: List of formats to include (e.g., ["EPUB", "PDF"])
Other:
comment: Search in book comments onlyhas_empty_comments: Filter books with empty/non-empty commentsformat_table: Format results as pretty text table (boolean)
Pagination:
limit: Maximum results to return (default: 50)offset: Results offset for pagination (default: 0)
# User says: "list books by conan doyle"
result = await query_books(operation="search", author="Conan Doyle", format_table=True)
# Advanced search: author + publisher + year
result = await query_books(
operation="search", author="Conan Doyle", publisher="Penguin", pubdate_start="1900-01-01", pubdate_end="1930-12-31"
)
# Search with multiple filters (AND logic)
result = await query_books(
operation="search", author="Agatha Christie", tags=["mystery", "crime"], min_rating=4, exclude_tags=["horror"]
)
# Search by publisher with year range
result = await query_books(
operation="search",
publishers=["O'Reilly Media", "No Starch Press"],
pubdate_start="2023-01-01",
pubdate_end="2024-12-31",
)
# Search recently added books with rating
result = await query_books(operation="search", added_after="2024-01-01", min_rating=4, format_table=True)
# List all books (simple operation)
result = await query_books(operation="list", limit=20)
# Get books by author ID
result = await query_books(operation="by_author", author_id=42, limit=10)
# Get books in a series
result = await query_books(operation="by_series", series_id=15)Dictionary containing operation-specific results:
- For
operation="search": Paginated search results with total count, books list, optional table - For
operation="list": Simple book list with pagination - For
operation="by_author": List of books by author ID - For
operation="by_series": List of books in series order
Portmanteau tool that consolidates book management operations: add, get, update, delete.
async def manage_books(
operation: str, # "add", "get", "update", "delete"
book_id: Optional[str] = None,
file_path: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None,
# ... additional parameters based on operation
) -> Dict[str, Any]operation="add": Add a new book to the library (requiresfile_path)operation="get": Retrieve detailed book information (requiresbook_id)operation="update": Update book metadata and properties (requiresbook_id)operation="delete": Delete a book from the library (requiresbook_id)
# Add a book
result = await manage_books(
operation="add", file_path="/path/to/book.epub", metadata={"title": "My Book", "authors": ["Author Name"]}
)
# Get book details
result = await manage_books(operation="get", book_id="123", include_metadata=True, include_formats=True)
# Update book metadata
result = await manage_books(operation="update", book_id="123", metadata={"rating": 5, "tags": ["favorite"]})
# Delete a book
result = await manage_books(operation="delete", book_id="123", delete_files=True)Portmanteau tool for managing multiple Calibre libraries.
operation="list": List all available librariesoperation="switch": Switch to a different library (requireslibrary_name)operation="stats": Get statistics for a libraryoperation="search": Search across multiple libraries
# List all libraries
result = await manage_libraries(operation="list")
# Switch library
result = await manage_libraries(operation="switch", library_name="Main Library")
# Get library statistics
result = await manage_libraries(operation="stats", library_name="Main Library")
# Search across libraries
result = await manage_libraries(
operation="search", query="python programming", libraries=["Main Library", "IT Library"]
)Get complete metadata and file information for a specific book (standalone tool, not portmanteau).
async def get_book_details(book_id: int) -> BookDetailResponsebook_id(int): Calibre book ID to fetch details for
BookDetailResponse with complete book information:
- Basic metadata: title, authors, series, rating, tags
- Publication info: published date, languages, comments
- File information: available formats, download links
- System data: identifiers, last modified, cover URL
Test connection to Calibre server and get diagnostics.
async def test_calibre_connection() -> ConnectionTestResponseConnectionTestResponse with:
connected: Boolean connection statusserver_version: Calibre server versionlibrary_name: Primary library nametotal_books: Number of books in libraryresponse_time_ms: Connection response timeerror_message: Error details if connection failedserver_capabilities: List of supported features
Portmanteau tool for book viewer and file opening operations.
operation="open": Open a book in the viewer (requiresbook_id,file_path)operation="get_page": Get a specific page from a book (requiresbook_id,file_path,page_number)operation="get_metadata": Get comprehensive metadata for a book (requiresbook_id,file_path)operation="get_state": Get current viewer state (requiresbook_id,file_path)operation="update_state": Update viewer state (requiresbook_id,file_path)operation="close": Close a viewer session (requiresbook_id)operation="open_file": Open book file with system's default application (requiresbook_id,file_path)operation="open_random"⭐ NEW: Search for books matching criteria, randomly select one, and open it
Searches for books matching author/tag/series filters, randomly selects one, and opens it with the system's default application.
Parameters:
author(optional): Author name filter (e.g., "John Dickson Carr")tag(optional): Tag name filter (e.g., "mystery")series(optional): Series name filter (e.g., "Sherlock Holmes")format_preference(default: "EPUB"): Preferred file format
Note: At least one search filter (author, tag, or series) is required.
Returns:
{"success": bool, "book_id": int, "title": str, "author": str, "file_path": str, "format": str, "message": str}Usage Examples:
# Open a random book by author
result = await manage_viewer(operation="open_random", author="Dickson Carr")
# Open random mystery book
result = await manage_viewer(operation="open_random", tag="mystery")
# Open random book in series with PDF preference
result = await manage_viewer(operation="open_random", series="Sherlock Holmes", format_preference="PDF")Portmanteau tool for metadata management and display.
operation="update": Update metadata for single or multiple books (requiresupdates)operation="organize_tags": AI-powered tag organization and cleanup suggestionsoperation="fix_issues": Automatically fix common metadata problemsoperation="show"⭐ NEW: Display comprehensive book metadata in formatted popup/modal
Searches for a book by title or author, retrieves comprehensive metadata, and displays it in a formatted HTML popup (optional).
Parameters:
query(required): Search query (title or partial title) - e.g., "Gormenghast"author(optional): Author name filter - e.g., "Mervyn Peake"open_browser(default: True): Whether to open metadata in browser popup
Returns:
{
"success": bool,
"book_id": int,
"title": str,
"author": str,
"metadata": dict, # Complete metadata dictionary
"html_path": Optional[str], # Path to HTML file if open_browser=True
"formatted_text": str, # Formatted text representation
}Usage Examples:
# Show metadata for a book (opens HTML popup)
result = await manage_metadata(operation="show", query="Gormenghast")
# Show metadata by author
result = await manage_metadata(operation="show", author="Peake")
# Show metadata without browser popup
result = await manage_metadata(operation="show", query="Gormenghast", open_browser=False)
# Display formatted text
if result["success"]:
print(result["formatted_text"])manage_smart_collections: Create, update, delete, query smart collectionsmanage_users: User management and authentication operations- Export tools:
export_books_csv,export_books_json,export_books_html,export_books_pandoc
Individual book result from search operations.
class BookSearchResult(BaseModel):
book_id: int
title: str
authors: List[str]
series: Optional[str] = None
series_index: Optional[float] = None
rating: Optional[int] = None # 1-5 scale
tags: List[str] = []
languages: List[str] = ["en"]
formats: List[str] = [] # ["EPUB", "PDF", "MOBI", etc.]
last_modified: Optional[str] = None
cover_url: Optional[str] = NoneResponse from query_books search operations.
class LibrarySearchResponse(BaseModel):
results: List[BookSearchResult]
total_found: int
query_used: Optional[str] = None
search_time_ms: intComplete book information from get_book_details.
class BookDetailResponse(BaseModel):
book_id: int
title: str
authors: List[str]
series: Optional[str] = None
series_index: Optional[float] = None
rating: Optional[int] = None
tags: List[str] = []
comments: Optional[str] = None
published: Optional[str] = None
languages: List[str] = []
formats: List[str] = []
identifiers: Dict[str, str] = {} # ISBN, Goodreads, etc.
last_modified: Optional[str] = None
cover_url: Optional[str] = None
download_links: Dict[str, str] = {} # Format -> URL mappingServer connection test results.
class ConnectionTestResponse(BaseModel):
connected: bool
server_version: Optional[str] = None
library_name: Optional[str] = None
total_books: Optional[int] = None
response_time_ms: int
error_message: Optional[str] = None
server_capabilities: List[str] = []IMPORTANT: The default library is automatically loaded on server startup. Users don't need to manually load or switch libraries before querying books.
Priority order for auto-loading:
- Persisted library (from FastMCP 2.13 storage)
config.local_library_path(if set)- Active library from Calibre's config files
- First discovered library (fallback)
CalibreMCP communicates with Calibre's built-in REST API server.
http://localhost:8080/ajax/...
GET /ajax/interface-data/init- Server initialization and library infoGET /ajax/search- Library search with query parametersGET /ajax/books- Bulk book metadata retrievalGET /ajax/book/{id}- Individual book details
GET /get/cover/{id}- Book cover imageGET /get/{format}/{id}- Download book in specific formatGET /get/thumb/{id}- Thumbnail cover image
Supports HTTP Basic Authentication when enabled in Calibre server:
# Configuration
username: "your_username"
password: "your_password"CalibreMCP supports Calibre's native search syntax through the query_books tool.
# Use query_books with operation="search"
query_books(operation="search", author="Conan Doyle") # Author filter
query_books(operation="search", tag="science") # Tag filter
query_books(operation="search", series="Foundation") # Series filter
query_books(operation="search", publisher="O'Reilly") # Publisher filter
query_books(operation="search", min_rating=4) # Rating filterFilters in query_books use AND logic when combined:
author="X"ANDtag="Y"ANDmin_rating=4= All conditions must matchtags=["X", "Y"]= Books with tag X OR tag Y
# Date range filtering
query_books(operation="search", pubdate_start="2020-01-01", pubdate_end="2024-12-31")
# File size filtering
query_books(
operation="search",
min_size=1048576, # 1 MB
max_size=10485760, # 10 MB
)
# Format filtering
query_books(operation="search", formats=["EPUB", "PDF"])title- Alphabetical by titleauthors- Alphabetical by author surnamerating- Highest rated firstdate- Most recently added firstpubdate- Most recently published firstseries- Series order
- Use specific filters (author, tag) instead of broad text searches
- Limit results to 50 or fewer for responsive UI
- Use
format_table=Truefor human-readable output - Cache frequent queries on client side
- Default: 60 requests per minute
- Burst limit: 10 concurrent requests
- Timeout: 30 seconds per request
- Cover images: ~100KB each
- Book metadata: ~2KB each
- Search results: Cache for 5 minutes
- Total cache: Limited to 50MB
- 200 - Success
- 401 - Authentication failed
- 404 - Calibre server not found / Book not found
- 500 - Calibre server internal error
- timeout - Request timeout (>30s)
Connection failed- Network connectivity issueAuthentication failed- Invalid username/passwordServer not found- Wrong URL or server not runningRequest timeout- Server overloaded or slow responseJSON decode error- Malformed server response
All MCP tools return valid responses even on errors:
- Empty result lists for search failures
- Error dictionaries with
success: falseand actionable error messages - Detailed suggestions for fixing issues
The Calibre webapp backend exposes REST endpoints (reservoir port 10720). See webapp/README.md.
| Endpoint | Method | Description |
|---|---|---|
/api/llm/models |
GET | List models (Ollama/LM Studio/OpenAI). Query: provider, base_url |
/api/llm/chat |
POST | Chat completion. Body: messages, model, stream, provider, base_url |
Config (backend .env): LLM_PROVIDER, LLM_BASE_URL, LLM_API_KEY
/api/books/- List, add books/api/authors/,/api/series/,/api/tags/- List with pagination/api/libraries/list,/api/libraries/switch,/api/libraries/stats/api/search/- Search books/api/viewer/open-file- Open book in system default app/api/export/csv,/api/export/json- Export books
# Start MCP Inspector for interactive testing
python -m calibre_mcp.server
# Navigate to: http://127.0.0.1:6274from calibre_mcp.calibre_api import quick_library_test
import asyncio
# Quick connection test
result = asyncio.run(quick_library_test("http://localhost:8080"))
print(f"Connection successful: {result}")from calibre_mcp.config import CalibreConfig
config = CalibreConfig.load_config()
print(f"Server: {config.server_url}")
print(f"Auth configured: {config.has_auth}")Built with Austrian efficiency for comprehensive e-book library management. Uses FastMCP 2.13+ portmanteau tool pattern for optimal Claude Desktop integration.