Skip to content
Conduit

mcp server

python-umcp-calibre

A calibre plugin that adds an MCP server

rcarmo/python-umcp-calibrecommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

Before you start

  • uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "python-umcp-calibre": {
      "command": "uvx",
      "args": [
        "calibre-umcp"
      ]
    }
  }
}

same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12

Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs

README

synced Oct 25, 2026

python-umcp-calibre

Calibre keeps its database, caches and filesystem state in the GUI process. python-umcp-calibre runs an MCP server in that process, so clients use Calibre's APIs and job machinery without opening metadata.db from a sidecar.

Version 0.3.5 adds persistent, redacted native task history, including scheduled downloads and automatic email jobs. It provides the released plugin and an older read-only compatibility server. Mutations are tested against exactly Calibre 9.15.0; the plugin hides them on every other Calibre version.

Process boundaries

ComponentLocationInterfaceLibrary access
Calibre Interface Action pluginplugins/calibre_umcp_plugin/Streamable HTTPRuns in the Calibre GUI process and uses the live database object
Read-only compatibility serversrc/calibre_umcp/server.pystdio or Streamable HTTPUses Calibre CLI commands, or the older JSON-RPC bridge when configured
JSON-RPC bridge helperserve_bridge() in plugins/calibre_umcp_plugin/bridge.pyHTTP JSON-RPCKept for tests and older wiring; the plugin UI does not publish it

Inactive-library reads use Calibre's GuiLibraryBroker handles. They do not switch the visible GUI library. Explicit library switching goes through Calibre's GUI action and requires a generation guard plus SWITCH_LIBRARY:<alias> confirmation.

HTTP endpoints

ServerMethod and pathAuthenticationUse
Released pluginPOST /mcpBearer token when configuredStreamable HTTP MCP endpoint
Released pluginGET /healthNoneReturns plugin, schema and toolset versions
Compatibility serverPOST /mcpDepends on the compatibility server deploymentStreamable HTTP MCP endpoint when started with --http
JSON-RPC helperPOST /rpcBearer token when configuredOlder bridge protocol used by compatibility code and tests
JSON-RPC helperGET /healthNoneBasic helper-process liveness check

The released plugin endpoint is /mcp. CALIBRE_UMCP_BRIDGE_URL belongs to the compatibility client and expects the older /rpc endpoint.

Tool discovery

Start with capabilities_readonly(). Read list_libraries_readonly() before choosing a library, then search with a small result limit and fetch details for one selected book. Responses include schema_version and toolset_version; reconnect and refresh tools/list after either value changes.

Read-only tools

ToolInputsResult
capabilities_readonlyNoneVersions, limits, stable errors and a compact tool index
describe_tool_readonlytool_nameArguments and result notes for one exposed tool
bridge_status_readonlyNonePlugin version, active library alias and generation
list_libraries_readonlyNoneConfigured aliases, labels, availability and policy flags
search_books_readonlyquery, limit, library, cursorBounded metadata rows with an opaque continuation cursor
get_book_metadata_readonlybook_id, libraryMetadata for one library-scoped book ID
get_book_formats_readonlybook_id, libraryPath-free format sizes, modification times and availability
inspect_book_format_readonlybook_id, format, library, include_text_sample=falseBounded EPUB structure and content signals; no ebook text
assess_book_quality_readonlybook_id, library, optional formatsScore, reasons, warnings and structured inspection errors
compare_book_quality_readonlyleft, right, policyTwo assessments and a non-mutating retention proposal
find_duplicates_readonlylibrary, limit, target_limit, cursorOne bounded pair-comparison segment
find_cross_library_duplicates_readonlysource and target aliases, limits, optional query and cursorOne bounded cross-library comparison segment
content_server_status_readonlyNoneAuthenticated content-server URL when it can be stated unambiguously
list_scheduled_news_readonlyNoneEnabled or bridge-disabled recipe state, schedule, retained prior schedule, last download and customisation metadata
list_native_tasks_readonlylimit, offset, optional status, queryNative GUI tasks, pagination and persistence status
get_native_task_readonlytask_idOne retained native task's metadata and status
get_native_task_log_readonlytask_id, offset, limitRedacted log page with character-based continuation
list_bridge_jobs_readonlyNoneBridge audit and job records
get_bridge_job_status_readonlyjob_idOne bridge audit or job record

EPUB inspection accepts files up to 64 MiB and archives with at most 4,096 entries or 256 MiB of expanded data. It scans no more than 8 MiB of content and runs for at most five seconds. Assessment and comparison convert supported inspection failures into grade: unknown results with inspection_errors; a direct inspection call returns the corresponding stable error.

Duplicate searches are segmented. Pass next_cursor back unchanged with the same arguments until it becomes null.

Native task history retains up to 30 days, 2,000 records and 32 KiB of log text per task. Redacted records persist in Calibre's configuration directory. A completed task does not establish SMTP acceptance or Kindle delivery. See native task history for capture, privacy and validation details.

Mutation gate

capabilities_mutation() and all mutation tools appear only when every condition in this table holds:

ConditionRequired state
Calibre runtimeExactly 9.15.0
UI tokenSaved in the plugin configuration
Mutation settingEnable implemented mutation tools checked in the plugin UI
Environment overrideCALIBRE_UMCP_BRIDGE_TOKEN, when set, matches the saved UI token

An environment-only token can authenticate HTTP requests. It cannot enable mutations. A mismatched environment override hides the mutation surface.

Metadata, format, cover, recipe-schedule, import, deletion, merge, conversion, copy, move, export and e-mail mutations accept expected_active_library and expected_active_generation. The bridge checks both before changing Calibre. Library switching requires both guards.

Mutation tools

ToolMain inputsOperation
capabilities_mutationNoneMutation policy, stable errors and a compact tool index
update_book_metadata_mutationbook_id, changesUpdates validated standard or custom metadata with rollback
begin_import_attachment_mutationfilename, byte count, SHA-256, optional formatOpens a bounded staged upload
append_import_attachment_mutationupload_handle, base64 chunkAppends one bounded chunk
finalize_import_attachment_mutationupload_handleVerifies size and SHA-256, then returns a one-time staged handle
stage_import_attachment_mutationfilename, base64 content, optional formatOne-call staging for small attachments
add_book_format_mutationbook_id, configured path or staged handle, format, replaceAdds or replaces one format
delete_book_format_mutationbook_id, format, allow_last_formatRemoves one format; final-format deletion needs explicit permission
set_book_cover_mutationbook_id, configured path or remove=trueReplaces or removes a cover with rollback
add_book_mutationconfigured path or staged handle, format, duplicate policyQueues a native Calibre book import
download_scheduled_news_mutationrecipe urnQueues an existing recipe through FetchNewsAction and Calibre's scheduler
update_scheduled_news_schedule_mutationurn, days_of_week, hour, minuteChanges an existing weekly schedule through RecipeModel.schedule_recipe()
disable_scheduled_news_mutationrecipe urnDisables future recurrence through RecipeModel.un_schedule_recipe() while retaining resume metadata
delete_books_mutationIDs, dry-run flag, confirmationPreviews, then moves confirmed books to Calibre trash
merge_duplicates_mutationsurvivor ID, source IDs, confirmation, cover optionsAdds missing formats and merges metadata while retaining source records
convert_book_mutationbook ID, output format, options, result/export policyQueues a native Calibre conversion job
copy_books_to_library_mutationIDs, destination alias, duplicate policy, optional destination mapCopies books and verifies destination hashes
move_books_to_library_mutationcopy inputs plus dry-run and confirmationVerifies the copy before moving source books to Calibre trash
save_book_to_disk_mutationbook ID, configured destination, options, overwrite flagQueues Calibre's save-to-disk engine
email_book_mutationbook ID, configured recipient, existing formatSubmits the format through Calibre's configured mail path
cancel_bridge_job_mutationjob_idRequests cancellation at the next boundary supported by the native job
switch_library_mutationalias, active-library guards, exact confirmationSwitches the visible GUI library with repair disabled

Metadata changes support title, authors, series, series_index, tags, identifiers, publisher, language, languages, comments, rating, pubdate, timestamp and custom columns through custom or #column_name.

Conversion options are limited to base_font_size, font_size_mapping, line_height, the four margin fields, output_profile, input_encoding, remove_paragraph_spacing, insert_blank_line, chapter, chapter_mark, page_breaks_before and pretty_print.

Save-to-disk options are limited to template, formats, save_cover, write_opf, save_extra_files, update_metadata, asciiize, to_lowercase, replace_whitespace and single_dir.

Controls and limits

AreaBehaviour
Import pathsBook, format and cover files must be below a UI-configured import root
Attachment stagingOpt-in root; 1 KiB to 1 GiB files; 60-second to 24-hour expiry; 8 MiB decoded chunks; SHA-256 verification; one-time handles
Export pathsSave and conversion exports must stay below a UI-configured export root
Library aliasesMust match ^[a-z][a-z0-9_-]{0,63}$; paths are omitted from MCP results
Copy and moveDestinations use configured aliases marked as copy targets; a move trashes sources after verified copying
Duplicate policiesreject, skip, add, merge_missing or replace; merge policies require explicit destination IDs
Scheduled newsOnly registered builtin: or custom: URNs; one active job per URN; schedule days use Monday 0 through Sunday 6; disabling preserves the prior schedule and last-download marker in plugin preferences without changing the recipe, its customisation or library records
E-mailRecipient and format must already exist in Calibre's mail configuration; automatic conversion is unsupported
Content serverReturns a URL only for a running authenticated server with a concrete or explicitly advertised host
Short mutationsGUI-thread database calls cannot be interrupted after they start
Long operationsUse Calibre jobs; audit records report partial work and delayed cancellation
DeletionPermanent deletion is unsupported; book removal uses Calibre trash
AuditOptional redacted JSONL file plus 10 to 10,000 in-memory records; default 500

update_scheduled_news_schedule_mutation() reads the existing schedule, calls Calibre's live recipe model, checks the stored result and verifies that recipe identity, title, last-download marker and customisation fields did not change. It restores the previous schedule if the update or verification fails.

disable_scheduled_news_mutation() calls Calibre's live RecipeModel.un_schedule_recipe() on the GUI thread. It refuses a queued or running recipe, verifies that the recipe remains registered and unscheduled, and persists its prior schedule and last-download marker in the plugin preferences. Repeating the request for a known disabled recipe returns changed=false; an unknown recipe returns NEWS_RECIPE_UNKNOWN. No MCP operation re-enables a recipe in this release.

content_server_status_readonly() withholds the URL when the server is stopped, authentication is disabled or a wildcard bind has no advertised host. Its reason_code states the failed condition.

Arbitrary recipients, automatic e-mail conversion, public temporary links and device actions are unsupported. The singular copy_book and move_book methods return explicit failures.

Build and test

The test suite uses Python's unittest runner:

make test

Ordinary development tests do not profile. Before a release, run make prerelease-test; it prints CPU cumulative and allocation hotspot summaries, then deletes the raw captures immediately. Build the plugin ZIP with:

make build

The output is <resolved PROJECT_TMP_ROOT>/build/calibre-umcp-plugin.zip; run make paths to print the resolved root. The build packages umcp.py and umcp_shared.py from src/calibre_umcp without copying generated files into source.

Install the plugin

Install from a checkout:

calibre-customize -a "$PROJECT_TMP_ROOT/build/calibre-umcp-plugin.zip"

linuxserver/calibre runs its profile as abc, so container installs normally use:

s6-setuidgid abc calibre-customize -a "$PROJECT_TMP_ROOT/build/calibre-umcp-plugin.zip"

Restart or reload Calibre after replacing the ZIP. The plugin starts MCP about one second after initialisation, once the active library is available. The µMCP Bridge menu has Status, Configure, Stop and Start commands if automatic startup fails.

Configure network access

Loopback is the default:

CALIBRE_UMCP_BRIDGE_HOST=127.0.0.1
CALIBRE_UMCP_PORT=9000

A container or LAN bind needs a token:

CALIBRE_UMCP_BRIDGE_HOST=0.0.0.0
CALIBRE_UMCP_PORT=9000
CALIBRE_UMCP_BRIDGE_TOKEN=<long-random-token>
VariableDefaultEffect
CALIBRE_UMCP_BRIDGE_HOST127.0.0.1MCP bind address; non-loopback binds require a token
CALIBRE_UMCP_PORT9000MCP HTTP port
CALIBRE_UMCP_BRIDGE_TOKENUnsetAuthenticates /mcp; must match the UI token to expose mutations
CALIBRE_UMCP_CONTENT_SERVER_ADVERTISED_HOSTUnsetConcrete host returned for an authenticated content server bound to a wildcard address
CALIBRE_UMCP_AUDIT_PATHUnsetRedacted JSONL audit file

Clients send Authorization: Bearer <token> to /mcp whenever a token is configured, including loopback connections. /health stays unauthenticated. Configure import roots, staging, export roots, library aliases, copy destinations, switching and mutation discovery in the plugin UI.

Compatibility server

The calibre-umcp command, equivalent to python -m calibre_umcp.server, runs the read-only compatibility server. It uses stdio without transport flags. --http --port N publishes Streamable HTTP at /mcp.

The supplied Dockerfile and docker-compose.yml build this compatibility server. They do not install the Interface Action plugin or expose its mutation tools.

Legacy mutator names such as convert_book, copy_book, move_book_destructive and email_book fail with directions to the corresponding plugin tool.

Design notes

DocumentSubject
ArchitectureProcess and trust boundaries
DesignImplementation choices
Multiple librariesAlias discovery, brokered reads, switching and duplicate checks
Calibre 9.15 API mapAudited read and mutation APIs
Plugin READMEZIP contents and container installation

The project is released under the MIT licence.

↑↓ navigate openesc close